diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	Tue Jul 16 16:49:41 2002
+++ b/CREDITS	Tue Jul 16 16:49:41 2002
@@ -199,12 +199,10 @@
 S: USA
 
 N: Greg Banks
-E: gnb@linuxfan.com
+E: gnb@alphalink.com.au
 D: IDT77105 ATM network driver
-S: NEC Australia
-S: 649-655 Springvale Rd
-S: Mulgrave, Victoria 3170
-S: Australia
+D: some SuperH port work
+D: some trivial futzing with kconfig
 
 N: James Banks
 E: james@sovereign.org
@@ -502,6 +500,14 @@
 S: Fremont, California 94539
 S: USA
 
+N: Florent Chabaud
+E: florent.chabaud@polytechnique.org
+D: software suspend
+S: SGDN/DCSSI/SDS/LTI
+S: 58, Bd Latour-Maubourg
+S: 75700 Paris 07 SP
+S: France
+
 N: Gordon Chaffee
 E: chaffee@cs.berkeley.edu
 W: http://bmrc.berkeley.edu/people/chaffee/
@@ -1708,7 +1714,7 @@
 N: Gabor Kuti
 M: seasons@falcon.sch.bme.hu
 M: seasons@makosteszta.sote.hu
-D: Software suspend
+D: Original author of software suspend
 
 N: Jaroslav Kysela
 E: perex@suse.cz
@@ -2582,11 +2588,11 @@
 S: Australia
 
 N: Aristeu Sergio Rozanski Filho
-E: aris@conectiva.com.br
+E: aris@cathedrallabs.org
 D: Support for EtherExpress 10 ISA (i82595) in eepro driver
-S: Conectiva S.A.
-S: R. Tocantins, 89 - Cristo Rei
-S: 80050-430 - Curitiba - Paraná
+D: User level driver support for input
+S: R. Jose Serrato, 130 - Santa Candida
+S: 82640-320 - Curitiba - Paraná
 S: Brazil
 
 N: Alessandro Rubini
diff -Nru a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
--- a/Documentation/DocBook/kernel-api.tmpl	Tue Jul 16 16:49:41 2002
+++ b/Documentation/DocBook/kernel-api.tmpl	Tue Jul 16 16:49:41 2002
@@ -46,9 +46,13 @@
 !Iinclude/asm-i386/unaligned.h
      </sect1>
 
+<!-- FIXME:
+  kernel/sched.c has no docs, which stuffs up the sgml.  Comment
+  out until somebody adds docs.  KAO
      <sect1><title>Delaying, scheduling, and timer routines</title>
 !Ekernel/sched.c
      </sect1>
+KAO -->
   </chapter>
 
   <chapter id="adt">
@@ -358,9 +362,13 @@
      <sect1><title>Frame Buffer Colormap</title>
 !Edrivers/video/fbcmap.c
      </sect1>
+<!-- FIXME:
+  drivers/video/fbgen.c has no docs, which stuffs up the sgml.  Comment
+  out until somebody adds docs.  KAO
      <sect1><title>Frame Buffer Generic Functions</title>
 !Idrivers/video/fbgen.c
      </sect1>
+KAO -->
      <sect1><title>Frame Buffer Video Mode Database</title>
 !Idrivers/video/modedb.c
 !Edrivers/video/modedb.c
diff -Nru a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
--- a/Documentation/SubmittingPatches	Tue Jul 16 16:49:41 2002
+++ b/Documentation/SubmittingPatches	Tue Jul 16 16:49:41 2002
@@ -161,7 +161,7 @@
 When sending patches to Linus, always follow step #6.
 
 Large changes are not appropriate for mailing lists, and some
-maintainers.  If your patch, uncompressed, exceeds 40Kb in size,
+maintainers.  If your patch, uncompressed, exceeds 40 kB in size,
 it is preferred that you store your patch on an Internet-accessible
 server, and provide instead a URL (link) pointing to your patch.
 
diff -Nru a/Documentation/devices.txt b/Documentation/devices.txt
--- a/Documentation/devices.txt	Tue Jul 16 16:49:42 2002
+++ b/Documentation/devices.txt	Tue Jul 16 16:49:42 2002
@@ -419,6 +419,7 @@
 		220 = /dev/mptctl	Message passing technology (MPT) control
 		221 = /dev/mvista/hssdsi	Montavista PICMG hot swap system driver
 		222 = /dev/mvista/hasi		Montavista PICMG high availability
+		223 = /dev/input/uinput		User level driver support for input
 		240-255			Reserved for local use
 
  11 char	Raw keyboard device
diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
--- a/Documentation/filesystems/ntfs.txt	Tue Jul 16 16:49:42 2002
+++ b/Documentation/filesystems/ntfs.txt	Tue Jul 16 16:49:42 2002
@@ -247,6 +247,33 @@
 
 Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
 
+2.0.21:
+	These only affect 32-bit architectures:
+	- Check for, and refuse to mount too large volumes (maximum is 2TiB).
+	- Check for, and refuse to open too large files and directories
+	  (maximum is 16TiB).
+2.0.20:
+	- Support non-resident directory index bitmaps. This means we now cope
+	  with huge directories without problems.
+	- Fix a page leak that manifested itself in some cases when reading
+	  directory contents.
+	- Internal cleanups.
+2.0.19:
+	- Fix race condition and improvements in block i/o interface.
+	- Optimization when reading compressed files.
+2.0.18:
+	- Fix race condition in reading of compressed files.
+2.0.17:
+	- Cleanups and optimizations.
+2.0.16:
+	- Fix stupid bug introduced in 2.0.15 in new attribute inode API.
+	- Big internal cleanup replacing the mftbmp access hacks by using the
+	  new attribute inode API instead.
+2.0.15:
+	- Bug fix in parsing of remount options.
+	- Internal changes implementing attribute (fake) inodes allowing all
+	  attribute i/o to go via the page cache and to use all the normal
+	  vfs/mm functionality.
 2.0.14:
 	- Internal changes improving run list merging code and minor locking
 	  change to not rely on BKL in ntfs_statfs().
diff -Nru a/Documentation/input/amijoy.txt b/Documentation/input/amijoy.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/input/amijoy.txt	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,184 @@
+Amiga 4-joystick parport extension
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Parallel port pins:
+
+ (2) - Up1	 (6) - Up2
+ (3) - Down1	 (7) - Down2
+ (4) - Left1	 (8) - Left2
+ (5) - Right1	 (9) - Right2
+(13) - Fire1	(11) - Fire2
+(18) - Gnd1	(18) - Gnd2
+
+Amiga digital joystick pinout
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+(1) - Up
+(2) - Down
+(3) - Left
+(4) - Right
+(5) - n/c
+(6) - Fire button
+(7) - +5V (50mA)
+(8) - Gnd
+(9) - Thumb button
+
+Amiga mouse pinout
+~~~~~~~~~~~~~~~~~~
+(1) - V-pulse
+(2) - H-pulse
+(3) - VQ-pulse
+(4) - HQ-pulse
+(5) - Middle button
+(6) - Left button
+(7) - +5V (50mA)
+(8) - Gnd
+(9) - Right button
+
+Amiga analog joystick pinout
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+(1) - Top button
+(2) - Top2 button
+(3) - Trigger button
+(4) - Thumb button
+(5) - Analog X
+(6) - n/c
+(7) - +5V (50mA)
+(8) - Gnd
+(9) - Analog Y
+
+Amiga lightpen pinout
+~~~~~~~~~~~~~~~~~~~~~
+(1) - n/c
+(2) - n/c
+(3) - n/c
+(4) - n/c
+(5) - Touch button
+(6) - /Beamtrigger
+(7) - +5V (50mA)
+(8) - Gnd
+(9) - Stylus button
+
+-------------------------------------------------------------------------------
+
+NAME     rev ADDR type chip   Description
+JOY0DAT      00A   R   Denise Joystick-mouse 0 data (left vert, horiz)
+JOY1DAT      00C   R   Denise Joystick-mouse 1 data (right vert,horiz)
+
+        These addresses each read a 16 bit register. These in turn
+        are loaded from the MDAT serial stream and are clocked in on
+        the rising edge of SCLK. MLD output is used to parallel load
+        the external parallel-to-serial converter.This in turn is
+        loaded with the 4 quadrature inputs from each of two game
+        controller ports (8 total) plus 8 miscellaneous control bits
+        which are new for LISA and can be read in upper 8 bits of
+        LISAID.
+        Register bits are as follows:
+        Mouse counter usage (pins  1,3 =Yclock, pins 2,4 =Xclock)
+
+    BIT#  15  14  13  12  11  10  09  08     07  06  05  04  03  02  01  00
+JOY0DAT   Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0     X7  X6  X5  X4  X3  X2  X1  X0
+JOY1DAT   Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0     X7  X6  X5  X4  X3  X2  X1  X0
+
+        0=LEFT CONTROLLER PAIR, 1=RIGHT CONTROLLER PAIR.
+        (4 counters total).The bit usage for both left and right
+        addresses is shown below. Each 6 bit counter (Y7-Y2,X7-X2) is
+        clocked by 2 of the signals input from the mouse serial
+        stream. Starting with first bit recived:
+
+         +-------------------+-----------------------------------------+
+         | Serial | Bit Name | Description                             |
+         +--------+----------+-----------------------------------------+
+         |   0    | M0H      | JOY0DAT Horizontal Clock                |
+         |   1    | M0HQ     | JOY0DAT Horizontal Clock (quadrature)   |
+         |   2    | M0V      | JOY0DAT Vertical Clock                  |
+         |   3    | M0VQ     | JOY0DAT Vertical Clock  (quadrature)    |
+         |   4    | M1V      | JOY1DAT Horizontall Clock               |
+         |   5    | M1VQ     | JOY1DAT Horizontall Clock (quadrature)  |
+         |   6    | M1V      | JOY1DAT Vertical Clock                  |
+         |   7    | M1VQ     | JOY1DAT Vertical Clock (quadrature)     |
+         +--------+----------+-----------------------------------------+
+
+         Bits 1 and 0 of each counter (Y1-Y0,X1-X0) may be
+         read to determine the state of the related input signal pair.
+         This allows these pins to double as joystick switch inputs.
+         Joystick switch closures can be deciphered as follows:
+
+         +------------+------+---------------------------------+
+         | Directions | Pin# | Counter bits                    |
+         +------------+------+---------------------------------+
+         | Forward    |  1   | Y1 xor Y0 (BIT#09 xor BIT#08)   |
+         | Left       |  3   | Y1                              |
+         | Back       |  2   | X1 xor X0 (BIT#01 xor BIT#00)   |
+         | Right      |  4   | X1                              |
+         +------------+------+---------------------------------+
+
+-------------------------------------------------------------------------------
+
+NAME      rev ADDR type chip    Description
+JOYTEST       036   W   Denise  Write to all 4  joystick-mouse counters at once.
+
+                  Mouse counter write test data:
+     BIT#  15  14  13  12  11  10  09  08     07  06  05  04  03  02  01  00
+  JOYxDAT  Y7  Y6  Y5  Y4  Y3  Y2  xx  xx     X7  X6  X5  X4  X3  X2  xx  xx
+  JOYxDAT  Y7  Y6  Y5  Y4  Y3  Y2  xx  xx     X7  X6  X5  X4  X3  X2  xx  xx
+
+-------------------------------------------------------------------------------
+
+NAME    rev ADDR type chip   Description
+POT0DAT  h  012   R   Paula  Pot counter data left pair (vert, horiz)
+POT1DAT  h  014   R   Paula  Pot counter data right pair (vert,horiz)
+
+        These addresses each read a pair of 8 bit pot counters.
+        (4 counters total). The bit assignment for both
+        addresses is shown below. The counters are stopped by signals
+        from 2 controller connectors (left-right) with 2 pins each.
+
+  BIT#  15  14  13  12  11  10  09  08     07  06  05  04  03  02  01  00
+ RIGHT  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0     X7  X6  X5  X4  X3  X2  X1  X0
+  LEFT  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0     X7  X6  X5  X4  X3  X2  X1  X0
+
+         +--------------------------+-------+
+         | CONNECTORS               | PAULA |
+         +-------+------+-----+-----+-------+
+         | Loc.  | Dir. | Sym | pin | pin   |
+         +-------+------+-----+-----+-------+
+         | RIGHT | Y    | RX  | 9   | 33    |
+         | RIGHT | X    | RX  | 5   | 32    |
+         | LEFT  | Y    | LY  | 9   | 36    |
+         | LEFT  | X    | LX  | 5   | 35    |
+         +-------+------+-----+-----+-------+
+
+         With normal (NTSC or PAL) horiz. line rate, the pots will
+         give a full scale (FF) reading with about 500kohms in one
+         frame time. With proportionally faster horiz line times,
+         the counters will count proportionally faster.
+         This should be noted when doing variable beam displays.
+
+-------------------------------------------------------------------------------
+
+NAME   rev ADDR type chip   Description
+POTGO      034   W   Paula  Pot port (4 bit) bi-direction and data, and pot counter start.
+
+-------------------------------------------------------------------------------
+
+NAME   rev ADDR type chip   Description
+POTINP     016   R   Paula  Pot pin data read
+
+        This register controls a 4 bit bi-direction I/O port
+        that shares the same 4 pins as the 4 pot counters above.
+
+         +-------+----------+---------------------------------------------+
+         | BIT#  | FUNCTION | DESCRIPTION                                 |
+         +-------+----------+---------------------------------------------+
+         | 15    | OUTRY    | Output enable for Paula pin 33              |
+         | 14    | DATRY    | I/O data Paula pin 33                       |
+         | 13    | OUTRX    | Output enable for Paula pin 32              |
+         | 12    | DATRX    | I/O data Paula pin 32                       |
+         | 11    | OUTLY    | Out put enable for Paula pin 36             |
+         | 10    | DATLY    | I/O data Paula pin 36                       |
+         | 09    | OUTLX    | Output enable for Paula pin 35              |
+         | 08    | DATLX    | I/O data  Paula pin 35                      |
+         | 07-01 |   X      | Not used                                    |
+         | 00    | START    | Start pots (dump capacitors,start counters) |
+         +-------+----------+---------------------------------------------+
+
+-------------------------------------------------------------------------------
diff -Nru a/Documentation/input/atarikbd.txt b/Documentation/input/atarikbd.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/input/atarikbd.txt	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,709 @@
+Intelligent Keyboard (ikbd) Protocol
+
+
+1. Introduction
+
+The Atari Corp. Intelligent Keyboard (ikbd) is a general purpose keyboard
+controller that is flexible enough that it can be used in a variety of
+products without modification. The keyboard, with its microcontroller,
+provides a convenient connection point for a mouse and switch-type joysticks.
+The ikbd processor also maintains a time-of-day clock with one second
+resolution.
+The ikbd has been designed to be general enough that it can be used with a
+ariety of new computer products. Product variations in a number of
+keyswitches, mouse resolution, etc. can be accommodated.
+The ikbd communicates with the main processor over a high speed bi-directional
+serial interface. It can function in a variety of modes to facilitate
+different applications of the keyboard,  joysticks, or mouse. Limited use of
+the controller is possible in applications in which only a unidirectional
+communications medium is available by carefully designing the default modes.
+
+3. Keyboard
+
+The keyboard always returns key make/break scan codes. The ikbd generates
+keyboard scan codes for each key press and release. The key scan make (key
+closure) codes start at 1, and are defined in Appendix A. For example, the
+ISO key position in the scan code table should exist even if no keyswitch
+exists in that position on a particular keyboard. The break code for each key
+is obtained by ORing 0x80 with the make code.
+
+The special codes 0xF6 through 0xFF are reserved for use as follows:
+    0xF6            status report
+    0xF7            absolute mouse position record
+    0xF8-0xFB       relative mouse position records(lsbs determind by
+                     mouse button states)
+    0xFC            time-of-day
+    0xFD            joystick report (both sticks)
+    0xFE            joystick 0 event
+    0xFF            joystick 1 event
+
+The two shift keys return different scan codes in this mode. The ENTER key
+and the RETurn key are also distinct.
+
+4. Mouse
+
+The mouse port should be capable of supporting a mouse with resolution of
+approximately 200 counts (phase changes or 'clicks') per inch of travel. The
+mouse should be scanned at a rate that will permit accurate tracking at
+velocities up to 10 inches per second.
+The ikbd can report mouse motion in three distinctly different ways. It can
+report relative motion, absolute motion in a coordinate system maintained
+within the ikbd, or by converting mouse motion into keyboard cursor control
+key equivalents.
+The mouse buttons can be treated as part of the mouse or as additional
+keyboard keys.
+
+4.1 Relative Position Reporting
+
+In relative position mode, the ikbd will return relative mouse position
+records whenever a mouse event occurs. A mouse event consists of a mouse
+button being pressed or released, or motion in either axis exceeding a
+settable threshold of motion. Regardless of the threshold, all bits of
+resolution are returned to the host computer.
+Note that the ikbd may return mouse relative position reports with
+significantly more than the threshold delta x or y. This may happen since no
+relative mouse motion events will be generated: (a) while the keyboard has
+been 'paused' ( the event will be stored until keyboard communications is
+resumed) (b) while any event is being transmitted.
+
+The relative mouse position record is a three byte record of the form
+(regardless of keyboard mode):
+    %111110xy           ; mouse position record flag
+                        ; where y is the right button state
+                        ; and x is the left button state
+    X                   ; delta x as twos complement integer
+    Y                   ; delta y as twos complement integer
+
+Note that the value of the button state bits should be valid even if the
+MOUSE BUTTON ACTION has set the buttons to act like part of the keyboard.
+If the accumulated motion before the report packet is generated exceeds the
++127...-128 range, the motion is broken into multiple packets.
+Note that the sign of the delta y reported is a function of the Y origin
+selected.
+
+4.2 Absolute Position reporting
+
+The ikbd can also maintain absolute mouse position. Commands exist for
+reseting the mouse position, setting X/Y scaling, and interrogating the
+current mouse position.
+
+4.3 Mouse Cursor Key Mode
+
+The ikbd can translate mouse motion into the equivalent cursor keystrokes.
+The number of mouse clicks per keystroke is independently programmable in
+each axis. The ikbd internally maintains mouse motion information to the
+highest resolution available, and merely generates a pair of cursor key events
+for each multiple of the scale factor.
+Mouse motion produces the cursor key make code immediately followed by the
+break code for the appropriate cursor key. The mouse buttons produce scan
+codes above those normally assigned for the largest envisioned keyboard (i.e.
+LEFT=0x74 & RIGHT=0x75).
+
+5. Joystick
+
+5.1 Joystick Event Reporting
+
+In this mode, the ikbd generates a record whever the joystick position is
+changed (i.e. for each opening or closing of a joystick switch or trigger).
+
+The joystick event record is two bytes of the form:
+    %1111111x           ; Joystick event marker
+                        ; where x is Joystick 0 or 1
+    %x000yyyy           ; where yyyy is the stick position
+                        ; and x is the trigger
+
+5.2 Joystick Interrogation
+
+The current state of the joystick ports may be interrogated at any time in
+this mode by sending an 'Interrogate Joystick' command to the ikbd.
+
+The ikbd response to joystick interrogation is a three byte report of the form
+    0xFD                ; joystick report header
+    %x000yyyy           ; Joystick 0
+    %x000yyyy           ; Joystick 1
+                        ; where x is the trigger
+                        ; and yyy is the stick position
+
+5.3 Joystick Monitoring
+
+A mode is available that devotes nearly all of the keyboard communications
+time to reporting the state of the joystick ports at a user specifiable rate.
+It remains in this mode until reset or commanded into another mode. The PAUSE
+command in this mode not only stop the output but also temporarily stops
+scanning the joysticks (samples are not queued).
+
+5.4 Fire Button Monitoring
+
+A mode is provided to permit monitoring a single input bit at a high rate. In
+this mode the ikbd monitors the state of the Joystick 1 fire button at the
+maximum rate permitted by the serial communication channel. The data is packed
+8 bits per byte for transmission to the host. The ikbd remains in this mode
+until reset or commanded into another mode. The PAUSE command in this mode not
+only stops the output but also temporarily stops scanning the button (samples
+are not queued).
+
+5.5 Joystick Key Code Mode
+
+The ikbd may be commanded to translate the use of either joystick into the
+equivalent cursor control keystroke(s). The ikbd provides a single breakpoint
+velocity joystick cursor.
+Joystick events produce the make code, immediately followed by the break code
+for the appropriate cursor motion keys. The trigger or fire buttons of the
+joysticks produce pseudo key scan codes above those used by the largest key
+matrix envisioned (i.e. JOYSTICK0=0x74, JOYSTICK1=0x75).
+
+6. Time-of-Day Clock
+
+The ikbd also maintains a time-of-day clock for the system. Commands are
+available to set and interrogate the timer-of-day clock. Time-keeping is
+maintained down to a resolution of one second.
+
+7. Status Inquiries
+
+The current state of ikbd modes and parameters may be found by sending status
+inquiry commands that correspond to the ikbd set commands.
+
+8. Power-Up Mode
+
+The keyboard controller will perform a simple self-test on power-up to detect
+major controller faults (ROM checksum and RAM test) and such things as stuck
+keys. Any keys down at power-up are presumed to be stuck, and their BREAK
+(sic) code is returned (which without the preceding MAKE code is a flag for a
+keyboard error). If the controller self-test completes without error, the code
+0xF0 is returned. (This code will be used to indicate the version/rlease of
+the ikbd controller. The first release of the ikbd is version 0xF0, should
+there be a second release it will be 0xF1, and so on.)
+The ikbd defaults to a mouse position reporting with threshold of 1 unit in
+either axis and the Y=0 origin at the top of the screen, and joystick event
+reporting mode for joystick 1, with both buttons being logically assigned to
+the mouse. After any joystick command, the ikbd assumes that joysticks are
+connected to both Joystick0 and Joystick1. Any mouse command (except MOUSE
+DISABLE) then causes port 0 to again be scanned as if it were a mouse, and
+both buttons are logically connected to it. If a mouse diable command is
+received while port 0 is presumed to be a mouse, the button is logically
+assigned to Joystick1 ( until the mouse is reenabled by another mouse command).
+
+9. ikbd Command Set
+
+This section contains a list of commands that can be sent to the ikbd. Command
+codes (such as 0x00) which are not specified should perform no operation
+(NOPs).
+
+9.1 RESET
+
+    0x80
+    0x01
+
+N.B. The RESET command is the only two byte command understood by the ikbd.
+Any byte following an 0x80 command byte other than 0x01 is ignored (and causes
+the 0x80 to be ignored).
+A reset may also be caused by sending a break lasting at least 200mS to the
+ikbd.
+Executing the RESET command returns the keyboard to its default (power-up)
+mode and parameter settings. It does not affect the time-of-day clock.
+The RESET command or function causes the ikbd to perform a simple self-test.
+If the test is successful, the ikbd will send the code of 0xF0 within 300mS
+of receipt of the RESET command (or the end of the break, or power-up). The
+ikbd will then scan the key matrix for any stuck (closed) keys. Any keys found
+closed will cause the break scan code to be generated (the break code arriving
+without being preceded by the make code is a flag for a key matrix error).
+
+9.2. SET MOUSE BUTTON ACTION
+
+    0x07
+    %00000mss           ; mouse button action
+                        ;       (m is presumed = 1 when in MOUSE KEYCODE mode)
+                        ; mss=0xy, mouse button press or release causes mouse
+                        ;  position report
+                        ;  where y=1, mouse key press causes absolute report
+                        ;  and x=1, mouse key release causes absolute report
+                        ; mss=100, mouse buttons act like keys 
+
+This command sets how the ikbd should treat the buttons on the mouse. The
+default mouse button action mode is %00000000, the buttons are treated as part
+of the mouse logically.
+When buttons act like keys, LEFT=0x74 & RIGHT=0x75.
+
+9.3 SET RELATIVE MOUSE POSITION REPORTING
+
+    0x08
+
+Set relative mouse position reporting. (DEFAULT) Mouse position packets are
+generated asynchronously by the ikbd whenever motion exceeds the setable
+threshold in either axis (see SET MOUSE THRESHOLD). Depending upon the mouse
+key mode, mouse position reports may also be generated when either mouse
+button is pressed or released. Otherwise the mouse buttons behave as if they
+were keyboard keys.
+
+9.4 SET ABSOLUTE MOUSE POSITIONING
+
+    0x09
+    XMSB                ; X maximum (in scaled mouse clicks)
+    XLSB
+    YMSB                ; Y maximum (in scaled mouse clicks)
+    YLSB
+	
+Set absolute mouse position maintenance. Resets the ikbd maintained X and Y
+coordinates.
+In this mode, the value of the internally maintained coordinates does NOT wrap
+between 0 and large positive numbers. Excess motion below 0 is ignored. The
+command sets the maximum positive value that can be attained in the scaled
+coordinate system. Motion beyond that value is also ignored.
+
+9.5 SET MOUSE KEYCODE MOSE
+
+    0x0A
+    deltax              ; distance in X clicks to return (LEFT) or (RIGHT)
+    deltay              ; distance in Y clicks to return (UP) or (DOWN)
+
+Set mouse monitoring routines to return cursor motion keycodes instead of
+either RELATIVE or ABSOLUTE motion records. The ikbd returns the appropriate
+cursor keycode after mouse travel exceeding the user specified deltas in
+either axis. When the keyboard is in key scan code mode, mouse motion will
+cause the make code immediately followed by the break code. Note that this
+command is not affected by the mouse motion origin.
+
+9..6 SET MOUSE THRESHOLD
+
+    0x0B
+    X                   ; x threshold in mouse ticks (positive integers)
+    Y                   ; y threshold in mouse ticks (positive integers)
+
+This command sets the threshold before a mouse event is generated. Note that
+it does NOT affect the resolution of the data returned to the host. This
+command is valid only in RELATIVE MOUSE POSITIONING mode. The thresholds
+default to 1 at RESET (or power-up).
+
+9.7 SET MOUSE SCALE
+
+    0x0C
+    X                   ; horizontal mouse ticks per internel X
+    Y                   ; vertical mouse ticks per internel Y
+
+This command sets the scale factor for the ABSOLUTE MOUSE POSITIONING mode.
+In this mode, the specified number of mouse phase changes ('clicks') must
+occur before the internally maintained coordinate is changed by one
+(independently scaled for each axis). Remember that the mouse position
+information is available only by interrogating the ikbd in the ABSOLUTE MOUSE
+POSITIONING mode unless the ikbd has been commanded to report on button press
+or release (see SET MOSE BUTTON ACTION).
+
+9.8 INTERROGATE MOUSE POSITION
+
+    0x0D
+    Returns:
+            0xF7       ; absolute mouse position header
+    BUTTONS
+            0000dcba   ; where a is right button down since last interrogation
+                       ; b is right button up since last
+                       ; c is left button down since last
+                       ; d is left button up since last
+            XMSB       ; X coordinate
+            XLSB
+            YMSB       ; Y coordinate
+            YLSB
+
+The INTERROGATE MOUSE POSITION command is valid when in the ABSOLUTE MOUSE
+POSITIONING mode, regardless of the setting of the MOUSE BUTTON ACTION.
+
+9.9 LOAD MOUSE POSITION
+
+    0x0E
+    0x00                ; filler
+    XMSB                ; X coordinate
+    XLSB                ; (in scaled coordinate system)
+    YMSB                ; Y coordinate
+    YLSB
+
+This command allows the user to preset the internally maintained absolute
+mouse position.
+
+9.10 SET Y=0 AT BOTTOM
+
+    0x0F
+
+This command makes the origin of the Y axis to be at the bottom of the
+logical coordinate system internel to the ikbd for all relative or absolute
+mouse motion. This causes mouse motion toward the user to be negative in sign
+and away from the user to be positive.
+
+9.11 SET Y=0 AT TOP
+
+    0x10
+
+Makes the origin of the Y axis to be at the top of the logical coordinate
+system within the ikbd for all relative or absolute mouse motion. (DEFAULT)
+This causes mouse motion toward the user to be positive in sign and away from
+the user to be negative.
+
+9.12 RESUME
+
+    0x11
+
+Resume sending data to the host. Since any command received by the ikbd after
+its output has been paused also causes an implicit RESUME this command can be
+thought of as a NO OPERATION command. If this command is received by the ikbd
+and it is not PAUSED, it is simply ignored.
+
+9.13 DISABLE MOUSE
+
+    0x12
+
+All mouse event reporting is disabled (and scanning may be internally
+disabled). Any valid mouse mode command resumes mouse motion monitoring. (The
+valid mouse mode commands are SET RELATIVE MOUSE POSITION REPORTING, SET
+ABSOLUTE MOUSE POSITIONING, and SET MOUSE KEYCODE MODE. )
+N.B. If the mouse buttons have been commanded to act like keyboard keys, this
+command DOES affect their actions.
+
+9.14 PAUSE OUTPUT
+
+    0x13
+
+Stop sending data to the host until another valid command is received. Key
+matrix activity is still monitored and scan codes or ASCII characters enqueued
+(up to the maximum supported by the microcontroller) to be sent when the host
+allows the output to be resumed. If in the JOYSTICK EVENT REPORTING mode,
+joystick events are also queued.
+Mouse motion should be accumulated while the output is paused. If the ikbd is
+in RELATIVE MOUSE POSITIONING REPORTING mode, motion is accumulated beyond the
+normal threshold limits to produce the minimum number of packets necessary for
+transmission when output is resumed. Pressing or releasing either mouse button
+causes any accumulated motion to be immediately queued as packets, if the
+mouse is in RELATIVE MOUSE POSITION REPORTING mode.
+Because of the limitations of the microcontroller memory this command should
+be used sparingly, and the output should not be shut of for more than <tbd>
+milliseconds at a time.
+The output is stopped only at the end of the current 'even'. If the PAUSE
+OUTPUT command is received in the middle of a multiple byte report, the packet
+will still be transmitted to conclusion and then the PAUSE will take effect.
+When the ikbd is in either the JOYSTICK MONITORING mode or the FIRE BUTTON
+MONITORING mode, the PAUSE OUTPUT command also temporarily stops the
+monitoring process (i.e. the samples are not enqueued for transmission).
+
+0.15 SET JOYSTICK EVENT REPORTING
+
+    0x14
+
+Enter JOYSTICK EVENT REPORTING mode (DEFAULT). Each opening or closure of a
+joystick switch or trigger causes a joystick event record to be generated.
+
+9.16 SET JOYSTICK INTERROGATION MODE
+
+    0x15
+
+Disables JOYSTICK EVENT REPORTING. Host must send individual JOYSTICK
+INTERROGATE commands to sense joystick state.
+
+9.17 JOYSTICK INTERROGATE
+
+    0x16
+
+Return a record indicating the current state of the joysticks. This command
+is valid in either the JOYSTICK EVENT REPORTING mode or the JOYSTICK
+INTERROGATION MODE.
+
+9.18 SET JOYSTICK MONITORING
+
+    0x17
+    rate                ; time between samples in hundreths of a second
+    Returns: (in packets of two as long as in mode)
+            %000000xy   ; where y is JOYSTICK1 Fire button
+                        ; and x is JOYSTICK0 Fire button
+            %nnnnmmmm   ; where m is JOYSTICK1 state
+                        ; and n is JOYSTICK0 state
+
+Sets the ikbd to do nothing but monitor the serial command lne, maintain the
+time-of-day clock, and monitor the joystick. The rate sets the interval
+between joystick samples.
+N.B. The user should not set the rate higher than the serial communications
+channel will allow the 2 bytes packets to be transmitted.
+
+9.19 SET FIRE BUTTON MONITORING
+
+    0x18
+    Returns: (as long as in mode)
+            %bbbbbbbb   ; state of the JOYSTICK1 fire button packed
+                        ; 8 bits per byte, the first sample if the MSB
+
+Set the ikbd to do nothing but monitor the serial command line, maintain the
+time-of-day clock, and monitor the fire button on Joystick 1. The fire button
+is scanned at a rate that causes 8 samples to be made in the time it takes for
+the previous byte to be sent to the host (i.e. scan rate = 8/10 * baud rate).
+The sample interval should be as constant as possible.
+
+9.20 SET JOYSTICK KEYCODE MODE
+
+    0x19
+    RX                  ; length of time (in tenths of seconds) until
+                        ; horizontal velocity breakpoint is reached
+    RY                  ; length of time (in tenths of seconds) until
+                        ; vertical velocity breakpoint is reached
+    TX                  ; length (in tenths of seconds) of joystick closure
+                        ; until horizontal cursor key is generated before RX
+                        ; has elapsed
+    TY                  ; length (in tenths of seconds) of joystick closure
+                        ; until vertical cursor key is generated before RY
+                        ; has elapsed
+    VX                  ; length (in tenths of seconds) of joystick closure
+                        ; until horizontal cursor keystokes are generated
+                        ; after RX has elapsed
+    VY                  ; length (in tenths of seconds) of joystick closure
+                        ; until vertical cursor keystokes are generated
+                        ; after RY has elapsed
+
+In this mode, joystick 0 is scanned in a way that simulates cursor keystrokes.
+On initial closure, a keystroke pair (make/break) is generated. Then up to Rn
+tenths of seconds later, keystroke pairs are generated every Tn tenths of
+seconds. After the Rn breakpoint is reached, keystroke pairs are generated
+every Vn tenths of seconds. This provides a velocity (auto-repeat) breakpoint
+feature.
+Note that by setting RX and/or Ry to zero, the velocity feature can be
+disabled. The values of TX and TY then become meaningless, and the generation
+of cursor 'keystrokes' is set by VX and VY.
+
+9.21 DISABLE JOYSTICKS
+
+    0x1A
+
+Disable the generation of any joystick events (and scanning may be internally
+disabled). Any valid joystick mode command resumes joystick monitoring. (The
+joystick mode commands are SET JOYSTICK EVENT REPORTING, SET JOYSTICK
+INTERROGATION MODE, SET JOYSTICK MONITORING, SET FIRE BUTTON MONITORING, and
+SET JOYSTICK KEYCODE MODE.)
+
+9.22 TIME-OF-DAY CLOCK SET
+
+    0x1B
+    YY                  ; year (2 least significant digits)
+    MM                  ; month
+    DD                  ; day
+    hh                  ; hour
+    mm                  ; minute
+    ss                  ; second
+
+All time-of-day data should be sent to the ikbd in packed BCD format.
+Any digit that is not a valid BCD digit should be treated as a 'don't care'
+and not alter that particular field of the date or time. This permits setting
+only some subfields of the time-of-day clock.
+
+9.23 INTERROGATE TIME-OF-DAT CLOCK
+
+    0x1C
+    Returns:
+            0xFC        ; time-of-day event header
+            YY          ; year (2 least significant digits)
+            MM          ; month
+            DD          ; day
+            hh          ; hour
+            mm          ; minute
+            ss          ; second
+
+    All time-of-day is sent in packed BCD format.
+
+9.24 MEMORY LOAD
+
+    0x20
+    ADRMSB              ; address in controller
+    ADRLSB              ; memory to be loaded
+    NUM                 ; number of bytes (0-128)
+    { data }
+
+This command permits the host to load arbitrary values into the ikbd
+controller memory. The time between data bytes must be less than 20ms.
+
+9.25 MEMORY READ
+
+    0x21
+    ADRMSB              ; address in controller
+    ADRLSB              ; memory to be read
+    Returns:
+            0xF6        ; status header
+            0x20        ; memory access
+            { data }    ; 6 data bytes starting at ADR
+
+This comand permits the host to read from the ikbd controller memory.
+
+9.26 CONTROLLER EXECUTE
+
+    0x22
+    ADRMSB              ; address of subroutine in
+    ADRLSB              ; controller memory to be called
+
+This command allows the host to command the execution of a subroutine in the
+ikbd controller memory.
+
+9.27 STATUS INQUIRIES
+	
+    Status commands are formed by inclusively ORing 0x80 with the
+    relevant SET command.
+
+    Example:
+    0x88 (or 0x89 or 0x8A)  ; request mouse mode
+    Returns:
+            0xF6        ; status response header
+            mode        ; 0x08 is RELATIVE
+                        ; 0x09 is ABSOLUTE
+                        ; 0x0A is KEYCODE
+            param1      ; 0 is RELATIVE
+                        ; XMSB maximum if ABSOLUTE
+                        ; DELTA X is KEYCODE
+            param2      ; 0 is RELATIVE
+                        ; YMSB maximum if ABSOLUTE
+                        ; DELTA Y is KEYCODE
+            param3      ; 0 if RELATIVE
+                        ; or KEYCODE
+                        ; YMSB is ABSOLUTE
+            param4      ; 0 if RELATIVE
+                        ; or KEYCODE
+                        ; YLSB is ABSOLUTE
+            0           ; pad
+            0
+
+The STATUS INQUIRY commands request the ikbd to return either the current mode
+or the parameters associated with a given command. All status reports are
+padded to form 8 byte long return packets. The responses to the status
+requests are designed so that the host may store them away (after stripping
+off the status report header byte) and later send them back as commands to
+ikbd to restore its state. The 0 pad bytes will be treated as NOPs by the
+ikbd.
+
+    Valid STATUS INQUIRY commands are:
+
+            0x87    mouse button action
+            0x88    mouse mode
+            0x89
+            0x8A
+            0x8B    mnouse threshold
+            0x8C    mouse scale
+            0x8F    mouse vertical coordinates
+            0x90    ( returns       0x0F Y=0 at bottom
+                            0x10 Y=0 at top )
+            0x92    mouse enable/disable
+                    ( returns       0x00 enabled)
+                            0x12 disabled )
+            0x94    joystick mode
+            0x95
+            0x96
+            0x9A    joystick enable/disable
+                    ( returns       0x00 enabled
+                            0x1A disabled )
+
+It is the (host) programmer's responsibility to have only one unanswered
+inquiry in process at a time.
+STATUS INQUIRY commands are not valid if the ikbd is in JOYSTICK MONITORING
+mode or FIRE BUTTON MONITORING mode.
+
+
+10. SCAN CODES
+
+The key scan codes return by the ikbd are chosen to simplify the
+implementaion of GSX.
+
+GSX Standard Keyboard Mapping.
+
+Hex	Keytop
+01	Esc
+02	1
+03	2
+04	3
+05	4
+06	5
+07	6
+08	7
+09	8
+0A	9
+0B	0
+0C	-
+0D	==
+0E	BS
+0F	TAB
+10	Q
+11	W
+12	E
+13	R
+14	T
+15	Y
+16	U
+17	I
+18	O
+19	P
+1A	[
+1B	]
+1C	RET
+1D	CTRL
+1E	A
+1F	S
+20	D
+21	F
+22	G
+23	H
+24	J
+25	K
+26	L
+27	;
+28	'
+29	`
+2A	(LEFT) SHIFT
+2B	\
+2C	Z
+2D	X
+2E	C
+2F	V
+30	B
+31	N
+32	M
+33	,
+34	.
+35	/
+36	(RIGHT) SHIFT
+37	{ NOT USED }
+38	ALT
+39	SPACE BAR
+3A	CAPS LOCK
+3B	F1
+3C	F2
+3D	F3
+3E	F4
+3F	F5
+40	F6
+41	F7
+42	F8
+43	F9
+44	F10
+45	{ NOT USED }
+46	{ NOT USED }
+47	HOME
+48	UP ARROW
+49	{ NOT USED }
+4A	KEYPAD -
+4B	LEFT ARROW
+4C	{ NOT USED }
+4D	RIGHT ARROW
+4E	KEYPAD +
+4F	{ NOT USED }
+50	DOWN ARROW
+51	{ NOT USED }
+52	INSERT
+53	DEL
+54	{ NOT USED }
+5F	{ NOT USED }
+60	ISO KEY
+61	UNDO
+62	HELP
+63	KEYPAD (
+64	KEYPAD /
+65	KEYPAD *
+66	KEYPAD *
+67	KEYPAD 7
+68	KEYPAD 8
+69	KEYPAD 9
+6A	KEYPAD 4
+6B	KEYPAD 5
+6C	KEYPAD 6
+6D	KEYPAD 1
+6E	KEYPAD 2
+6F	KEYPAD 3
+70	KEYPAD 0
+71	KEYPAD .
+72	KEYPAD ENTER
diff -Nru a/Documentation/input/cd32.txt b/Documentation/input/cd32.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/input/cd32.txt	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,19 @@
+I have written a small patch that let's me use my Amiga CD32
+joypad connected to the parallel port. Thought I'd share it with you so
+you can add it to the list of supported joysticks (hopefully someone will
+find it useful).
+
+It needs the following wiring:
+
+CD32 pad   |   Parallel port
+----------------------------
+1 (Up)     |    2 (D0)
+2 (Down)   |    3 (D1)
+3 (Left)   |    4 (D2)
+4 (Right)  |    5 (D3)
+5 (Fire3)  |   14 (AUTOFD)
+6 (Fire1)  |   17 (SELIN)
+7 (+5V)    |    1 (STROBE)
+8 (Gnd)    |   18 (Gnd)
+9 (Fire2)  |    7 (D5)
+
diff -Nru a/Documentation/input/ff.txt b/Documentation/input/ff.txt
--- a/Documentation/input/ff.txt	Tue Jul 16 16:49:43 2002
+++ b/Documentation/input/ff.txt	Tue Jul 16 16:49:43 2002
@@ -1,6 +1,7 @@
 Force feedback for Linux.
 By Johann Deneux <deneux@ifrance.com> on 2001/04/22.
-
+You can redistribute this file, provided you include shape.fig and
+interactive.fig.
 ----------------------------------------------------------------------------
 
 0. Introduction
@@ -38,13 +39,10 @@
 
 You then need to insert the modules into the following order:
 % modprobe joydev
-% modprobe serport
+% modprobe serport		# Only for serial
 % modprobe iforce
 % modprobe evdev
 % ./inputattach -ifor $2 &	# Only for serial
-For convenience, you may use the shell script named "ff" available from
-the cvs tree of the Linux Console Project at sourceforge. You can also
-retrieve it from http://www.esil.univ-mrs.fr/~jdeneux/projects/ff/.
 If you are using USB, you don't need the inputattach step.
 
 Please check that you have all the /dev/input entries needed:
@@ -68,7 +66,7 @@
 2.1 Does it work ?
 ~~~~~~~~~~~~~~~~~~
 There is an utility called fftest that will allow you to test the driver.
-% fftest /dev/eventXX
+% fftest /dev/input/eventXX
 
 3. Instructions to the developper
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -81,22 +79,28 @@
 #include <linux/input.h>
 #include <sys/ioctl.h>
 
+unsigned long features[1 + FF_MAX/sizeof(unsigned long)];
 int ioctl(int file_descriptor, int request, unsigned long *features);
 
-"request" must be EVIOCGBIT(EV_FF, sizeof(unsigned long))
+"request" must be EVIOCGBIT(EV_FF, size of features array in bytes )
 
 Returns the features supported by the device. features is a bitfield with the
 following bits:
-- FF_X		has an X axis (should allways be the case)
-- FF_Y		has an Y axis (usually not the case for wheels)
+- FF_X		has an X axis (usually joysticks)
+- FF_Y		has an Y axis (usually joysticks)
+- FF_WHEEL	has a wheel (usually sterring wheels)
 - FF_CONSTANT	can render constant force effects
 - FF_PERIODIC	can render periodic effects (sine, ramp, square...)
 - FF_SPRING	can simulate the presence of a spring
-- FF_FRICTION	can simulate friction (aka drag, damper effect...)
+- FF_FRICTION	can simulate friction 
+- FF_DAMPER	can simulate damper effects
 - FF_RUMBLE	rumble effects (normally the only effect supported by rumble
 		pads)
-- 8 bits from FF_N_EFFECTS_0 containing the number of effects that can be
-		simultaneously played.
+
+
+int ioctl(int fd, EVIOCGEFFECTS, int *n);
+
+Returns the number of effects the device can keep in its memory.
 
 3.2 Uploading effects to the device
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -112,7 +116,11 @@
 The content of effect may be modified. In particular, its field "id" is set
 to the unique id assigned by the driver. This data is required for performing
 some operations (removing an effect, controlling the playback).
-See <linux/input.h> for a description of the ff_effect stuct.
+This if field must be set to -1 by the user in order to tell the driver to
+allocate a new effect.
+See <linux/input.h> for a description of the ff_effect stuct. You should also
+find help in a few sketches, contained in files shape.fig and interactive.fig.
+You need xfig to visualize these files.
 
 3.3 Removing an effect from the device
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -187,8 +195,31 @@
 
 3.7 Dynamic update of an effect
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-This consists in changing some parameters of an effect while it's playing. The
-driver currently does not support that. You still have the brute-force method,
-which consists in erasing the effect and uploading the updated version. It
-actually works pretty well. You don't need to stop-and-start the effect.
+Proceed as if you wanted to upload a new effect, except that instead of
+setting the id field to -1, you set it to the wanted effect id.
+Normally, the effect is not stopped and restarted. However, depending on the
+type of device, not all paramaters can be dynamically updated. For example,
+the direction of an effect cannot be updated with iforce devices. In this
+case, the driver stops the effect, up-load it, and restart it.
+
+
+3.8 Information about the status of effects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Every time the status of an effect is changed, an event is sent. The values
+and meanings of the fields of the event are as follows:
+struct input_event {
+/* When the status of the effect changed */
+	struct timeval time;
+
+/* Set to EV_FF_STATUS */
+	unsigned short type;
+
+/* Contains the id of the effect */
+	unsigned short code;
+
+/* Indicates the status */
+	unsigned int value;
+};
 
+FF_STATUS_STOPPED	The effect stopped playing
+FF_STATUS_PLAYING	The effect started to play
diff -Nru a/Documentation/input/iforce-protocol.txt b/Documentation/input/iforce-protocol.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/input/iforce-protocol.txt	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,254 @@
+** Introduction
+This document describes what I managed to discover about the protocol used to
+specify force effects to I-Force 2.0 devices.  None of this information comes
+from Immerse. That's why you should not trust what is written in this
+document. This document is intended to help understanding the protocol.
+This is not a reference. Comments and corrections are welcome.  To contact me,
+send an email to: deneux@ifrance.com
+
+** WARNING **
+I may not be held responsible for any dammage or harm caused if you try to
+send data to your I-Force device based on what you read in this document.
+
+** Preliminary Notes:
+All values are hexadecimal with big-endian encoding (msb on the left). Beware,
+values inside packets are encoded using little-endian.  Bytes whose roles are
+unknown are marked ???  Information that needs deeper inspection is marked (?)
+
+** General form of a packet **
+This is how packets look when the device uses the rs232 to communicate.
+2B OP LEN DATA CS
+CS is the checksum. It is equal to the exclusive or of all bytes.
+
+When using USB:
+OP DATA
+The 2B, LEN and CS fields have disappeared, probably because USB handles frames and
+data corruption is handled or unsignificant.
+
+First, I describe effects that are sent by the device to the computer
+
+** Device input state
+This packet is used to indicate the state of each button and the value of each
+axis
+OP= 01 for a joystick, 03 for a wheel
+LEN= Varies from device to device
+00 X-Axis lsb
+01 X-Axis msb
+02 Y-Axis lsb, or gas pedal for a wheel
+03 Y-Axis msb, or brake pedal for a wheel
+04 Throttle
+05 Buttons
+06 Lower 4 bits: Buttons
+   Upper 4 bits: Hat
+07 Rudder
+
+** Device effects states
+OP= 02
+LEN= Varies
+00 ? Bit 1 (Value 2) is the value of the deadman switch
+01 Bit 8 is set if the effect is playing. Bits 0 to 7 are the effect id.
+02 ??
+03 Address of parameter block changed (lsb)
+04 Address of parameter block changed (msb)
+05 Address of second parameter block changed (lsb)
+... depending on the number of parameter blocks updated
+
+** Force effect **
+OP=  01
+LEN= 0e
+00 Channel (when playing several effects at the same time, each must be assigned a channel)
+01 Wave form
+	Val 00 Constant
+	Val 20 Square
+	Val 21 Triangle
+	Val 22 Sine
+	Val 23 Sawtooth up
+	Val 24 Sawtooth down
+	Val 40 Spring (Force = f(pos))
+	Val 41 Friction (Force = f(velocity)) and Inertia (Force = f(acceleration))
+
+	
+02 Axes affected and trigger
+	Bits 4-7: Val 2 = effect along one axis. Byte 05 indicates direction
+	          Val 4 = X axis only. Byte 05 must contain 5a
+	          Val 8 = Y axis only. Byte 05 must contain b4
+	          Val c = X and Y axes. Bytes 05 must contain 60
+	Bits 0-3: Val 0 = No trigger
+	          Val x+1 = Button x triggers the effect
+	When the whole byte is 0, cancel the previously set trigger
+
+03-04 Duration of effect (little endian encoding, in ms)
+
+05 Direction of effect, if applicable. Else, see 02 for value to assign.
+
+06-07 Minimum time between triggering.
+
+08-09 Address of periodicity or magnitude parameters
+0a-0b Address of attack and fade parameters, or ffff if none.
+*or*
+08-09 Address of interactive parameters for X-axis, or ffff if not applicable
+0a-0b Address of interactive parameters for Y-axis, or ffff if not applicable
+
+0c-0d Delay before execution of effect (little endian encoding, in ms)
+
+
+** Time based parameters **
+
+*** Attack and fade ***
+OP=  02
+LEN= 08
+00-01 Address where to store the parameteres
+02-03 Duration of attack (little endian encoding, in ms)
+04 Level at end of attack. Signed byte.
+05-06 Duration of fade.
+07 Level at end of fade.
+
+*** Magnitude ***
+OP=  03
+LEN= 03
+00-01 Address
+02 Level. Signed byte.
+
+*** Periodicity ***
+OP=  04
+LEN= 07
+00-01 Address
+02 Magnitude. Signed byte.
+03 Offset. Signed byte.
+04 Phase. Val 00 = 0 deg, Val 40 = 90 degs.
+05-06 Period (little endian encoding, in ms)
+
+** Interactive parameters **
+OP=  05
+LEN= 0a
+00-01 Address
+02 Positive Coeff
+03 Negative Coeff
+04+05 Offset (center)
+06+07 Dead band (Val 01F4 = 5000 (decimal))
+08 Positive saturation (Val 0a = 1000 (decimal) Val 64 = 10000 (decimal))
+09 Negative saturation
+
+The encoding is a bit funny here: For coeffs, these are signed values. The
+maximum value is 64 (100 decimal), the min is 9c.
+For the offset, the minimum value is FE0C, the maximum value is 01F4.
+For the deadband, the minimum value is 0, the max is 03E8.
+
+** Controls **
+OP=  41
+LEN= 03
+00 Channel
+01 Start/Stop
+	Val 00: Stop
+	Val 01: Start and play once.
+	Val 41: Start and play n times (See byte 02 below)
+02 Number of iterations n.
+
+** Init **
+
+*** Querying features ***
+OP=  ff
+Query command. Length varies according to the query type.
+The general format of this packet is:
+ff 01 QUERY [INDEX] CHECKSUM
+reponses are of the same form:
+FF LEN QUERY VALUE_QUERIED CHECKSUM2
+where LEN = 1 + length(VALUE_QUERIED)
+
+**** Query ram size ****
+QUERY = 42 ('B'uffer size)
+The device should reply with the same packet plus two additionnal bytes
+containing the size of the memory:
+ff 03 42 03 e8 CS would mean that the device has 1000 bytes of ram available.
+
+**** Query number of effects ****
+QUERY = 4e ('N'umber of effects)
+The device should respond by sending the number of effects that can be played
+at the same time (one byte)
+ff 02 4e 14 CS would stand for 20 effects.
+
+**** Vendor's id ****
+QUERY = 4d ('M'anufacturer)
+Query the vendors'id (2 bytes)
+
+**** Product id *****
+QUERY = 50 ('P'roduct)
+Query the product id (2 bytes)
+
+**** Open device ****
+QUERY = 4f ('O'pen) 
+No data returned.
+
+**** Close device *****
+QUERY = 43 ('C')lose
+No data returned.
+
+**** Query effect ****
+QUERY = 45 ('E') 
+Send effect type.
+Returns nonzero if supported (2 bytes)
+
+**** Firmware Version ****
+QUERY = 56 ('V'ersion)
+Sends back 3 bytes - major, minor, subminor
+
+*** Initialisation of the device ***
+
+**** Set Control ****
+!!! Device dependent, can be different on different models !!!
+OP=  40 <idx> <val> [<val>]
+LEN= 2 or 3
+00 Idx
+   Idx 00 Set dead zone (0..2048) 
+   Idx 01 Ignore Deadman sensor (0..1)     
+   Idx 02 Enable comm watchdog (0..1)     
+   Idx 03 Set the strength of the spring (0..100)   
+   Idx 04 Enable or disable the spring (0/1)
+   Idx 05 Set axis saturation threshold (0..2048) 
+
+**** Set Effect State ****
+OP=  42 <val>
+LEN= 1
+00 State
+   Bit 3 Pause force feedback
+   Bit 2 Enable force feedback
+   Bit 0 Stop all effects
+
+**** Set overall gain ****
+OP=  43 <val>
+LEN= 1
+00 Gain
+   Val 00 = 0%
+   Val 40 = 50%
+   Val 80 = 100%
+
+** Parameter memory **
+
+Each device has a certain amount of memory to store parameters of effects.
+The amount of RAM may vary, I encountered values from 200 to 1000 bytes. Below
+is the amount of memory apparently needed for every set of parameters:
+ - period : 0c
+ - magnitude : 02
+ - attack and fade : 0e
+ - interactive : 08
+
+** Appendix: How to study the protocol ? **
+
+1. Generate effects using the force editor provided with the DirectX SDK, or use Immersion Studio (freely available at their web site in the developer section: www.immersion.com)
+2. Start a soft spying RS232 or USB (depending on where you connected your joystick/wheel). I used ComPortSpy from fCoder (alpha version!)
+3. Play the effect, and watch what happens on the spy screen.
+
+A few words about ComPortSpy:
+At first glance, this soft seems, hum, well... buggy. In fact, data appear with a few seconds latency. Personnaly, I restart it every time I play an effect.
+Remember it's free (as in free beer) and alpha!
+
+** URLS **
+Check www.immerse.com for Immersion Studio, and www.fcoder.com for ComPortSpy.
+
+** Author of this document **
+Johann Deneux <deneux@ifrance.com>
+Home page at http://www.esil.univ-mrs.fr/~jdeneux/projects/ff/
+
+Additions by Vojtech Pavlik.
+
+I-Force is trademark of Immersion Corp.
diff -Nru a/Documentation/input/input.txt b/Documentation/input/input.txt
--- a/Documentation/input/input.txt	Tue Jul 16 16:49:41 2002
+++ b/Documentation/input/input.txt	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 			  Linux Input drivers v1.0
-	       (c) 1999-2001 Vojtech Pavlik <vojtech@suse.cz>
+	       (c) 1999-2001 Vojtech Pavlik <vojtech@ucw.cz>
 			     Sponsored by SuSE
-	    $Id: input.txt,v 1.5 2001/06/06 11:05:33 vojtech Exp $
+	    $Id: input.txt,v 1.8 2002/05/29 03:15:01 bradleym Exp $
 ----------------------------------------------------------------------------
 
 0. Disclaimer
@@ -21,7 +21,7 @@
 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
   Should you need to contact me, the author, you can do so either by e-mail
-- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
+- mail your message to <vojtech@ucw.cz>, or by paper mail: Vojtech Pavlik,
 Simunkova 1594, Prague 8, 182 00 Czech Republic
 
   For your convenience, the GNU General Public License version 2 is included
@@ -30,11 +30,12 @@
 1. Introduction
 ~~~~~~~~~~~~~~~
   This is a collection of drivers that is designed to support all input
-devices under Linux. However, in the current kernels, although it's
-possibilities are much bigger, it's limited to USB devices only. This is
-also why it resides in the drivers/usb subdirectory.
+devices under Linux. While it is currently used only on for USB input
+devices, future use (say 2.5/2.6) is expected to expand to replace
+most of the existing input system, which is why it lives in
+drivers/input/ instead of drivers/usb/.
 
-  The center of the input drivers is the input.o module, which must be
+  The centre of the input drivers is the input.o module, which must be
 loaded before any other of the input modules - it serves as a way of
 communication between two groups of modules:
 
@@ -59,7 +60,7 @@
 	mousedev.o
 	keybdev.o
 	usbcore.o
-	usb-[uo]hci.o
+	usb-uhci.o or usb-ohci.o or uhci.o
 	hid.o
 
   After this, the USB keyboard will work straight away, and the USB mouse
@@ -67,8 +68,8 @@
 
 	crw-r--r--   1 root     root      13,  63 Mar 28 22:45 mice
 
-  This device, has to be created, unless you use devfs, in which case it's
-created automatically. The commands to do that are:
+  This device has to be created, unless you use devfs, in which case it's
+created automatically. The commands to do create it by hand are:
 
 	cd /dev
 	mkdir input
@@ -97,9 +98,9 @@
 however not useful without being handled, so you also will need to use some
 of the modules from section 3.2.
 
-3.1.1 hid.c
+3.1.1 hid.o
 ~~~~~~~~~~~
-  Hid.c is the largest and most complex driver of the whole suite. It
+  hid.o is the largest and most complex driver of the whole suite. It
 handles all HID devices, and because there is a very wide variety of them,
 and because the USB HID specification isn't simple, it needs to be this big.
 
@@ -120,59 +121,62 @@
 
   However, because the devices vary wildly, you might happen to have a
 device that doesn't work well. In that case #define DEBUG at the beginning
-of hid.c and send me the syslog traces.
+of hid-core.c and send me the syslog traces.
 
-3.1.2 usbmouse.c
+3.1.2 usbmouse.o
 ~~~~~~~~~~~~~~~~
   For embedded systems, for mice with broken HID descriptors and just any
-other use when the big hid.c wouldn't be a good choice, there is the
+other use when the big hid.o wouldn't be a good choice, there is the
 usbmouse.c driver. It handles USB mice only. It uses a simpler HIDBP
 protocol. This also means the mice must support this simpler protocol. Not
-all do. If you don't have any strong reason to use this module, use hid.c
+all do. If you don't have any strong reason to use this module, use hid.o
 instead.
 
-3.1.3 usbkbd.c
+3.1.3 usbkbd.o
 ~~~~~~~~~~~~~~
-  Much like usbmouse.c, this module talks to keyboards with a simpplified
+  Much like usbmouse.c, this module talks to keyboards with a simplified
 HIDBP protocol. It's smaller, but doesn't support any extra special keys.
-Use hid.c instead if there isn't any special reason to use this.
+Use hid.o instead if there isn't any special reason to use this.
 
-3.1.4 wacom.c
+3.1.4 wacom.o
 ~~~~~~~~~~~~~
   This is a driver for Wacom Graphire and Intuos tablets. Not for Wacom
 PenPartner, that one is handled by the HID driver. Although the Intuos and
 Graphire tablets claim that they are HID tablets as well, they are not and
 thus need this specific driver.
 
-3.1.5 iforce.c
+3.1.5 iforce.o
 ~~~~~~~~~~~~~~~
   A driver for I-Force joysticks and wheels, both over USB and RS232. 
-It includes ForceFeedback support now, even though Immersion Corp. considers
-the protocol a trade secret and won't disclose a word about it.
+It includes ForceFeedback support now, even though Immersion
+Corp. considers the protocol a trade secret and won't disclose a word
+about it. 
 
 3.2 Event handlers
 ~~~~~~~~~~~~~~~~~~
   Event handlers distrubite the events from the devices to userland and
 kernel, as needed.
 
-3.2.1 keybdev.c
+3.2.1 keybdev.o
 ~~~~~~~~~~~~~~~
-  Keybdev is currently a rather ugly hack that translates the input events
-into architecture-specific keyboard raw mode (Xlated AT Set2 on x86), and
-passes them into the handle_scancode function of the keyboard.c module. This
-works well enough on all architectures that keybdev can generate rawmode on,
-other architectures can be added to it.
-
-  The right way would be to pass the events to keyboard.c directly, best if
-keyboard.c would itself be an event handler. This is done in the input
-patch, available on the webpage mentioned below.
+  keybdev is currently a rather ugly hack that translates the input
+events into architecture-specific keyboard raw mode (Xlated AT Set2 on
+x86), and passes them into the handle_scancode function of the
+keyboard.c module. This works well enough on all architectures that
+keybdev can generate rawmode on, other architectures can be added to
+it.
+
+  The right way would be to pass the events to keyboard.c directly,
+best if keyboard.c would itself be an event handler. This is done in
+the input patch, available on the webpage mentioned below. 
 
-3.2.2 mousedev.c
+3.2.2 mousedev.o
 ~~~~~~~~~~~~~~~~
-  Mousedev is also a hack to make programs that use mouse input work. It
-takes events from either mice or digitizers/tablets and makes a PS/2-style
-(a la /dev/psaux) mouse device available to the userland. Ideally, the
-programs could use a more reasonable interface, for example evdev.c
+  mousedev is also a hack to make programs that use mouse input
+work. It takes events from either mice or digitizers/tablets and makes
+a PS/2-style (a la /dev/psaux) mouse device available to the
+userland. Ideally, the programs could use a more reasonable interface,
+for example evdev.o
 
   Mousedev devices in /dev/input (as shown above) are:
 
@@ -185,30 +189,31 @@
 	crw-r--r--   1 root     root      13,  62 Apr  1 10:50 mouse30
 	crw-r--r--   1 root     root      13,  63 Apr  1 10:50 mice
 
-Each 'mouse' device is assigned to a single mouse or digitizer, except the last
-one - 'mice'. This single character device is shared by all mice and
-digitizers, and even if none are connected, the device is present.  This is
-useful for hotplugging USB mice, so that programs can open the device even when
-no mice are present.
-
-  CONFIG_INPUT_MOUSEDEV_SCREEN_[XY] in the kernel configuration are the size
-of your screen (in pixels) in XFree86. This is needed if you want to use
-your digitizer in X, because it's movement is sent to X via a virtual PS/2
-mouse and thus needs to be scaled accordingly. These values won't be used if
-you use a mouse only.
+Each 'mouse' device is assigned to a single mouse or digitizer, except
+the last one - 'mice'. This single character device is shared by all
+mice and digitizers, and even if none are connected, the device is
+present.  This is useful for hotplugging USB mice, so that programs
+can open the device even when no mice are present.
+
+  CONFIG_INPUT_MOUSEDEV_SCREEN_[XY] in the kernel configuration are
+the size of your screen (in pixels) in XFree86. This is needed if you
+want to use your digitizer in X, because its movement is sent to X
+via a virtual PS/2 mouse and thus needs to be scaled
+accordingly. These values won't be used if you use a mouse only.
 
   Mousedev will generate either PS/2, ImPS/2 (Microsoft IntelliMouse) or
-ExplorerPS/2 (IntelliMouse Explorer) protocols, depending on what the program
-reading the data wishes. You can set GPM and X to any of these. You'll need
-ImPS/2 if you want to make use of a wheel on a USB mouse and ExplorerPS/2 if you
-want to use extra (up to 5) buttons. 
+ExplorerPS/2 (IntelliMouse Explorer) protocols, depending on what the
+program reading the data wishes. You can set GPM and X to any of
+these. You'll need ImPS/2 if you want to make use of a wheel on a USB
+mouse and ExplorerPS/2 if you want to use extra (up to 5) buttons. 
 
 3.2.3 joydev.c
 ~~~~~~~~~~~~~~
   Joydev implements v0.x and v1.x Linux joystick api, much like
 drivers/char/joystick/joystick.c used to in earlier versions. See
-joystick-api.txt in the Documentation subdirectory for details.  As soon as
-any joystick is connected, it can be accessed in /dev/input on:
+joystick-api.txt in the Documentation subdirectory for details.  As
+soon as any joystick is connected, it can be accessed in /dev/input
+on: 
 
 	crw-r--r--   1 root     root      13,   0 Apr  1 10:50 js0
 	crw-r--r--   1 root     root      13,   1 Apr  1 10:50 js1
@@ -218,16 +223,17 @@
 
 And so on up to js31.
 
-3.2.4 evdev.c
+3.2.4 evdev.o
 ~~~~~~~~~~~~~
-  Evdev is the generic input event interface. It passes the events generated
-in the kernel straight to the program, with timestamps. The API is still
-evolving, but should be useable now. It's described in section 5.
+  evdev is the generic input event interface. It passes the events
+generated in the kernel straight to the program, with timestamps. The
+API is still evolving, but should be useable now. It's described in
+section 5. 
 
   This should be the way for GPM and X to get keyboard and mouse mouse
-events. It allows for multihead in X without any specific multihead kernel
-support. The event codes are the same on all architectures and are hardware
-independent.
+events. It allows for multihead in X without any specific multihead
+kernel support. The event codes are the same on all architectures and
+are hardware independent.
 
   The devices are in /dev/input:
 
@@ -237,40 +243,27 @@
 	crw-r--r--   1 root     root      13,  67 Apr  1 10:50 event3
 	...
 
-3. Contacts
-~~~~~~~~~~~
-  This effort has it's home page at:
-
-	http://www.suse.cz/development/input/
-
-You'll find both the latest HID driver and the complete Input driver there
-as well as information how to access the CVS repository for latest revisions
-of the drivers.
-
-  There is also a mailing list for this:
-
-	majordomo@atrey.karlin.mff.cuni.cz
-
-Send "subscribe linux-input" to subscribe to it.
+And so on up to event31.
 
 4. Verifying if it works
 ~~~~~~~~~~~~~~~~~~~~~~~~
-  Typing a couple keys on the keyboard should be enough to check that a USB
-keyboard works and is correctly connected to the kernel keyboard driver.
+  Typing a couple keys on the keyboard should be enough to check that
+a USB keyboard works and is correctly connected to the kernel keyboard
+driver. 
 
-  Doing a cat /dev/input/mouse0 (c, 13, 32) will verify that a mouse is also
-emulated, characters should appear if you move it.
+  Doing a cat /dev/input/mouse0 (c, 13, 32) will verify that a mouse
+is also emulated, characters should appear if you move it.
 
-  You can test the joystick emulation with the 'jstest' utility, available
-in the joystick package (see Documentation/joystick.txt).
+  You can test the joystick emulation with the 'jstest' utility,
+available in the joystick package (see Documentation/joystick.txt).
 
-  You can test the event devics with the 'evtest' utitily available on the
-input driver homepage (see the URL above).
+  You can test the event devices with the 'evtest' utility available
+in the LinuxConsole project CVS archive (see the URL below).
 
 5. Event interface
 ~~~~~~~~~~~~~~~~~~
   Should you want to add event device support into any application (X, gpm,
-svgalib ...) I <vojtech@suse.cz> will be happy to provide you any help I
+svgalib ...) I <vojtech@ucw.cz> will be happy to provide you any help I
 can. Here goes a description of the current state of things, which is going
 to be extended, but not changed incompatibly as time goes:
 
@@ -295,3 +288,25 @@
   'value' is the value the event carries. Either a relative change for
 EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
 release, 1 for keypress and 2 for autorepeat.
+
+6. Contacts
+~~~~~~~~~~~
+  This effort has its home page at:
+
+	http://www.suse.cz/development/input/
+
+You'll find both the latest HID driver and the complete Input driver
+there as well as information how to access the CVS repository for
+latest revisions of the drivers.
+
+  There is also a mailing list for this:
+
+	majordomo@atrey.karlin.mff.cuni.cz
+
+Send "subscribe linux-input" to subscribe to it.
+
+The input changes are also being worked on as part of the LinuxConsole
+project, see:
+
+	 http://sourceforge.net/projects/linuxconsole/
+
diff -Nru a/Documentation/input/interactive.fig b/Documentation/input/interactive.fig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/input/interactive.fig	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,42 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 1 0 2 0 7 50 0 -1 6.000 0 0 -1 0 0 6
+	 1200 3600 1800 3600 2400 4800 3000 4800 4200 5700 4800 5700
+2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
+	 1200 3150 4800 3150 4800 6300 1200 6300 1200 3150
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 1200 4800 4800 4800
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4
+	 2400 4800 2400 6525 1950 7125 1950 7800
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4
+	 3000 4800 3000 6525 3600 7125 3600 7800
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 1 3
+	0 0 1.00 60.00 120.00
+	 3825 5400 4125 5100 5400 5100
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 1 3
+	0 0 1.00 60.00 120.00
+	 2100 4200 2400 3900 5400 3900
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 4800 5700 5400 5700
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 1800 3600 5400 3600
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 1 3
+	0 0 1.00 60.00 120.00
+	 2700 4800 2700 4425 5400 4425
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
+	0 0 1.00 60.00 120.00
+	0 0 1.00 60.00 120.00
+	 1950 7800 3600 7800
+4 1 0 50 0 0 12 0.0000 4 135 810 2775 7725 Dead band\001
+4 0 0 50 0 0 12 0.0000 4 180 1155 5400 5700 right saturation\001
+4 0 0 50 0 0 12 0.0000 4 135 1065 5400 3600 left saturation\001
+4 0 0 50 0 0 12 0.0000 4 180 2505 5400 3900 left coeff ( positive in that case )\001
+4 0 0 50 0 0 12 0.0000 4 180 2640 5475 5100 right coeff ( negative in that case )\001
+4 0 0 50 0 0 12 0.0000 4 105 480 5400 4425 center\001
diff -Nru a/Documentation/input/joystick-parport.txt b/Documentation/input/joystick-parport.txt
--- a/Documentation/input/joystick-parport.txt	Tue Jul 16 16:49:42 2002
+++ b/Documentation/input/joystick-parport.txt	Tue Jul 16 16:49:42 2002
@@ -1,8 +1,8 @@
 		    Linux Joystick parport drivers v2.0
-	       (c) 1998-2000 Vojtech Pavlik <vojtech@suse.cz>
+	       (c) 1998-2000 Vojtech Pavlik <vojtech@ucw.cz>
 	       (c) 1998 Andree Borrmann <a.borrmann@tu-bs.de>
 			     Sponsored by SuSE
-	$Id: joystick-parport.txt,v 1.5 2001/05/15 06:41:00 vojtech Exp $
+	$Id: joystick-parport.txt,v 1.6 2001/09/25 09:31:32 vojtech Exp $
 ----------------------------------------------------------------------------
 
 0. Disclaimer
diff -Nru a/Documentation/input/joystick.txt b/Documentation/input/joystick.txt
--- a/Documentation/input/joystick.txt	Tue Jul 16 16:49:43 2002
+++ b/Documentation/input/joystick.txt	Tue Jul 16 16:49:43 2002
@@ -1,7 +1,7 @@
 		       Linux Joystick driver v2.0.0
-	       (c) 1996-2000 Vojtech Pavlik <vojtech@suse.cz>
+	       (c) 1996-2000 Vojtech Pavlik <vojtech@ucw.cz>
 			     Sponsored by SuSE
-	   $Id: joystick.txt,v 1.6 2001/06/05 09:57:01 vojtech Exp $
+	   $Id: joystick.txt,v 1.12 2002/03/03 12:13:07 jdeneux Exp $
 ----------------------------------------------------------------------------
 
 0. Disclaimer
@@ -21,8 +21,8 @@
 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
   Should you need to contact me, the author, you can do so either by e-mail
-- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
-Ucitelska 1576, Prague 8, 182 00 Czech Republic
+- mail your message to <vojtech@ucw.cz>, or by paper mail: Vojtech Pavlik,
+Simunkova 1594, Prague 8, 182 00 Czech Republic
 
   For your convenience, the GNU General Public License version 2 is included
 in the package: See the file COPYING.
@@ -111,7 +111,7 @@
 	alias tty-ldisc-2 serport
 	alias char-major-13 input
 	above input joydev ns558 analog
-	options analog js=gameport
+	options analog js=gamepad
 
 2.5 Verifying that it works
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -503,15 +503,16 @@
 
 3.21 I-Force devices 
 ~~~~~~~~~~~~~~~~~~~~
-  All I-Force devices are supported by the iforce.c module. This includes:
+  All I-Force devices are supported by the iforce.o module. This includes:
 
 * AVB Mag Turbo Force
 * AVB Top Shot Pegasus
+* AVB Top Shot Force Feedback Racing Wheel
 * Logitech WingMan Force
-* Logitech WingMan Force 3D
 * Logitech WingMan Force Wheel 
-* Logitech WingMan Strike Force 3D
 * Guillemot Race Leader Force Feedback
+* Guillemot Force Feedback Racing Wheel
+* Thrustmaster Motor Sport GT
 
   To use it, you need to attach the serial port to the driver using the
 
@@ -524,6 +525,10 @@
 isn't needed.
 
   The I-Force driver now supports force feedback via the event interface.
+
+  Please note that Logitech WingMan *3D devices are _not_ supported by this
+module, rather by hid. Force feedback is not supported for those devices.
+Logitech gamepads are also hid devices.
 
 3.22 Gravis Stinger gamepad 
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff -Nru a/Documentation/input/shape.fig b/Documentation/input/shape.fig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/input/shape.fig	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,65 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 6
+	 4200 3600 4200 3075 4950 2325 7425 2325 8250 3150 8250 3600
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 4200 3675 4200 5400
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 8250 3675 8250 5400
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 3675 3600 8700 3600
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 8775 3600 10200 3600
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 8325 3150 9075 3150
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 7500 2325 10200 2325
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 3600 3600 3000 3600
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 4125 3075 3000 3075
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
+	0 0 1.00 60.00 120.00
+	0 0 1.00 60.00 120.00
+	 4200 5400 8175 5400
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
+	0 0 1.00 60.00 120.00
+	0 0 1.00 60.00 120.00
+	 10125 2325 10125 3600
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
+	0 0 1.00 60.00 120.00
+	0 0 1.00 60.00 120.00
+	 3000 3150 3000 3600
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
+	0 0 1.00 60.00 120.00
+	0 0 1.00 60.00 120.00
+	 9075 3150 9075 3600
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 4950 2325 4950 1200
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
+	 7425 2325 7425 1200
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4
+	 4200 3075 4200 2400 3600 1800 3600 1200
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4
+	 8250 3150 8250 2475 8775 1950 8775 1200
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
+	0 0 1.00 60.00 120.00
+	0 0 1.00 60.00 120.00
+	 3600 1275 4950 1275
+2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
+	0 0 1.00 60.00 120.00
+	0 0 1.00 60.00 120.00
+	 7425 1275 8700 1275
+4 1 0 50 0 0 12 0.0000 4 135 1140 6075 5325 Effect duration\001
+4 0 0 50 0 0 12 0.0000 4 180 1305 10200 3000 Effect magnitude\001
+4 0 0 50 0 0 12 0.0000 4 135 780 9150 3450 Fade level\001
+4 1 0 50 0 0 12 0.0000 4 180 1035 4275 1200 Attack length\001
+4 1 0 50 0 0 12 0.0000 4 180 885 8175 1200 Fade length\001
+4 2 0 50 0 0 12 0.0000 4 135 930 2925 3375 Attack level\001
diff -Nru a/Documentation/input/xpad.txt b/Documentation/input/xpad.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/input/xpad.txt	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,84 @@
+usb-xpad - Linux USB driver for XBOX HID gamecontrollers
+
+This is the very first release of a driver for XBOX gamecontrollers.
+Basically, this was hacked away in just a few hours, so don't expect
+miracles.
+
+0. Status
+---------
+
+For now, this driver has only been tested on just one Linux-Box.
+This one is running a 2.4.18 kernel with usb-uhci on an amd athlon 600.
+
+The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) reports
+8 axes and 10 buttons.
+
+Alls 8 axes work, though they all have the same range (-32768..32767)
+and the zero-setting is not correct for the triggers.
+9 of the 10 buttons work (my black button does not work, though I can
+see no reason for it not to), all of them are in digital mode, though
+(the six buttons on the right side are "analog" ones).
+
+
+1. USB adapter
+--------------
+
+Before you can actually use the driver, you need to get yourself an
+adapter cable to connect the XBOX-controller to your Linux-Box.
+
+Such a cable is pretty easy to build. The Controller itself is a USB device
+(a hub with three ports; two expansion slots and the controller device)
+with the only differnce in a nonstandard connector (5 pins vs. 4 on
+standard USB connector).
+
+You just need to solder an USB connector onto the cable and keep the
+yellow wire unconnected. The other pins have the same order on both
+connectors so there no magic to it. Detailed info on these matters can be found
+on the net.
+
+Thanks to the trip splitter found on the cable you don't even need to cut the
+original cable, you can buy an extension cable and cut that instead. That way,
+you can still use the controller with your XBOX, if you have one ;)
+
+
+2. driver installation
+----------------------
+
+Once you have the adapter cable and the controller is connected, you need
+to load your USB subsystem and should cat /proc/bus/usb/devices.
+There should be an entry like the one in InterAct_german.dump.
+
+Don't worry if the vendor and/or product ID don't match, those are easy to
+add to the driver. You could do it yourself, just add the appropriate line
+into the list after the line
+    '} xpad_device[] = {'
+, but before the line that says
+    '{ 0x0000, 0x0000, "unknown...." }'.
+
+In theory, the driver should work with other controllers than mine
+(InterAct PowerPad pro, bought in Germany) just fine, but see for yourself.
+
+If you compiled and installed the driver, test the functionality:
+> modprobe usb-xpad
+> modprobe joydev
+> jstest /dev/input/js0
+
+There should be a single line showing 18 inputs (8 axes, 10 buttons), and
+it's values should change if you move the sticks and push the buttons.
+
+It works? Voila, your done ;)
+
+
+3. Thanks
+---------
+
+I have to thank ITO Takayuki for the detailed info on his site
+ http://euc.jp/periphs/xbox-controller.ja.html.
+ 
+His useful info and both the usb-skeleton as well as the iforce input driver
+helped a lot in rapid prototyping the basic functionality.
+
+
+-- 
+Marko Friedemann <mfr@bmx-chemnitz.de>
+2002-07-02
diff -Nru a/Documentation/usb/URB.txt b/Documentation/usb/URB.txt
--- a/Documentation/usb/URB.txt	Tue Jul 16 16:49:42 2002
+++ b/Documentation/usb/URB.txt	Tue Jul 16 16:49:42 2002
@@ -1,6 +1,13 @@
 Revised: 2000-Dec-05.
+Again:   2002-Jul-06
+
+    NOTE:
+
+    The USB subsystem now has a substantial section in "The Linux Kernel API"
+    guide (in linux/Documentation/DocBook), generated from the current source
+    code.  This particular documentation file isn't particularly current or
+    complete; don't rely on it except for a quick overview.
 
-1. Specification of the API
 
 1.1. Basic concept or 'What is an URB?'
 
@@ -8,124 +15,119 @@
 called USB Request Block, or URB for short. 
 
 - An URB consists of all relevant information to execute any USB transaction 
-and deliver the data and status back. 
+  and deliver the data and status back. 
 
 - Execution of an URB is inherently an asynchronous operation, i.e. the 
-usb_submit_urb(urb) call returns immediately after it has successfully queued 
-the requested action. 
+  usb_submit_urb(urb) call returns immediately after it has successfully queued 
+  the requested action. 
 
-- Ongoing transfers for one URB (e.g. ISO) can simply be canceled with
-usb_unlink_urb(urb) at any time. 
+- Transfers for one URB can be canceled with usb_unlink_urb(urb) at any time. 
 
 - Each URB has a completion handler, which is called after the action
-has been successfully completed or canceled (INT transfers behave a bit
-differently, see below). The URB also contains a context-pointer for free 
-usage and information passing to the completion handler.
-
-- URBs can be linked. After completing one URB, the next one can be
-automatically submitted. This is especially useful for ISO transfers:
-You only have read/write the data from/to the buffers in the completion 
-handler, the continuous streaming itself is transparently done by the 
-URB-machinery.
+  has been successfully completed or canceled. The URB also contains a
+  context-pointer for passing information to the completion handler.
 
+- Each endpoint for a device logically supports a queue of requests.
+  You can fill that queue, so that the USB hardware can still transfer
+  data to an endpoint while your driver handles completion of another.
+  This maximizes use of USB bandwidth, and supports seamless streaming
+  of data to (or from) devices when using periodic transfer modes.
 
-1.2. The URB structure
 
-typedef struct urb
-{
-	spinlock_t lock;		// lock for the URB
+1.2. The URB structure
 
-// ignore, for host controller/URB machine internal use
-	void *hcpriv;                   // private data for host controller
-	struct list_head urb_list;      // list pointer to all active urbs 
+Some of the fields in an URB are:
 
-// This is used for urb linking
-	struct urb* next;               // pointer to next URB  
+struct urb
+{
+// (IN) device and pipe specify the endpoint queue
 	struct usb_device *dev;         // pointer to associated USB device
+	unsigned int pipe;              // endpoint information
+
+	unsigned int transfer_flags;    // ISO_ASAP, SHORT_NOT_OK, etc.
 
-// pipe is assembled by the various well-known pipe macros in usb.h
-	unsigned int pipe;              // pipe information
+// (IN) all urbs need completion routines
+	void *context;                  // context for completion routine
+	void (*complete)(struct urb *); // pointer to completion routine
 
-// status after each completion
+// (OUT) status after each completion
 	int status;                     // returned status
-	unsigned int transfer_flags;    // ASAP, DISABLE_SPD, etc.
 
-// for data stage (CTRL), BULK, INT and ISO
+// (IN) buffer used for data transfers
 	void *transfer_buffer;          // associated data buffer
-
-// expected length
 	int transfer_buffer_length;     // data buffer length
-	int actual_length;              // actual data buffer length    
+	int number_of_packets;          // size of iso_frame_desc
 
-// setup stage for CTRL (always 8 bytes!)
+// (OUT) sometimes only part of CTRL/BULK/INTR transfer_buffer is used
+	int actual_length;              // actual data buffer length
+
+// (IN) setup stage for CTRL (pass a struct usb_ctrlrequest)
 	unsigned char* setup_packet;    // setup packet (control only)
 
-// with ASAP, start_frame is set to the determined frame
-	int start_frame;                // start frame (iso/irq)
-	int number_of_packets;          // # of packets (iso/int)
-	int interval;                   // polling interval (irq only)
-	int error_count;                // number of errors (iso only)
-	//
-	void *context;                  // context for completion routine
-	usb_complete_t complete;        // pointer to completion routine
-	//
-// specification of the requested data offsets and length for ISO
-	iso_packet_descriptor_t iso_frame_desc[0];
-} urb_t, *purb_t;
+// Only for PERIODIC transfers (ISO, INTERRUPT)
+    // (IN/OUT) start_frame is set unless ISO_ASAP isn't set
+	int start_frame;                // start frame
+	int interval;                   // polling interval
+
+    // ISO only: packets are only "best effort"; each can have errors
+	int error_count;                // number of errors
+	struct usb_iso_packet_descriptor iso_frame_desc[0];
+};
+
+Your driver must create the "pipe" value using values from the appropriate
+endpoint descriptor in an interface that it's claimed.
 
 
 1.3. How to get an URB?
 
 URBs are allocated with the following call
 
-	purb_t usb_alloc_urb(int isoframes)
+	struct urb *usb_alloc_urb(int isoframes, int mem_flags)
 
 Return value is a pointer to the allocated URB, 0 if allocation failed.
 The parameter isoframes specifies the number of isochronous transfer frames
-you want to schedule. For CTRL/BULK/INT, use 0.
+you want to schedule. For CTRL/BULK/INT, use 0.  The mem_flags paramter
+holds standard memory allocation flags, letting you control (among other
+things) whether the underlying code may block or not.
 
 To free an URB, use
 
-	void usb_free_urb(purb_t purb)
+	void usb_free_urb(struct urb *urb)
 
-This call also may free internal (host controller specific) memory in the
-future.
+You may not free an urb that you've submitted, but which hasn't yet been
+returned to you in a completion callback.
 
 
 1.4. What has to be filled in?
 
-Depending on the type of transaction, there are some macros 
-(FILL_CONTROL_URB, FILL_CONTROL_URB_TO, FILL_BULK_URB,
-FILL_BULK_URB_TO, and FILL_INT_URB, defined in usb.h)
-that simplify the URB creation. In general, all macros need the usb
+Depending on the type of transaction, there are some inline functions 
+defined in <linux/usb.h> to simplify the initialization, such as
+fill_control_urb() and fill_bulk_urb().  In general, they need the usb
 device pointer, the pipe (usual format from usb.h), the transfer buffer,
 the desired transfer length, the completion  handler, and its context. 
-Take a look at the usb_control_msg function that converts the old API 
-into the URB API.
+Take a look at the some existing drivers to see how they're used.
 
 Flags:
 For ISO there are two startup behaviors: Specified start_frame or ASAP.
 For ASAP set USB_ISO_ASAP in transfer_flags.
 
-If short packets should NOT be tolerated, set USB_DISABLE_SPD in 
+If short packets should NOT be tolerated, set URB_SHORT_NOT_OK in 
 transfer_flags.
 
-Usually, to reduce restart time, the completion handler is called
-AFTER the URB re-submission.  However, it is called BEFORE URB
-re-submission for INT transfers that are being continued.
-
 
 1.5. How to submit an URB?
 
 Just call
 
-	int usb_submit_urb(purb_t purb)
+	int usb_submit_urb(struct urb *urb, int mem_flags)
+
+The mem_flags parameter, such as SLAB_ATOMIC, controls memory allocation,
+such as whether the lower levels may block when memory is tight.
 
 It immediately returns, either with status 0 (request queued) or some
 error code, usually caused by the following:
 
 - Out of memory (-ENOMEM)
-- Wrong pipe handle (-ENXIO)
 - Unplugged device (-ENODEV)
 - Stalled endpoint (-EPIPE)
 - Too many queued ISO transfers (-EAGAIN)
@@ -133,13 +135,12 @@
 - Invalid INT interval (-EINVAL)
 - More than one packet for INT (-EINVAL)
 
-After submission, urb->status is USB_ST_URB_PENDING (-EINPROGRESS).
+After submission, urb->status is -EINPROGRESS; however, you should never
+look at that value except in your completion callback.
 
-For isochronous endpoints, subsequent submitting of URBs to the same endpoint
-with the ASAP flag result in a seamless ISO streaming. Exception: The 
-execution cannot be scheduled later than 900 frames from the 'now'-time. 
-The same applies to INT transfers, but here the seamless continuation is 
-independent of the transfer flags (implicitly ASAP).
+For isochronous endpoints, your completion handlers should (re)submit
+URBs to the same endpoint with the ISO_ASAP flag, using multi-buffering,
+to get seamless ISO streaming.
 
 
 1.6. How to cancel an already running URB?
@@ -147,12 +148,12 @@
 For an URB which you've submitted, but which hasn't been returned to
 your driver by the host controller, call
 
-	int usb_unlink_urb(purb_t purb)
+	int usb_unlink_urb(struct urb *urb)
 
 It removes the urb from the internal list and frees all allocated
-HW descriptors. The status is changed to USB_ST_URB_KILLED. After 
-usb_unlink_urb() returns, you can safely free the URB with usb_free_urb(urb)
-and all other possibly associated data (urb->context etc.)
+HW descriptors. The status is changed to reflect unlinking. After 
+usb_unlink_urb() returns with that status code, you can free the URB
+with usb_free_urb().
 
 There is also an asynchronous unlink mode.  To use this, set the
 the USB_ASYNC_UNLINK flag in urb->transfer flags before calling
@@ -163,10 +164,6 @@
 
 1.7. What about the completion handler?
 
-The completion handler is optional, but useful for fast data processing
-or wakeup of a sleeping process (as shown in the compatibility wrapper's 
-completion handler).
-
 The handler is of the following type:
 
 	typedef void (*usb_complete_t)(struct urb *);
@@ -176,10 +173,17 @@
 detect any USB errors. Since the context parameter is included in the URB,
 you can pass information to the completion handler. 
 
+Note that even when an error (or unlink) is reported, data may have been
+transferred.  That's because USB transfers are packetized; it might take
+sixteen packets to transfer your 1KByte buffer, and ten of them might
+have transferred succesfully before the completion is called.
+
+
 NOTE:  ***** WARNING *****
-AVOID using the urb->dev field in your completion handler; it's cleared
-as part of URB unlinking.  Instead, use urb->context to hold all the
-data your driver needs.
+Don't use urb->dev field in your completion handler; it's cleared
+as part of giving urbs back to drivers.  (Addressing an issue with
+ownership of periodic URBs, which was otherwise ambiguous.) Instead,
+use urb->context to hold all the data your driver needs.
 
 NOTE:  ***** WARNING *****
 Also, NEVER SLEEP IN A COMPLETION HANDLER.  These are normally called
@@ -191,38 +195,58 @@
 
 1.8. How to do isochronous (ISO) transfers?
 
-For ISO transfers you have to append the iso_packet_descriptor_t structure 
-to the URB for each frame you want to schedule. When using usb_alloc_urb(n)
-(recommended), the iso_packets parameter can be used to allocate the
-structures for iso_packets frames.
+For ISO transfers you have to fill a usb_iso_packet_descriptor structure,
+allocated at the end of the URB by usb_alloc_urb(n,mem_flags), for each
+packet you want to schedule.   You also have to set urb->interval to say
+how often to make transfers; it's often one per frame (which is once
+every microframe for highspeed devices).  The actual interval used will
+be a power of two that's no bigger than what you specify.
+
+The usb_submit_urb() call modifies urb->interval to the implemented interval
+value that is less than or equal to the requested interval value.  If
+ISO_ASAP scheduling is used, urb->start_frame is also updated.
 
 For each entry you have to specify the data offset for this frame (base is
 transfer_buffer), and the length you want to write/expect to read.
 After completion, actual_length contains the actual transferred length and 
-status contains the resulting USB-status for the ISO transfer for this frame.
+status contains the resulting status for the ISO transfer for this frame.
 It is allowed to specify a varying length from frame to frame (e.g. for
 audio synchronisation/adaptive transfer rates). You can also use the length 
 0 to omit one or more frames (striping).
 
-As can be concluded from above, the UHCI-driver does not care for continuous
-data in case of short packet ISO reads! There's no fixup_isoc() like in the 
-old driver. There may be a common routine to do this in the future, but this 
-has nothing to do with the UHCI-driver!
-
-For scheduling you can choose your own start frame or ASAP. As written above,
-queuing more than one ISO frame with ASAP to the same device&endpoint result 
-in seamless ISO streaming. For continuous streaming you have to use URB
-linking. 
+For scheduling you can choose your own start frame or ISO_ASAP. As explained
+earlier, if you always keep at least one URB queued and your completion
+keeps (re)submitting a later URB, you'll get smooth ISO streaming (if usb
+bandwidth utilization allows).
+
+If you specify your own start frame, make sure it's several frames in advance
+of the current frame.  You might want this model if you're synchronizing
+ISO data with some other event stream.
 
 
 1.9. How to start interrupt (INT) transfers?
 
-INT transfers are currently implemented with different queues for intervals 
-for 1, 2, 4,... 128ms. Only one URB is allocated for each interrupt. After
-calling the completion handler, that URB is recycled by the host controller
-driver (HCD).
-With the submission of one URB, the interrupt is scheduled until it is
-canceled by usb_unlink_urb.
+Interrupt transfers, like isochronous transfers, are periodic, and happen
+in intervals that are powers of two (1, 2, 4 etc) units.  Units are frames
+for full and low speed devices, and microframes for high speed ones.
+
+Currently, after you submit one interrupt URB, that urb is owned by the
+host controller driver until you cancel it with usb_unlink_urb().  You
+may unlink interrupt urbs in their completion handlers, if you need to.
+
+After a transfer completion is called, the URB is automagically resubmitted.
+THIS BEHAVIOR IS EXPECTED TO BE REMOVED!!
+
+Interrupt transfers may only send (or receive) the "maxpacket" value for
+the given interrupt endpoint; if you need more data, you will need to
+copy that data out of (or into) another buffer.  Similarly, you can't
+queue interrupt transfers.
+THESE RESTRICTIONS ARE EXPECTED TO BE REMOVED!!
+
+Note that this automagic resubmission model does make it awkward to use
+interrupt OUT transfers.  The portable solution involves unlinking those
+OUT urbs after the data is transferred, and perhaps submitting a final
+URB for a short packet.
 
 The usb_submit_urb() call modifies urb->interval to the implemented interval
 value that is less than or equal to the requested interval value.
diff -Nru a/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt
--- a/Documentation/usb/error-codes.txt	Tue Jul 16 16:49:41 2002
+++ b/Documentation/usb/error-codes.txt	Tue Jul 16 16:49:41 2002
@@ -22,9 +22,8 @@
 
 -ENODEV		specified USB-device or bus doesn't exist
 
--ENXIO		a control or interrupt URB is already queued to this endpoint;
-		or (UHCI only) a bulk URB is already queued to this endpoint
-		and USB_QUEUE_BULK wasn't used
+-ENXIO		host controller driver does not support queuing of this type
+		of urb.  (treat as a host controller bug.)
 
 -EINVAL		a) Invalid transfer type specified (or not supported)
 		b) Invalid interrupt interval (0<=n<256)
@@ -90,9 +89,9 @@
 			greater than either the max packet size of the
 			endpoint or the remaining buffer size.  "Babble".
 
--EREMOTEIO		The endpoint returned less than max packet size
-			and that amount did not fill the specified buffer
-			(and USB_DISBLE_SPD was not set in transfer_flags)
+-EREMOTEIO		The data read from the endpoint did not fill the
+			specified buffer, and URB_SHORT_NOT_OK was set in
+			urb->transfer_flags.
 
 -ETIMEDOUT		transfer timed out, NAK
 
diff -Nru a/Documentation/usb/hiddev.txt b/Documentation/usb/hiddev.txt
--- a/Documentation/usb/hiddev.txt	Tue Jul 16 16:49:42 2002
+++ b/Documentation/usb/hiddev.txt	Tue Jul 16 16:49:42 2002
@@ -18,7 +18,7 @@
 The data flow for a HID event produced by a device is something like
 the following :
 
- usb.c ---> hid-core.c  ----> input.c ----> [keyboard/mouse/joystick/event]
+ usb.c ---> hid-core.c  ----> hid-input.c ----> [keyboard/mouse/joystick/event]
                          |
                          |
                           --> hiddev.c ----> POWER / MONITOR CONTROL 
@@ -106,6 +106,15 @@
 collections the device has from the num_applications field from the
 hiddev_devinfo structure. 
 
+HIDIOCGCOLLECTIONINFO - struct hiddev_collection_info (read/write)
+This returns a superset of the information above, providing not only
+application collections, but all the collections the device has.  It
+also returns the level the collection lives in the hierarchy.
+The user passes in a hiddev_collection_info struct with the index 
+field set to the index that should be returned.  The ioctl fills in 
+the other fields.  If the index is larger than the last collection 
+index, the ioctl returns -1 and sets errno to -EINVAL.
+
 HIDIOCGDEVINFO - struct hiddev_devinfo (read)
 Gets a hiddev_devinfo structure which describes the device.
 
@@ -171,6 +180,10 @@
 Sets the value of a usage in an output report.  The user fills in
 the hiddev_usage_ref structure as above, but additionally fills in
 the value field.
+
+HIDIOGCOLLECTIONINDEX - struct hiddev_usage_ref (write)
+Returns the collection index associated with this usage.  This
+indicates where in the collection hierarchy this usage sits.
 
 HIDIOCGFLAG - int (read)
 HIDIOCSFLAG - int (write)
diff -Nru a/Documentation/video4linux/bttv/CARDLIST b/Documentation/video4linux/bttv/CARDLIST
--- a/Documentation/video4linux/bttv/CARDLIST	Tue Jul 16 16:49:41 2002
+++ b/Documentation/video4linux/bttv/CARDLIST	Tue Jul 16 16:49:41 2002
@@ -3,41 +3,41 @@
   card=1 - MIRO PCTV
   card=2 - Hauppauge (bt848)
   card=3 - STB
-  card=4 - Intel
+  card=4 - Intel Create and Share PCI/ Smart Video Recorder III
   card=5 - Diamond DTV2000
   card=6 - AVerMedia TVPhone
   card=7 - MATRIX-Vision MV-Delta
-  card=8 - FlyVideo II (Bt848) LR26
+  card=8 - Lifeview FlyVideo II (Bt848) LR26
   card=9 - IXMicro TurboTV
   card=10 - Hauppauge (bt878)
   card=11 - MIRO PCTV pro
-  card=12 - ADS Technologies Channel Surfer TV
+  card=12 - ADS Technologies Channel Surfer TV (bt848)
   card=13 - AVerMedia TVCapture 98
   card=14 - Aimslab Video Highway Xtreme (VHX)
   card=15 - Zoltrix TV-Max
-  card=16 - Pixelview PlayTV (bt878)
+  card=16 - Prolink Pixelview PlayTV (bt878)
   card=17 - Leadtek WinView 601
   card=18 - AVEC Intercapture
-  card=19 - LifeView FlyKit w/o Tuner
+  card=19 - Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)
   card=20 - CEI Raffles Card
-  card=21 - Lucky Star Image World ConferenceTV
-  card=22 - Phoebe Tv Master + FM (CPH050)
+  card=21 - Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50
+  card=22 - Askey CPH050/ Phoebe Tv Master + FM
   card=23 - Modular Technology MM205 PCTV, bt878
-  card=24 - [many vendors] CPH05X/06X (bt878)
-  card=25 - Terratec/Vobis TV-Boostar
-  card=26 - Newer Hauppauge WinCam (bt878)
-  card=27 - MAXI TV Video PCI2
+  card=24 - Askey CPH05X/06X (bt878) [many vendors]
+  card=25 - Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar
+  card=26 - Hauppauge WinCam newer (bt878)
+  card=27 - Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50
   card=28 - Terratec TerraTV+
   card=29 - Imagenation PXC200
-  card=30 - FlyVideo 98
-  card=31 - iProTV
-  card=32 - Intel Create and Share PCI
+  card=30 - Lifeview FlyVideo 98 LR50
+  card=31 - Formac iProTV
+  card=32 - Intel Create and Share PCI/ Smart Video Recorder III
   card=33 - Terratec TerraTValue
   card=34 - Leadtek WinFast 2000
-  card=35 - Flyvideo 98 (LR50Q) / Chronos Video Shuttle II
-  card=36 - Flyvideo 98FM (LR50Q) / Typhoon TView TV/FM Tuner
-  card=37 - PixelView PlayTV pro
-  card=38 - TView99 CPH06X
+  card=35 - Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II
+  card=36 - Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner
+  card=37 - Prolink PixelView PlayTV pro
+  card=38 - Askey CPH06X TView99
   card=39 - Pinnacle PCTV Studio/Rave
   card=40 - STB2
   card=41 - AVerMedia TVPhone 98
@@ -47,37 +47,37 @@
   card=45 - MATRIX-Vision MV-Delta 2
   card=46 - Zoltrix Genie TV/FM
   card=47 - Terratec TV/Radio+
-  card=48 - Dynalink Magic TView 
-  card=49 - GV-BCTV3
+  card=48 - Askey CPH03x/ Dynalink Magic TView
+  card=49 - IODATA GV-BCTV3/PCI
   card=50 - Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP
   card=51 - Eagle Wireless Capricorn2 (bt878A)
   card=52 - Pinnacle PCTV Studio Pro
   card=53 - Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS
-  card=54 - Lifetec LT 9415 TV (LR90 Rev.F)
-  card=55 - BESTBUY Easy TV (CPH031)
-  card=56 - FlyVideo '98/FM
+  card=54 - Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]
+  card=55 - Askey CPH031/ BESTBUY Easy TV
+  card=56 - Lifeview FlyVideo 98FM LR50
   card=57 - GrandTec 'Grand Video Capture' (Bt848)
-  card=58 - Phoebe TV Master Only (No FM) CPH060
-  card=59 - TV Capturer (CPH03X)
+  card=58 - Askey CPH060/ Phoebe TV Master Only (No FM)
+  card=59 - Askey CPH03x TV Capturer
   card=60 - Modular Technology MM100PCTV
   card=61 - AG Electronics GMV1
-  card=62 - BESTBUY Easy TV (bt878)
+  card=62 - Askey CPH061/ BESTBUY Easy TV (bt878)
   card=63 - ATI TV-Wonder
   card=64 - ATI TV-Wonder VE
-  card=65 - FlyVideo 2000S
+  card=65 - Lifeview FlyVideo 2000S LR90
   card=66 - Terratec TValueRadio
-  card=67 - GV-BCTV4/PCI
+  card=67 - IODATA GV-BCTV4/PCI
   card=68 - 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)
   card=69 - Active Imaging AIMMS
-  card=70 - PV-BT878P+
-  card=71 - Flyvideo 98EZ (capture only)
-  card=72 - Prolink PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)
+  card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C)
+  card=71 - Lifeview FlyVideo 98EZ (capture only) LR51
+  card=72 - Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)
   card=73 - Sensoray 311
   card=74 - RemoteVision MX (RV605)
   card=75 - Powercolor MTV878/ MTV878R/ MTV878F
   card=76 - Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)
   card=77 - GrandTec Multi Capture Card (Bt878)
-  card=78 - AOPEN VA1000
+  card=78 - Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF
 
 tuner.o
   type=0 - Temic PAL (4002 FH5)
diff -Nru a/Documentation/video4linux/bttv/Cards b/Documentation/video4linux/bttv/Cards
--- a/Documentation/video4linux/bttv/Cards	Tue Jul 16 16:49:41 2002
+++ b/Documentation/video4linux/bttv/Cards	Tue Jul 16 16:49:41 2002
@@ -1,3 +1,8 @@
+
+Gunther Mayer's bttv card gallery (graphical version of this text file :-)
+is available at: http://mayerg.gmxhome.de/bttv/bttv-gallery.html
+
+
 Suppported cards:
 
 
@@ -91,10 +96,9 @@
 - sound decoder: TDA9800, MSP34xx (stereo cards) 
 
 
-CPH-Series (CPH050, ...)
-------------------------
-Developed by TelSignal(?), OEMed by many vendors (Askey, Typhoon, 
-  Anubis, Dynalink)
+Askey CPH-Series
+----------------
+Developed by TelSignal(?), OEMed by many vendors (Typhoon, Anubis, Dynalink)
 
   Card series:
     CPH01x: BT848 capture only
@@ -149,9 +153,12 @@
       LR50 Rev.Q = Flyvideo 98 (w/eeprom and PCI subsystem ID)
            Rev.W = Flyvideo 98 (no eeprom)
       LR51 Rev.E = Flyvideo 98 EZ (capture only)
-      LR90       = Flyvideo 2000 series
+      LR90       = Flyvideo 2000 (Bt878)
+		   Flyvideo 2000S (Bt878) w/Stereo TV (Package incl. LR91 daughterboard)
       LR91       = Stereo daughter card for LR90
       LR97       = Flyvideo DVBS
+      LR136	 = Flyvideo 2100/3100 (Low profile, SAA7130/SAA7134)
+      LR137      = Flyvideo DV2000/DV3000 (SAA7130/SAA7134 + IEEE1394)
       LR138 Rev.C= Flyvideo 2000 (SAA7130)
 	        or Flyvideo 3000 (SAA7134) w/Stereo TV
 		   These exist in variations w/FM and w/Remote sometimes denoted
@@ -162,15 +169,14 @@
       Their Bt8x8 cards are listed as discontinued.
       Flyvideo 2000S was probably sold as Flyvideo 3000 in some contries(Europe?).
       The new Flyvideo 2000/3000 are SAA7130/SAA7134 based. 
-      Flyvideo 2100/3100 are half-sized cards (for system integrators etc.)
 
   "Flyvideo II" had been the name for the 848 cards, nowadays (in Germany)
   this name is re-used for LR50 Rev.W.
   The Lifeview website mentioned Flyvideo III at some time, but such a card
-  has never been seen. 
+  has not yet been seen (perhaps it was the german name for LR90 [stereo]).
   These cards are sold by many OEMs too.
 
-  FlyVideo A2 = LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821)
+  FlyVideo A2 = LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821) {Germany}
 
 
 Typhoon TV card series:
@@ -190,7 +196,12 @@
   50686 "TV Tuner"                       = KNC1 TV Station
   50687 "TV Tuner stereo"                = KNC1 TV Station pro
   50688 "TV Tuner RDS" (black package)   = KNC1 TV Station RDS
+  50689  TV SAT DVB-S CARD CI PCI (SAA7146AH)
   50692 "TV/FM Tuner" (small PCB)
+  50694  TV TUNER CARD RDS (PHILIPS CHIPSET SAA7134HL)
+  50696  TV TUNER STEREO (PHILIPS CHIPSET SAA7134HL, MK3ME Tuner)
+  50804  PC-SAT TV/Audio Karte = Techni-PC-Sat (ZORAN 36120PQC, Tuner:Alps)
+  50866  TVIEW SAT RECEIVER+ADR
   50868 "TV/FM Tuner Pal I" (variant of 50682)
   50999 "TV/FM Tuner Secam" (variant of 50682)
 
@@ -207,16 +218,30 @@
 
 Prolink
 -------
-   Pixelview Play TV Pro:
-     PV-BT878P+rev.9B (Play TV Pro w/FM w/NICAM)
-     PV-BT878P+rev.8X 
-     PV-BT878P+rev.4C (Play TV Pro) 
-     PV-BT878P+rev.4E (Play TV Pak) 
-     PV-BT878P+rev.2F 
-     PV-BT878TV 
-
-   PixelView Play TV 
-     PV-BT848P+
+   TV cards:
+   PixelView Play TV pro - (Model: PV-BT878P+ REV 8E)
+   PixelView Play TV pro - (Model: PV-BT878P+ REV 9D)
+   PixelView Play TV pro - (Model: PV-BT878P+ REV 4C / 8D / 10A )
+   PixelView Play TV - (Model: PV-BT848P+)
+   878TV - (Model: PV-BT878TV)
+
+   Multimedia TV packages (card + software pack):
+   PixelView Play TV Theater - (Model: PV-M4200) =  PixelView Play TV pro + Software
+   PixelView Play TV PAK -     (Model: PV-BT878P+ REV 4E)
+   PixelView Play TV/VCR -     (Model: PV-M3200 REV 4C / 8D / 10A ) 
+   PixelView Studio PAK -      (Model:    M2200 REV 4C / 8D / 10A )
+   PixelView PowerStudio PAK - (Model: PV-M3600 REV 4E)
+   PixelView DigitalVCR PAK -  (Model: PV-M2400 REV 4C / 8D / 10A )
+
+   Further Cards:
+   PV-BT878P+rev.9B (Play TV Pro, opt. w/FM w/NICAM)
+   PV-BT878P+rev.2F
+   
+   Video Conferencing:
+   PixelView Meeting PAK - (Model: PV-BT878P)
+   PixelView Meeting PAK Lite - (Model: PV-BT878P)
+   PixelView Meeting PAK plus - (Model: PV-BT878P+rev 4C/8D/10A)
+   PixelView Capture - (Model: PV-BT848P)
 
 Dynalink
 --------
@@ -235,7 +260,7 @@
 Tekram
 ------
    VideoCap C205 (Bt848)
-   VideoCap C210 (Zoran ZR36120 +Philips)
+   VideoCap C210 (zr36120 +Philips)
    CaptureTV M200 (ISA)
    CaptureTV M205 (Bt848)
 
@@ -257,8 +282,8 @@
    TV-Station FM (+Radio)
    TV-Station RDS (+RDS)
 
-PV951 cards:
-------------
+Provideo PV951 
+--------------
   These are sold as:
    Boeder TV-FM Video Capture Card
    Titanmedia Supervision TV-2400
@@ -270,12 +295,14 @@
 Highscreen
 ----------
    TV Karte = LR50 Rev.S
-   TV-Boostar = Terratec Terra TV+ Version 1.0 (Bt848, TDA9821) "ceb105.pcb"
+   TV-Boostar = Terratec Terra TV+ Version 1.0 (Bt848, tda9821) "ceb105.pcb"
 
 Zoltrix
 -------
+   Face to Face Capture (Bt848 capture only) (PCB "VP-2848")
    Face To Face TV MAX (Bt848) (PCB "VP-8482 Rev1.3")
    Genie TV (Bt878) (PCB "VP-8790 Rev 2.1")
+   Genie Wonder Pro
 
 AVerMedia
 ---------
@@ -304,19 +331,21 @@
 -------
    Video Highway Xtreme (aka "VHX") (Bt848, FM w/ TEA5757)
 
-IXMicro
+IXMicro (former: IMS=Integrated Micro Solutions)
 -------
    IXTV BT848
    IXTV BT878
    TurboTV (Bt848)
 
 Lifetec/Medion/Tevion/Aldi
--------
-   LT9415/MD9415 = LR90 Rev. F
+--------------------------
+   LT9306/MD9306 = CPH061
+   LT9415/MD9415 = LR90 Rev.F or Rev.G
           MD9592 = Avermedia TVphone98 (PCI_ID=1461:0003), PCB-Rev=M168II-B (w/TDA9873H)
+          MD9717 = KNC One (Rev D4, saa7134)
 
 Modular Technologies (www.modulartech.com) UK
---------------------
+---------------------------------------------
    MM100 PCTV (Bt848)
    MM205 PCTV (Bt878)
    MM210 PCTV (Bt878) (Galaxy TV)
@@ -326,19 +355,26 @@
    Terra TV+ Version 1.0 (Bt848), "ceb105.PCB" printed on the PCB, TDA9821
    Terra TV+ Version 1.1 (Bt878), "LR74 Rev.E" printed on the PCB, TDA9821
    Terra TValueRadio,             "LR102 Rev.C" printed on the PCB
-   Terra TV/Radio+ Version 1.0,   "80-CP2830100-0" TTTV3 printed on the PCB, i
+   Terra TV/Radio+ Version 1.0,   "80-CP2830100-0" TTTV3 printed on the PCB,
 				     "CPH010-E83" on the back, SAA6588T, TDA9873H
    Terra TValue Version BT878,    "80-CP2830110-0 TTTV4" printed on the PCB, 
 				     "CPH011-D83" on back
    Terra TValue Version 1.0       "ceb105.PCB" (really identical to Terra TV+ Version 1.0)
+   Terra Active Radio Upgrade (tea5757h, saa6588t)
 
    LR74 is a newer PCB revision of ceb105 (both incl. connector for Active Radio Upgrade)
 
-
 Technisat
 ---------
-   Mediafocus I (ZR36120/ZR36125)
-   Mediafocus II (SAA7146)
+   Discos ADR PC-Karte ISA (no TV!)
+   Discos ADR PC-Karte PCI (probably no TV?)
+   Techni-PC-Sat (Sat. analog)
+         Rev 1.2 (zr36120, vpx3220, stv0030, saa5246, BSJE3-494A)
+   Mediafocus I (zr36120/zr36125, drp3510, Sat. analog + ADR Radio)
+   Mediafocus II (saa7146, Sat. analog)
+         SatADR Rev 2.1 (saa7146a, saa7113h, stv0056a, msp3400c, drp3510a, BSKE3-307A)
+   SkyStar 1 DVB  (AV7110)
+   SkyStar 2 DVB  (B2C2) (=Sky2PC)
 
 Siemens
 -------
@@ -359,34 +395,252 @@
    Mirovideo PCTV (Bt848)
    Mirovideo PCTV SE (Bt848)
    Mirovideo PCTV Pro (Bt848 + Daughterboard)
-   Studio PCTV Rave (Bt878 w/o infrared)
-   Studio PCTV
-   Studio PCTV Pro (Bt878 stereo w/ FM)
+   Studio PCTV Rave (Bt878 package w/o infrared)
+   Studio PCTV      (Bt878)
+   Studio PCTV Pro  (Bt878 stereo w/ FM)
 
+   M(J)PEG capture and playback:
    DC1+ (ISA)
-   DC10  (zr36057 + zr36060 + saa7110 + adv7176)
-   DC10+ (zr36067 + zr36060 + saa7110 + adv7176)
-   DC20
-   DC30
-   DC30+ (zr36067 + zr36050 + zr36016 + vpx3220 + adv7176)
+   DC10  (zr36057,     zr36060,      saa7110, adv7176)
+   DC10+ (zr36067,     zr36060,      saa7110, adv7176)
+   DC20  (ql16x24b,zr36050, zr36016, saa7110, saa7187 ...)
+   DC30  (zr36057, zr36050, zr36016, vpx3220, adv7176, ad1843, tea6415, miro FST97A1)
+   DC30+ (zr36067, zr36050, zr36016, vpx3220, adv7176)
+   DC50  (zr36067, zr36050, zr36016, saa7112, adv7176 (2 pcs.?), ad1843, miro FST97A1, Lattice ???)
 
 Lenco
 -----
    MXR-9565 (=Technisat Mediafocus?)
-   MXR-9571 (Bt848)
+   MXR-9571 (Bt848) (=CPH031?)
    MXR-9575
-   MXR-9477 (Bt878)
-   MXTV-9578CP (= Prolink PV-BT878P+4E)
+   MXR-9577 (Bt878) (=Prolink 878TV Rev.3x)
+   MXTV-9578CP (Bt878) (= Prolink PV-BT878P+4E)
 
 Iomega
 ------
-   Buz (Zoran zr36067 + zr36060 + SAA7111 + SAA7185)
+   Buz (zr36067, zr36060, saa7111, saa7185)
 
 LML
 ---
-   LML33 (zr36067 + zr36060 + bt819+ bt856)
+   LML33 (zr36067, zr36060, bt819, bt856)
 
 Grandtec
 --------
    Grand Video Capture (Bt848)
    Multi Capture Card  (Bt878)
+
+Koutech
+-------
+   KW-606 (Bt848)
+   KW-607 (Bt848 capture only)
+   KW-606RSF
+   KW-607A (capture only)
+   KW-608 (Zoran capture only)
+ 
+IODATA (jp)
+------
+   GV-BCTV/PCI
+   GV-BCTV2/PCI
+   GV-BCTV3/PCI
+   GV-BCTV4/PCI
+   GV-VCP/PCI (capture only)
+   GV-VCP2/PCI (capture only)
+
+Canopus (jp)
+-------
+   WinDVR	= Kworld "KW-TVL878RF"
+
+www.sigmacom.co.kr 
+------------------
+   Sigma Cyber TV II 
+
+www.sasem.co.kr
+---------------
+   Litte OnAir TV
+
+hama 
+----
+   TV/Radio-Tuner Card, PCI (Model 44677) = CPH051
+
+Sigma Designs
+-------------
+   Hollywood plus (em8300, em9010, adv7175), (PCB "M340-10") MPEG DVD decoder
+
+Formac
+------
+   iProTV (Card for iMac Mezzanine slot, Bt848+SCSI)
+   ProTV (Bt848)
+   ProTV II = ProTV Stereo (Bt878)
+
+ATI
+---
+   TV-Wonder
+   TV-Wonder VE
+
+Diamond Multimedia
+------------------
+   DTV2000 (Bt848, tda9875)
+
+Aopen
+-----
+   VA1000 Plus (w/ Stereo)
+   VA1000 Lite
+   VA1000 (=LR90)
+
+Intel
+-----
+   Smart Video Recorder (ISA full-length)
+   Smart Video Recorder pro (ISA half-length)
+   Smart Video Recorder III (Bt848)
+
+STB
+---
+   TV PCI (Temic4032FY5, tda9850??)
+   other variants?
+
+Videologic
+----------
+   Captivator Pro/TV (ISA?)
+   Captivator PCI/VC (Bt848 bundled with camera) (capture only)
+
+Technotrend
+------------
+   TT-SAT PCI (PCB "Sat-PCI Rev.:1.3.1"; zr36125, vpx3225d, stc0056a, Tuner:BSKE6-155A
+   TT-DVB-Sat
+   TT-DVB-C PCI
+
+Teles
+-----
+   DVB-s (Rev. 2.2, BSRV2-301A, data only?)
+
+Remote Vision
+-------------
+   MX RV605 (Bt848 capture only)
+
+Boeder
+------
+   PC ChatCam (Model 68252) (Bt848 capture only)
+   Tv/Fm Capture Card  (Model 68404) = PV951
+
+Media-Surfer  (esc-kathrein.de)
+-------------------------------
+   Sat-Surfer (ISA)
+   Sat-Surfer PCI = Techni-PC-Sat
+   Cable-Surfer 1
+   Cable-Surfer 2
+   Cable-Surfer PCI (zr36120)
+   Audio-Surfer (ISA Radio card)
+
+Jetway (www.jetway.com.tw)
+--------------------------
+   JW-TV 878M 
+   JW-TV 878  = KWorld KW-TV878RF
+
+Galaxis
+-------
+   Galaxis DVB Card S CI
+   Galaxis DVB Card C CI
+   Galaxis DVB Card S
+   Galaxis DVB Card C
+
+Hauppauge
+---------
+   many many WinTV models ...
+   WinTV DVBs
+   WinTV NOVA
+   WinTV NOVA-CI
+   WinTV-Nexus-s
+
+Matrix-Vision
+-------------
+   MATRIX-Vision MV-Delta
+   MATRIX-Vision MV-Delta 2
+   MVsigma-SLC (Bt848)
+
+Conceptronic (.net)
+------------
+   TVCON FM,  TV card w/ FM = CPH05x
+
+BestData
+--------
+   HCC100 = VCC100rev1 + camera
+   VCC100 rev1 (bt848)
+   VCC100 rev2 (bt878)
+
+Gallant  (www.gallantcom.com) www.minton.com.tw
+-----------------------------------------------
+   Intervision IV-510 (capture only bt8x8)
+   Intervision IV-550 (bt8x8)
+   Intervision IV-100 (zoran)
+   Intervision IV-1000 (bt8x8)
+   
+Asonic (www.asonic.com.cn) (website down)
+-----------------------------------------
+   SkyEye tv 878
+
+Hoontech
+--------
+   878TV/FM
+
+Teppro (www.itcteppro.com.tw)
+-----------------------------
+   ITC PCITV (Card Ver 1.0) "Teppro TV1/TVFM1 Card"
+   ITC PCITV (Card Ver 2.0)
+   ITC PCITV (Card Ver 3.0) = "PV-BT878P+ (REV.9D)"
+   ITC PCITV (Card Ver 4.0)
+   TEPPRO IV-550 (For BT848 Main Chip)
+   ITC DSTTV (bt878, satellite)
+   ITC VideoMaker (saa7146, StreamMachine sm2110, tvtuner) "PV-SM2210P+ (REV:1C)"
+
+Kworld (www.kworld.com.tw)
+--------------------------
+   KWORLD KW-TV878RF-Pro TV Capture with FM Radio
+   KWORLD KW-TV878R-Pro TV
+   KWORLD KW-TVL878RF  (low profile)
+   KWORLD KW-TV878R TV Capture (No FM Radio)
+   KWORLD KW-TV878RF TV
+
+JTT/ Justy Corp.http://www.justy.co.jp/ (www.jtt.com.jp website down)
+---------------------------------------------------------------------
+   JTT-02 (JTT TV) "TV watchmate pro" (bt848) 
+
+ADS www.adstech.com
+-------------------
+   Channel Surfer TV ( CHX-950 ) 
+   Channel Surfer TV+FM ( CHX-960FM )
+
+AVEC www.prochips.com
+---------------------
+   AVEC Intercapture (bt848, tea6320)
+
+NoBrand
+-------
+   TV Excel = Australian Name for "PV-BT878P+ 8E" or so
+
+Mach www.machspeed.com
+----
+   Mach TV 878
+
+Eline www.eline-net.com/
+-----
+   Eline Vision TVMaster / TVMaster FM (ELV-TVM/ ELV-TVM-FM) = LR26  (bt878)
+   Eline Vision TVMaster-2000 (ELV-TVM-2000, ELV-TVM-2000-FM)= LR138 (saa713x)
+
+Spirit http://www.spiritmodems.com.au/
+------
+   Spirit TV Tuner/Video Capture Card (bt848)
+
+Boser www.boser.com.tw
+-----
+   HS-878 Mini PCI Capture Add-on Card
+   HS-879 Mini PCI 3D Audio and Capture Add-on Card (w/ ES1938 Solo-1)
+
+Satelco
+-------
+   TV-FM =KNC1 saa7134
+
+Sensoray www.sensoray.com
+--------
+   Sensoray 311 (PC/104 bus)
+   Sensoray 611 (PCI)
+
diff -Nru a/Documentation/video4linux/bttv/Insmod-options b/Documentation/video4linux/bttv/Insmod-options
--- a/Documentation/video4linux/bttv/Insmod-options	Tue Jul 16 16:49:41 2002
+++ b/Documentation/video4linux/bttv/Insmod-options	Tue Jul 16 16:49:41 2002
@@ -29,7 +29,7 @@
 		irq_debug=0/1	irq handler debug messages.
 				default is 0 (off).
 		gbuffers=2-32	number of capture buffers for mmap'ed capture.
-				default is 2.
+				default is 4.
 		gbufsize=	size of capture buffers. default and
 				maximum value is 0x208000 (~2MB)
 		no_overlay=0	Enable overlay on broken hardware.  There
diff -Nru a/Documentation/video4linux/bttv/README b/Documentation/video4linux/bttv/README
--- a/Documentation/video4linux/bttv/README	Tue Jul 16 16:49:41 2002
+++ b/Documentation/video4linux/bttv/README	Tue Jul 16 16:49:41 2002
@@ -58,6 +58,9 @@
 		the helper modules.
 MAKEDEV:	a script to create the special files for v4l
 CARDLIST:	List of all supported cards
+Cards:		more detailed descriptions of known TV cards:
+		OEM name variants, used i2c chips, ...
+		also includes non-bttv cards.
 
 Loading just the bttv modules isn't enouth for most cards.  The
 drivers for the i2c tuner/sound chips must also be loaded.  bttv tries
diff -Nru a/Documentation/video4linux/bttv/README.freeze b/Documentation/video4linux/bttv/README.freeze
--- a/Documentation/video4linux/bttv/README.freeze	Tue Jul 16 16:49:41 2002
+++ b/Documentation/video4linux/bttv/README.freeze	Tue Jul 16 16:49:41 2002
@@ -46,6 +46,11 @@
 the PCI bus. The bt848/878 chips have a few workarounds for known
 incompatibilities, see README.quirks.
 
+Some folks report that increasing the pci latency helps too,
+althrought I'm not sure whenever this really fixes the problems or
+only makes it less likely to happen.  Both bttv and btaudio have a
+insmod option to set the PCI latency of the device.
+
 Some mainboard have problems to deal correctly with multiple devices
 doing DMA at the same time.  bttv + ide seems to cause this sometimes,
 if this is the case you likely see freezes only with video and hard disk
@@ -63,3 +68,4 @@
 VGA cards seems to cause trouble sometimes.  I've also seen funny
 effects with bttv sharing the IRQ with the ACPI bridge (and
 apci-enabled kernel).
+
diff -Nru a/Documentation/video4linux/bttv/Tuners b/Documentation/video4linux/bttv/Tuners
--- a/Documentation/video4linux/bttv/Tuners	Tue Jul 16 16:49:41 2002
+++ b/Documentation/video4linux/bttv/Tuners	Tue Jul 16 16:49:41 2002
@@ -10,6 +10,7 @@
    M= BG+I+DK
    N= NTSC 
    Q= BG+I+DK+LL
+ [89]: ?
  [125]:
    2: No FM
    5: With FM
@@ -24,22 +25,23 @@
    3-wire/I2C tuning, 2-band/3-band
 
 Philips Tuner identification: (e.g. FM1216MF)
-  F[IRMQ]12[1345]{MF|ME|MP}
-  [IRMQ]:
-   I: Tuner Series
-   R: Tuner + Radio IF
-   M: Tuner + FM
-   Q,MR: specials
+  F[IRMQ]12[1345]6{MF|ME|MP}
+  F[IRMQ]:
+   FI12x6: Tuner Series
+   FR12x6: Tuner + Radio IF
+   FM12x6: Tuner + FM
+   FQ12x6: special
+   FMR12x6: special
    TD15xx: Digital Tuner ATSC
-  [1345]
-   1: PAL BG
-   3: NTSC
-   4: PAL I
-   5: Pal DK
+  12[1345]6:
+   1216: PAL BG
+   1236: NTSC
+   1246: PAL I
+   1256: Pal DK
   {MF|ME|MP}
    MF: w/ Secam
-   ME: BD DK I LL
-   MP: BG DK I
+   ME: BG DK I LL   (Multi Europe)
+   MP: BG DK I      (Multi PAL)
    MR: BG DK M (?)
    MG: BG DKI M (?)
 
@@ -50,10 +52,10 @@
     41xx: Tuner compact
     40x9: Tuner+FM compact
    [0136]
-    0: PAL BG
-    1: Pal DK, Secam LL
-    3: NTSC
-    6: PAL I
+    xx0x: PAL BG
+    xx1x: Pal DK, Secam LL
+    xx3x: NTSC
+    xx6x: PAL I
    F[HYNR]5
     FH5: Pal BG
     FY5: others
@@ -86,3 +88,8 @@
     P= Standard phono female socket
     D= IEC female socket
     F= F-connector
+
+Other Tuners:
+TCL2002MB-1 : PAL BG + DK       =TUNER_LG_PAL_NEW_TAPC
+TCL2002MB-1F: PAL BG + DK w/FM  =PHILIPS_PAL
+TCL2002MI-2 : PAL I		= ??
diff -Nru a/Documentation/video4linux/meye.txt b/Documentation/video4linux/meye.txt
--- a/Documentation/video4linux/meye.txt	Tue Jul 16 16:49:41 2002
+++ b/Documentation/video4linux/meye.txt	Tue Jul 16 16:49:41 2002
@@ -86,7 +86,7 @@
 
 	MEYEIOC_SYNC
 		Takes as an argument the buffer number you want to sync.
-		This ioctl blocks untils the buffer is filled and ready
+		This ioctl blocks until the buffer is filled and ready
 		for the application to use. It returns the buffer size.
 
 	MEYEIOC_STILLCAPT
@@ -106,7 +106,7 @@
 		
 	- mjpeg hardware playback doesn't work (depends on overlay...)
 
-	- rewrite the driver to use some commun video4linux API for snapshot
+	- rewrite the driver to use some common video4linux API for snapshot
 	  and mjpeg capture. Unfortunately, video4linux1 does not permit it,
 	  the BUZ API seems to be targeted to TV cards only. The video4linux 2
 	  API may be an option, if it goes into the kernel (maybe 2.5 
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Tue Jul 16 16:49:43 2002
+++ b/MAINTAINERS	Tue Jul 16 16:49:43 2002
@@ -1590,6 +1590,12 @@
 W:	http://www.linuxtr.net
 S:	Maintained
 
+TOSHIBA ACPI EXTRAS DRIVER
+P:	John Belmonte
+M:	toshiba_acpi@memebeam.org
+W:	http://memebeam.org/toys/ToshibaAcpiDriver
+S:	Maintained
+
 TOSHIBA SMM DRIVER
 P:	Jonathan Buzzard
 M:	jonathan@buzzard.org.uk
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Tue Jul 16 16:49:41 2002
+++ b/Makefile	Tue Jul 16 16:49:41 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 25
+SUBLEVEL = 26
 EXTRAVERSION =
 
 # *DOCUMENTATION*
diff -Nru a/arch/alpha/config.in b/arch/alpha/config.in
--- a/arch/alpha/config.in	Tue Jul 16 16:49:41 2002
+++ b/arch/alpha/config.in	Tue Jul 16 16:49:41 2002
@@ -235,9 +235,9 @@
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   bool 'Discontiguous Memory Support' CONFIG_DISCONTIGMEM
+   bool 'Discontiguous Memory Support (EXPERIMENTAL)' CONFIG_DISCONTIGMEM
    if [ "$CONFIG_DISCONTIGMEM" = "y" ]; then
-      bool ' NUMA Support' CONFIG_NUMA
+      bool ' NUMA Support (EXPERIMENTAL)' CONFIG_NUMA
    fi
 fi
 
diff -Nru a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
--- a/arch/alpha/kernel/signal.c	Tue Jul 16 16:49:42 2002
+++ b/arch/alpha/kernel/signal.c	Tue Jul 16 16:49:42 2002
@@ -36,36 +36,6 @@
 		     unsigned long, unsigned long);
 
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
-		int err;
-
-		/* If you change siginfo_t structure, please be sure
-		   this code is fixed accordingly.
-		   It should never copy any pad contained in the structure
-		   to avoid security leaks, but must copy the generic
-		   3 ints plus the relevant union member.  */
-		err = __put_user(*(long *)&from->si_signo, (long *)&to->si_signo);
-		err |= __put_user((short)from->si_code, &to->si_code);
-		switch (from->si_code >> 16) {
-		case __SI_CHLD >> 16:
-			err |= __put_user(from->si_utime, &to->si_utime);
-			err |= __put_user(from->si_stime, &to->si_stime);
-			err |= __put_user(from->si_status, &to->si_status);
-		default:
-			err |= __put_user(from->si_addr, &to->si_addr);
-			break;
-		/* case __SI_RT: This is not generated by the kernel as of now.  */
-		}
-		return err;
-	}
-}
-
 /*
  * The OSF/1 sigprocmask calling sequence is different from the
  * C sigprocmask() sequence..
diff -Nru a/arch/arm/Makefile b/arch/arm/Makefile
--- a/arch/arm/Makefile	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/Makefile	Tue Jul 16 16:49:42 2002
@@ -10,10 +10,12 @@
 LDFLAGS_vmlinux	:=-p -X -T arch/arm/vmlinux.lds
 OBJCOPYFLAGS	:=-O binary -R .note -R .comment -S
 GZFLAGS		:=-9
-CFLAGS		+=-pipe
+#CFLAGS		+=-pipe
+
+CFLAGS		:=$(CFLAGS:-O2=-Os)
 
 ifneq ($(CONFIG_NO_FRAME_POINTER),y)
-CFLAGS		:=$(CFLAGS:-fomit-frame-pointer=)
+CFLAGS		:=$(CFLAGS: -fomit-frame-pointer=)
 endif
 
 ifeq ($(CONFIG_DEBUG_INFO),y)
@@ -24,7 +26,7 @@
 # the options further down the list override previous items.
 #
 apcs-$(CONFIG_CPU_32)		:=-mapcs-32
-apcs-$(CONFIG_CPU_26)		:=-mapcs-26 -mcpu=arm3 -Os
+apcs-$(CONFIG_CPU_26)		:=-mapcs-26 -mcpu=arm3
 
 # This selects which instruction set is used.
 # Note that GCC is lame - it doesn't numerically define an
@@ -212,8 +214,11 @@
 	@ln -sf proc-$(PROCESSOR) include/asm-arm/proc
 	@touch $@
 
-prepare: include/asm-arm/.arch include/asm-arm/.proc \
-	 include/asm-arm/constants.h
+prepare: maketools
+
+.PHONY: maketools
+maketools: include/asm-arm/.arch include/asm-arm/.proc \
+	 include/asm-arm/constants.h include/linux/version.h FORCE
 	@$(MAKETOOLS)
 
 vmlinux: arch/arm/vmlinux.lds
@@ -222,6 +227,7 @@
 	$(wildcard include/config/cpu/32.h) \
 	$(wildcard include/config/cpu/26.h) \
 	$(wildcard include/config/arch/*.h)
+	@echo '  Generating $@'
 	@sed 's/TEXTADDR/$(TEXTADDR)/;s/DATAADDR/$(DATAADDR)/' $(LDSCRIPT) >$@
 
 bzImage zImage zinstall Image bootpImage install: vmlinux
@@ -242,10 +248,6 @@
 
 archclean: FORCE
 	@$(MAKEBOOT) clean
-
-# we need version.h
-maketools: include/linux/version.h FORCE
-	@$(MAKETOOLS)
 
 # My testing targets (that short circuit a few dependencies)
 zImg:;	@$(MAKEBOOT) zImage
diff -Nru a/arch/arm/config.in b/arch/arm/config.in
--- a/arch/arm/config.in	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/config.in	Tue Jul 16 16:49:41 2002
@@ -153,18 +153,15 @@
 fi
 endmenu
 
-if [ "$CONFIG_ARCH_IOP310" = "y" ]; then
-   mainmenu_option next_comment
-   comment 'IOP310 Implementation Options'
-   choice 'IOP310 System Type' \
-   	"IQ80310	CONFIG_ARCH_IQ80310" IQ80310
-   comment 'IOP310 Chipset Features'
-   bool 'Support Intel 80312 Application Accelerator Unit (EXPERIMENTAL)' CONFIG_IOP310_AAU
-   bool 'Support Intel 80312 DMA (EXPERIMENTAL)' CONFIG_IOP310_DMA
-   bool 'Support Intel 80312 Messaging Unit (EXPERIMENTAL)' CONFIG_IOP310_MU
-   bool 'Support Intel 80312 Performance Monitor (EXPERIMENTAL)' CONFIG_IOP310_PMON
-   endmenu
-fi
+mainmenu_option next_comment
+comment 'IOP310 Implementation Options'
+dep_bool '  IQ80310' CONFIG_ARCH_IQ80310 $CONFIG_ARCH_IOP310
+comment 'IOP310 Chipset Features'
+dep_bool 'Support Intel 80312 Application Accelerator Unit (EXPERIMENTAL)' CONFIG_IOP310_AAU $CONFIG_ARCH_IOP310 $CONFIG_EXPERIMENTAL
+dep_bool 'Support Intel 80312 DMA (EXPERIMENTAL)' CONFIG_IOP310_DMA $CONFIG_ARCH_IOP310 $CONFIG_EXPERIMENTAL
+dep_bool 'Support Intel 80312 Messaging Unit (EXPERIMENTAL)' CONFIG_IOP310_MU $CONFIG_ARCH_IOP310 $CONFIG_EXPERIMENTAL
+dep_bool 'Support Intel 80312 Performance Monitor (EXPERIMENTAL)' CONFIG_IOP310_PMON $CONFIG_ARCH_IOP310 $CONFIG_EXPERIMENTAL
+endmenu
 
 # Definitions to make life easier
 if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \
diff -Nru a/arch/arm/def-configs/neponset b/arch/arm/def-configs/neponset
--- a/arch/arm/def-configs/neponset	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/def-configs/neponset	Tue Jul 16 16:49:42 2002
@@ -15,7 +15,14 @@
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
 
 #
 # Loadable module support
@@ -27,6 +34,7 @@
 #
 # System Type
 #
+# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
@@ -36,6 +44,7 @@
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP310 is not set
 # CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
@@ -68,12 +77,16 @@
 # CONFIG_SA1100_ADSBITSY is not set
 # CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_H3XXX is not set
 # CONFIG_SA1100_EXTENEX1 is not set
 # CONFIG_SA1100_FLEXANET is not set
 # CONFIG_SA1100_FREEBIRD is not set
 # CONFIG_SA1100_GRAPHICSCLIENT is not set
 # CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
 # CONFIG_SA1100_HUW_WEBPANEL is not set
 # CONFIG_SA1100_ITSY is not set
@@ -82,27 +95,46 @@
 # CONFIG_SA1100_OMNIMETER is not set
 # CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
 # CONFIG_SA1100_SHERMAN is not set
 # CONFIG_SA1100_SIMPAD is not set
 # CONFIG_SA1100_PFS168 is not set
 # CONFIG_SA1100_VICTOR is not set
 # CONFIG_SA1100_XP860 is not set
 # CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_STORK is not set
 CONFIG_SA1111=y
 CONFIG_FORCE_MAX_ZONEORDER=9
-CONFIG_SA1100_USB=m
-CONFIG_SA1100_USB_NETLINK=m
-CONFIG_SA1100_USB_CHAR=m
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_H3600_SLEEVE is not set
 
 #
 # CLPS711X/EP721X Implementations
 #
+# CONFIG_ARCH_AUTCPU12 is not set
 # CONFIG_ARCH_CDB89712 is not set
 # CONFIG_ARCH_CLEP7312 is not set
 # CONFIG_ARCH_EDB7211 is not set
 # CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
 # CONFIG_ARCH_EP7211 is not set
 # CONFIG_ARCH_EP7212 is not set
+
+#
+# IOP310 Implementation Options
+#
+# CONFIG_ARCH_IQ80310 is not set
+
+#
+# IOP310 Chipset Features
+#
+# CONFIG_IOP310_AAU is not set
+# CONFIG_IOP310_DMA is not set
+# CONFIG_IOP310_MU is not set
+# CONFIG_IOP310_PMON is not set
 # CONFIG_ARCH_ACORN is not set
 # CONFIG_FOOTBRIDGE is not set
 # CONFIG_FOOTBRIDGE_HOST is not set
@@ -115,22 +147,34 @@
 #
 # CONFIG_CPU_32v3 is not set
 CONFIG_CPU_32v4=y
+# CONFIG_CPU_32v5 is not set
 # CONFIG_CPU_ARM610 is not set
 # CONFIG_CPU_ARM710 is not set
 # CONFIG_CPU_ARM720T is not set
 # CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
 # CONFIG_CPU_ARM1020 is not set
 # CONFIG_CPU_SA110 is not set
 CONFIG_CPU_SA1100=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_DISCONTIGMEM=y
+# CONFIG_CPU_XSCALE is not set
+# CONFIG_XSCALE_PMU is not set
+
+#
+# Processor Features
+#
 
 #
 # General setup
 #
+CONFIG_DISCONTIGMEM=y
 # CONFIG_PCI is not set
 CONFIG_ISA=y
 # CONFIG_ISA_DMA is not set
+# CONFIG_FIQ is not set
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
 CONFIG_CPU_FREQ=y
 CONFIG_HOTPLUG=y
 
@@ -138,14 +182,12 @@
 # PCMCIA/CardBus support
 #
 CONFIG_PCMCIA=y
+CONFIG_PCMCIA_PROBE=y
+# CONFIG_I82092 is not set
 # CONFIG_I82365 is not set
 # CONFIG_TCIC is not set
 # CONFIG_PCMCIA_CLPS6700 is not set
 CONFIG_PCMCIA_SA1100=y
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
 
 #
 # At least one math emulation must be selected
@@ -154,12 +196,14 @@
 # CONFIG_FPE_FASTFPE is not set
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
-# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_PM is not set
+CONFIG_PM=y
+# CONFIG_PREEMPT is not set
+CONFIG_APM=y
 # CONFIG_ARTHUR is not set
-CONFIG_CMDLINE=""
+CONFIG_CMDLINE="console=ttySA0,38400n8 console=tty1 cpufreq=221200 rw root=/dev/mtdblock3 load_ramdisk=1 prompt_ramdisk=0 mem=32M noinitrd initrd=0xc0800000,3M profile=2"
 CONFIG_LEDS=y
 CONFIG_LEDS_TIMER=y
 CONFIG_LEDS_CPU=y
@@ -173,30 +217,34 @@
 #
 # Memory Technology Devices (MTD)
 #
-CONFIG_MTD=m
+CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=m
-CONFIG_MTD_REDBOOT_PARTS=m
-CONFIG_MTD_BOOTLDR_PARTS=m
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_REDBOOT_PARTS=y
+# CONFIG_MTD_BOOTLDR_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
 #
 # User Modules And Translation Layers
 #
-CONFIG_MTD_CHAR=m
-CONFIG_MTD_BLOCK=m
-# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_MTD_CHAR is not set
+CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
 
 #
 # RAM/ROM/Flash chip drivers
 #
-CONFIG_MTD_CFI=m
+CONFIG_MTD_CFI=y
 # CONFIG_MTD_JEDECPROBE is not set
-CONFIG_MTD_GEN_PROBE=m
-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
-CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY is not set
+CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
@@ -213,9 +261,12 @@
 # CONFIG_MTD_NORA is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_CDB89712 is not set
-CONFIG_MTD_SA1100=m
+CONFIG_MTD_SA1100=y
+# CONFIG_MTD_2PARTS_IPAQ is not set
 # CONFIG_MTD_DC21285 is not set
 # CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_EPXA10DB is not set
+# CONFIG_MTD_FORTUNET is not set
 # CONFIG_MTD_PCI is not set
 
 #
@@ -256,10 +307,11 @@
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
 
 #
@@ -277,8 +329,9 @@
 #
 # Networking options
 #
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
@@ -288,17 +341,24 @@
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
 
 #
 #  
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -328,6 +388,7 @@
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -337,7 +398,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -360,11 +420,13 @@
 #
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -390,6 +452,11 @@
 # CONFIG_WAN is not set
 
 #
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+
+#
 # PCMCIA network device support
 #
 CONFIG_NET_PCMCIA=y
@@ -400,6 +467,7 @@
 # CONFIG_PCMCIA_NMCLAN is not set
 # CONFIG_PCMCIA_SMC91C92 is not set
 # CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_AXNET is not set
 # CONFIG_ARCNET_COM20020_CS is not set
 # CONFIG_PCMCIA_IBMTR is not set
 # CONFIG_NET_PCMCIA_RADIO is not set
@@ -417,38 +485,8 @@
 #
 # ATA/IDE/MFM/RLL support
 #
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_IDE is not set
 # CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECS=y
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
 
 #
 # SCSI support
@@ -467,37 +505,131 @@
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN is not set
+# CONFIG_ISDN_BOOL is not set
 
 #
-# Input core support
+# Input device support
 #
 CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
 CONFIG_INPUT_KEYBDEV=y
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 # CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_TSLIBDEV=y
 # CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_GAMEPORT_NS558 is not set
+# CONFIG_GAMEPORT_L4 is not set
+# CONFIG_INPUT_EMU10K1 is not set
+# CONFIG_GAMEPORT_VORTEX is not set
+# CONFIG_GAMEPORT_FM801 is not set
+# CONFIG_GAMEPORT_CS461x is not set
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_SA1111=y
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_PS2SERKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_JOYSTICK_ANALOG is not set
+# CONFIG_JOYSTICK_A3D is not set
+# CONFIG_JOYSTICK_ADI is not set
+# CONFIG_JOYSTICK_COBRA is not set
+# CONFIG_JOYSTICK_GF2K is not set
+# CONFIG_JOYSTICK_GRIP is not set
+# CONFIG_JOYSTICK_GUILLEMOT is not set
+# CONFIG_JOYSTICK_INTERACT is not set
+# CONFIG_JOYSTICK_SIDEWINDER is not set
+# CONFIG_JOYSTICK_TMDC is not set
+# CONFIG_JOYSTICK_IFORCE_USB is not set
+# CONFIG_JOYSTICK_IFORCE_232 is not set
+# CONFIG_JOYSTICK_WARRIOR is not set
+# CONFIG_JOYSTICK_MAGELLAN is not set
+# CONFIG_JOYSTICK_SPACEORB is not set
+# CONFIG_JOYSTICK_SPACEBALL is not set
+# CONFIG_JOYSTICK_STINGER is not set
+# CONFIG_JOYSTICK_TWIDDLER is not set
+# CONFIG_JOYSTICK_DB9 is not set
+# CONFIG_JOYSTICK_GAMECON is not set
+# CONFIG_JOYSTICK_TURBOGRAFX is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
 
 #
 # Character devices
 #
 CONFIG_VT=y
 # CONFIG_VT_CONSOLE is not set
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_DIGI is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
 
 #
 # Serial drivers
 #
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+CONFIG_SERIAL_8250_CS=y
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_ATOMWIDE_SERIAL is not set
+# CONFIG_DUALSP_SERIAL is not set
 # CONFIG_SERIAL_ANAKIN is not set
 # CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
 # CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X_OLD_NAME is not set
 # CONFIG_SERIAL_21285 is not set
 # CONFIG_SERIAL_21285_OLD is not set
 # CONFIG_SERIAL_21285_CONSOLE is not set
@@ -505,15 +637,6 @@
 # CONFIG_SERIAL_UART00_CONSOLE is not set
 CONFIG_SERIAL_SA1100=y
 CONFIG_SERIAL_SA1100_CONSOLE=y
-CONFIG_SA1100_DEFAULT_BAUDRATE=9600
-CONFIG_SERIAL_8250=m
-# CONFIG_SERIAL_8250_CONSOLE is not set
-# CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_MANY_PORTS is not set
-# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_HUB6 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -522,71 +645,61 @@
 #
 # I2C support
 #
-# CONFIG_I2C is not set
+CONFIG_I2C=y
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_PHILIPSPAR is not set
+# CONFIG_I2C_ELV is not set
+# CONFIG_I2C_VELLEMAN is not set
+CONFIG_I2C_BIT_SA1100_GPIO=y
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PROC=y
 
 #
 # L3 serial bus support
 #
-# CONFIG_L3 is not set
-# CONFIG_L3_ALGOBIT is not set
-# CONFIG_L3_BIT_SA1100_GPIO is not set
+CONFIG_L3=y
+CONFIG_L3_ALGOBIT=y
+CONFIG_L3_BIT_SA1100_GPIO=y
 
 #
 # Other L3 adapters
 #
-# CONFIG_L3_SA1111 is not set
-# CONFIG_BIT_SA1100_GPIO is not set
+CONFIG_L3_SA1111=y
+CONFIG_BIT_SA1100_GPIO=y
 
 #
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
 # CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-# CONFIG_INPUT_NS558 is not set
-# CONFIG_INPUT_LIGHTNING is not set
-# CONFIG_INPUT_PCIGAME is not set
-# CONFIG_INPUT_CS461X is not set
-# CONFIG_INPUT_EMU10K1 is not set
-# CONFIG_INPUT_SERIO is not set
-# CONFIG_INPUT_SERPORT is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_ANALOG is not set
-# CONFIG_INPUT_A3D is not set
-# CONFIG_INPUT_ADI is not set
-# CONFIG_INPUT_COBRA is not set
-# CONFIG_INPUT_GF2K is not set
-# CONFIG_INPUT_GRIP is not set
-# CONFIG_INPUT_INTERACT is not set
-# CONFIG_INPUT_TMDC is not set
-# CONFIG_INPUT_SIDEWINDER is not set
-# CONFIG_INPUT_IFORCE_USB is not set
-# CONFIG_INPUT_IFORCE_232 is not set
-# CONFIG_INPUT_WARRIOR is not set
-# CONFIG_INPUT_MAGELLAN is not set
-# CONFIG_INPUT_SPACEORB is not set
-# CONFIG_INPUT_SPACEBALL is not set
-# CONFIG_INPUT_STINGER is not set
-# CONFIG_INPUT_DB9 is not set
-# CONFIG_INPUT_GAMECON is not set
-# CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
 
 #
 # Watchdog Cards
 #
-# CONFIG_WATCHDOG is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_21285_WATCHDOG is not set
+# CONFIG_977_WATCHDOG is not set
+CONFIG_SA1100_WATCHDOG=m
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_MACHZ_WDT is not set
 # CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_SA1100_RTC is not set
+CONFIG_SA1100_RTC=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -601,8 +714,7 @@
 #
 # PCMCIA character devices
 #
-CONFIG_PCMCIA_SERIAL_CS=m
-# CONFIG_MWAVE is not set
+# CONFIG_SYNCLINK_CS is not set
 
 #
 # Multimedia devices
@@ -613,35 +725,41 @@
 # File systems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_CMS_FS is not set
 # CONFIG_EXT3_FS is not set
 # CONFIG_JBD is not set
 # CONFIG_JBD_DEBUG is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
-CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
 # CONFIG_MINIX_FS is not set
-# CONFIG_FREEVXFS_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_DEBUG is not set
 # CONFIG_HPFS_FS is not set
@@ -670,8 +788,10 @@
 # CONFIG_ROOT_NFS is not set
 # CONFIG_NFSD is not set
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
+# CONFIG_EXPORTFS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_NCPFS_PACKET_SIGNING is not set
@@ -683,7 +803,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -694,15 +813,12 @@
 # CONFIG_AMIGA_PARTITION is not set
 # CONFIG_ATARI_PARTITION is not set
 # CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_MSDOS_PARTITION is not set
 # CONFIG_LDM_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 CONFIG_NLS=y
 
@@ -710,7 +826,7 @@
 # Native Language Support
 #
 CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
 # CONFIG_NLS_CODEPAGE_850 is not set
@@ -731,8 +847,9 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
 # CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -771,16 +888,21 @@
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_FONTWIDTH8_ONLY=y
 CONFIG_FBCON_FONTS=y
-CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x8 is not set
 # CONFIG_FONT_8x16 is not set
 # CONFIG_FONT_SUN8x16 is not set
 # CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_ACORN_8x8=y
 
 #
 # Sound
 #
 CONFIG_SOUND=y
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
@@ -801,17 +923,24 @@
 # CONFIG_SOUND_VIA82CXXX is not set
 # CONFIG_MIDI_VIA82CXXX is not set
 CONFIG_SOUND_SA1100=y
-# CONFIG_SOUND_UDA1341 is not set
-# CONFIG_SOUND_ASSABET_UDA1341 is not set
+CONFIG_SOUND_UDA1341=y
+CONFIG_SOUND_ASSABET_UDA1341=y
 # CONFIG_SOUND_H3600_UDA1341 is not set
 # CONFIG_SOUND_PANGOLIN_UDA1341 is not set
-# CONFIG_SOUND_SA1111_UDA1341 is not set
+CONFIG_SOUND_SA1111_UDA1341=y
+# CONFIG_SOUND_STORK_UDA1341 is not set
 # CONFIG_SOUND_SA1100SSP is not set
+# CONFIG_SOUND_STORK_AC97 is not set
 # CONFIG_SOUND_OSS is not set
 # CONFIG_SOUND_WAVEARTIST is not set
 # CONFIG_SOUND_TVMIXER is not set
 
 #
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
 # Multimedia Capabilities Port drivers
 #
 CONFIG_MCP=y
@@ -823,37 +952,43 @@
 #
 # Console Switches
 #
-CONFIG_SWITCHES=y
-CONFIG_SWITCHES_SA1100=y
-CONFIG_SWITCHES_UCB1X00=y
+# CONFIG_SWITCHES is not set
 
 #
 # USB support
 #
-CONFIG_USB=y
+CONFIG_USB=m
 CONFIG_USB_DEBUG=y
 
 #
 # Miscellaneous USB options
 #
-# CONFIG_USB_DEVICEFS is not set
-# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_LONG_TIMEOUT is not set
-# CONFIG_USB_LARGE_CONFIG is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
 
 #
-# USB Controllers
+# USB Host Controller Drivers
 #
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-CONFIG_USB_OHCI_SA1111=y
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_UHCI_HCD_ALT is not set
+CONFIG_USB_OHCI_SA1111=m
+# CONFIG_USB_SL811HS is not set
 
 #
 # USB Device Class drivers
 #
 # CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -862,21 +997,23 @@
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
 
 #
 # USB Human Interface Devices (HID)
 #
-CONFIG_USB_HID=y
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDINPUT is not set
 # CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
 
 #
 # USB Imaging devices
 #
-# CONFIG_USB_DC2XX is not set
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_SCANNER is not set
 # CONFIG_USB_MICROTEK is not set
@@ -885,18 +1022,28 @@
 #
 # USB Multimedia devices
 #
+# CONFIG_USB_DABUSB is not set
 
 #
 #   Video4Linux support is needed for USB Multimedia device support
 #
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_STV680 is not set
 
 #
 # USB Network adaptors
 #
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
 
 #
@@ -915,6 +1062,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -926,9 +1074,14 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
 # CONFIG_USB_SERIAL_OMNINET is not set
@@ -936,8 +1089,11 @@
 #
 # USB Miscellaneous drivers
 #
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
-# CONFIG_USB_ID75 is not set
+# CONFIG_USB_BRLVGER is not set
 
 #
 # Bluetooth support
@@ -948,13 +1104,22 @@
 # Kernel hacking
 #
 # CONFIG_NO_FRAME_POINTER is not set
-CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SLAB=y
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_NO_PGT_CACHE is not set
-# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_DC21285_PORT is not set
 # CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff -Nru a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
--- a/arch/arm/kernel/entry-armv.S	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/kernel/entry-armv.S	Tue Jul 16 16:49:42 2002
@@ -712,7 +712,6 @@
 		mrs	r9, cpsr			@ Enable interrupts if they were
 		tst	r3, #PSR_I_BIT
 		biceq	r9, r9, #PSR_I_BIT		@ previously
-		mov	r0, r2				@ *** remove once everyones in sync
 /*
  * This routine must not corrupt r9
  */
@@ -855,7 +854,6 @@
 		stmdb	r5, {sp, lr}^
 		alignment_trap r7, r7, __temp_abt
 		zero_fp
-		mov	r0, r2				@ remove once everyones in sync
 #ifdef MULTI_ABORT
 		ldr	r4, .LCprocfns			@ pass r0, r3 to
 		mov	lr, pc				@ processor code
@@ -913,10 +911,13 @@
 		stmdb	r8, {sp, lr}^			@ Save user sp, lr
 		alignment_trap r4, r7, __temp_und
 		zero_fp
+		tst	r6, #PSR_T_BIT			@ Thumb mode?
+		bne	fpundefinstr			@ ignore FP
 		adrsvc	al, r9, ret_from_exception	@ r9  = normal FP return
 		adrsvc	al, lr, fpundefinstr		@ lr  = undefined instr return
 
-call_fpe:	get_thread_info r10			@ get current thread
+call_fpe:	set_cpsr_c r0, #MODE_SVC		@ Enable interrupts
+		get_thread_info r10			@ get current thread
 		ldr	r4, [r10, #TI_TASK]		@ get current task
 		mov	r8, #1
 		strb	r8, [r4, #TSK_USED_MATH]	@ set current->used_math
@@ -924,8 +925,7 @@
 		add	r10, r10, #TI_FPSTATE		@ r10 = workspace
 		ldr	pc, [r4]			@ Call FP module USR entry point
 
-fpundefinstr:	set_cpsr_c r0, #MODE_SVC		@ Enable interrupts
-		mov	r0, sp
+fpundefinstr:	mov	r0, sp
 		adrsvc	al, lr, ret_from_exception
 		b	do_undefinstr
 
diff -Nru a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
--- a/arch/arm/kernel/irq.c	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/kernel/irq.c	Tue Jul 16 16:49:41 2002
@@ -202,8 +202,7 @@
 	if (status & SA_SAMPLE_RANDOM)
 		add_interrupt_randomness(irq);
 
-	__cli();
-	spin_lock(&irq_controller_lock);
+	spin_lock_irq(&irq_controller_lock);
 }
 
 /*
@@ -634,6 +633,8 @@
 
 		irq_desc[i].probing = 1;
 		irq_desc[i].triggered = 0;
+		if (irq_desc[i].chip->type)
+			irq_desc[i].chip->type(i, IRQT_PROBE);
 		irq_desc[i].chip->unmask(i);
 		irqs += 1;
 	}
diff -Nru a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
--- a/arch/arm/kernel/process.c	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/kernel/process.c	Tue Jul 16 16:49:42 2002
@@ -75,10 +75,10 @@
  */
 void default_idle(void)
 {
-	__cli();
+	local_irq_disable();
 	if (!need_resched() && !hlt_counter)
 		arch_idle();
-	__sti();
+	local_irq_enable();
 }
 
 /*
diff -Nru a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
--- a/arch/arm/kernel/ptrace.c	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/kernel/ptrace.c	Tue Jul 16 16:49:41 2002
@@ -40,12 +40,17 @@
  * Get the address of the live pt_regs for the specified task.
  * These are saved onto the top kernel stack when the process
  * is not running.
+ *
+ * Note: if a user thread is execve'd from kernel space, the
+ * kernel stack will not be empty on entry to the kernel, so
+ * ptracing these tasks will fail.
  */
 static inline struct pt_regs *
 get_user_regs(struct task_struct *task)
 {
 	return (struct pt_regs *)
-		((unsigned long)task->thread_info + 8192 - sizeof(struct pt_regs));
+		((unsigned long)task->thread_info + THREAD_SIZE -
+				 8 - sizeof(struct pt_regs));
 }
 
 /*
@@ -54,7 +59,7 @@
  * this routine assumes that all the privileged stacks are in our
  * data space.
  */
-static inline long get_stack_long(struct task_struct *task, int offset)
+static inline long get_user_reg(struct task_struct *task, int offset)
 {
 	return get_user_regs(task)->uregs[offset];
 }
@@ -66,7 +71,7 @@
  * data space.
  */
 static inline int
-put_stack_long(struct task_struct *task, int offset, long data)
+put_user_reg(struct task_struct *task, int offset, long data)
 {
 	struct pt_regs newregs, *regs = get_user_regs(task);
 	int ret = -EINVAL;
@@ -111,7 +116,7 @@
 	unsigned int reg = (insn >> 16) & 15;
 	unsigned long val;
 
-	val = get_stack_long(child, reg);
+	val = get_user_reg(child, reg);
 	if (reg == 15)
 		val = pc_pointer(val + 8);
 
@@ -133,10 +138,10 @@
 		shift = (insn >> 8) & 15;
 		type = 3;
 	} else {
-		val = get_stack_long (child, insn & 15);
+		val = get_user_reg (child, insn & 15);
 
 		if (insn & (1 << 4))
-			shift = (int)get_stack_long (child, (insn >> 8) & 15);
+			shift = (int)get_user_reg (child, (insn >> 8) & 15);
 		else
 			shift = (insn >> 7) & 31;
 
@@ -166,7 +171,7 @@
 	int shift;
 	int type;
 
-	val = get_stack_long(child, insn & 15);
+	val = get_user_reg(child, insn & 15);
 	shift = (insn >> 7) & 31;
 	type = (insn >> 5) & 3;
 
@@ -215,7 +220,7 @@
 
 		aluop1 = ptrace_getrn(child, insn);
 		aluop2 = ptrace_getaluop2(child, insn);
-		ccbit  = get_stack_long(child, REG_PSR) & PSR_C_BIT ? 1 : 0;
+		ccbit  = get_user_reg(child, REG_PSR) & PSR_C_BIT ? 1 : 0;
 
 		switch (insn & OP_MASK) {
 		case OP_AND: alt = aluop1 & aluop2;		break;
@@ -270,13 +275,7 @@
 			unsigned int nr_regs;
 
 			if (insn & (1 << 23)) {
-				nr_regs = insn & 65535;
-
-				nr_regs = (nr_regs & 0x5555) + ((nr_regs & 0xaaaa) >> 1);
-				nr_regs = (nr_regs & 0x3333) + ((nr_regs & 0xcccc) >> 2);
-				nr_regs = (nr_regs & 0x0707) + ((nr_regs & 0x7070) >> 4);
-				nr_regs = (nr_regs & 0x000f) + ((nr_regs & 0x0f00) >> 8);
-				nr_regs <<= 2;
+				nr_regs = hweight16(insn & 65535) << 2;
 
 				if (!(insn & (1 << 24)))
 					nr_regs -= 4;
@@ -348,6 +347,11 @@
 	regs = get_user_regs(child);
 	pc = instruction_pointer(regs);
 
+	if (thumb_mode(regs)) {
+		printk(KERN_WARNING "ptrace: can't handle thumb mode\n");
+		return -EINVAL;
+	}
+
 	res = read_tsk_long(child, pc, &insn);
 	if (!res) {
 		struct debug_info *dbg = &child->thread.debug;
@@ -411,6 +415,118 @@
 	__ptrace_cancel_bpt(child);
 }
 
+/*
+ * Handle hitting a breakpoint.
+ */
+void ptrace_break(struct task_struct *tsk, struct pt_regs *regs)
+{
+	siginfo_t info;
+
+	/*
+	 * The PC is always left pointing at the next instruction.  Fix this.
+	 */
+	regs->ARM_pc -= 4;
+
+	if (tsk->thread.debug.nsaved == 0)
+		printk(KERN_ERR "ptrace: bogus breakpoint trap\n");
+
+	__ptrace_cancel_bpt(tsk);
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code  = TRAP_BRKPT;
+	info.si_addr  = (void *)instruction_pointer(regs) -
+			 (thumb_mode(regs) ? 2 : 4);
+
+	force_sig_info(SIGTRAP, &info, tsk);
+}
+
+/*
+ * Read the word at offset "off" into the "struct user".  We
+ * actually access the pt_regs stored on the kernel stack.
+ */
+static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
+			    unsigned long *ret)
+{
+	unsigned long tmp;
+
+	if (off & 3 || off >= sizeof(struct user))
+		return -EIO;
+
+	tmp = 0;
+	if (off < sizeof(struct pt_regs))
+		tmp = get_user_reg(tsk, off >> 2);
+
+	return put_user(tmp, ret);
+}
+
+/*
+ * Write the word at offset "off" into "struct user".  We
+ * actually access the pt_regs stored on the kernel stack.
+ */
+static int ptrace_write_user(struct task_struct *tsk, unsigned long off,
+			     unsigned long val)
+{
+	if (off & 3 || off >= sizeof(struct user))
+		return -EIO;
+
+	if (off >= sizeof(struct pt_regs))
+		return 0;
+
+	return put_user_reg(tsk, off >> 2, val);
+}
+
+/*
+ * Get all user integer registers.
+ */
+static int ptrace_getregs(struct task_struct *tsk, void *uregs)
+{
+	struct pt_regs *regs = get_user_regs(tsk);
+
+	return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
+}
+
+/*
+ * Set all user integer registers.
+ */
+static int ptrace_setregs(struct task_struct *tsk, void *uregs)
+{
+	struct pt_regs newregs;
+	int ret;
+
+	ret = -EFAULT;
+	if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) {
+		struct pt_regs *regs = get_user_regs(tsk);
+
+		ret = -EINVAL;
+		if (valid_user_regs(&newregs)) {
+			*regs = newregs;
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Get the child FPU state.
+ */
+static int ptrace_getfpregs(struct task_struct *tsk, void *ufp)
+{
+	return copy_to_user(ufp, &tsk->thread_info->fpstate,
+			    sizeof(struct user_fp)) ? -EFAULT : 0;
+}
+
+/*
+ * Set the child FPU state.
+ */
+static int ptrace_setfpregs(struct task_struct *tsk, void *ufp)
+{
+	tsk->used_math = 1;
+	return copy_from_user(&tsk->thread_info->fpstate, ufp,
+			      sizeof(struct user_fp)) ? -EFAULT : 0;
+}
+
 static int do_ptrace(int request, struct task_struct *child, long addr, long data)
 {
 	unsigned long tmp;
@@ -427,18 +543,8 @@
 				ret = put_user(tmp, (unsigned long *) data);
 			break;
 
-		/*
-		 * read the word at location "addr" in the user registers.
-		 */
 		case PTRACE_PEEKUSR:
-			ret = -EIO;
-			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
-				break;
-
-			tmp = 0;  /* Default return condition */
-			if (addr < sizeof(struct pt_regs))
-				tmp = get_stack_long(child, (int)addr >> 2);
-			ret = put_user(tmp, (unsigned long *)data);
+			ret = ptrace_read_user(child, addr, (unsigned long *)data);
 			break;
 
 		/*
@@ -449,16 +555,8 @@
 			ret = write_tsk_long(child, addr, data);
 			break;
 
-		/*
-		 * write the word at location addr in the user registers.
-		 */
 		case PTRACE_POKEUSR:
-			ret = -EIO;
-			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
-				break;
-
-			if (addr < sizeof(struct pt_regs))
-				ret = put_stack_long(child, (int)addr >> 2, data);
+			ret = ptrace_write_user(child, addr, data);
 			break;
 
 		/*
@@ -486,14 +584,12 @@
 		 * exit.
 		 */
 		case PTRACE_KILL:
-			/* already dead */
-			ret = 0;
-			if (child->state == TASK_ZOMBIE)
-				break;
-			child->exit_code = SIGKILL;
 			/* make sure single-step breakpoint is gone. */
 			__ptrace_cancel_bpt(child);
-			wake_up_process(child);
+			if (child->state != TASK_ZOMBIE) {
+				child->exit_code = SIGKILL;
+				wake_up_process(child);
+			}
 			ret = 0;
 			break;
 
@@ -512,71 +608,32 @@
 			ret = 0;
 			break;
 
-		/*
-		 * detach a process that was attached.
-		 */
 		case PTRACE_DETACH:
 			ret = ptrace_detach(child, data);
 			break;
 
-		/*
-		 * Get all gp regs from the child.
-		 */
-		case PTRACE_GETREGS: {
-			struct pt_regs *regs = get_user_regs(child);
-
-			ret = 0;
-			if (copy_to_user((void *)data, regs,
-					 sizeof(struct pt_regs)))
-				ret = -EFAULT;
-
+		case PTRACE_GETREGS:
+			ret = ptrace_getregs(child, (void *)data);
 			break;
-		}
-
-		/*
-		 * Set all gp regs in the child.
-		 */
-		case PTRACE_SETREGS: {
-			struct pt_regs newregs;
 
-			ret = -EFAULT;
-			if (copy_from_user(&newregs, (void *)data,
-					   sizeof(struct pt_regs)) == 0) {
-				struct pt_regs *regs = get_user_regs(child);
-
-				ret = -EINVAL;
-				if (valid_user_regs(&newregs)) {
-					*regs = newregs;
-					ret = 0;
-				}
-			}
+		case PTRACE_SETREGS:
+			ret = ptrace_setregs(child, (void *)data);
 			break;
-		}
 
-		/*
-		 * Get the child FPU state.
-		 */
 		case PTRACE_GETFPREGS:
-			ret = -EIO;
-			if (!access_ok(VERIFY_WRITE, (void *)data, sizeof(struct user_fp)))
-				break;
-
-			/* we should check child->used_math here */
-			ret = __copy_to_user((void *)data, &child->thread_info->fpstate,
-					     sizeof(struct user_fp)) ? -EFAULT : 0;
+			ret = ptrace_getfpregs(child, (void *)data);
 			break;
 		
-		/*
-		 * Set the child FPU state.
-		 */
 		case PTRACE_SETFPREGS:
-			ret = -EIO;
-			if (!access_ok(VERIFY_READ, (void *)data, sizeof(struct user_fp)))
-				break;
+			ret = ptrace_setfpregs(child, (void *)data);
+			break;
 
-			child->used_math = 1;
-			ret = __copy_from_user(&child->thread_info->fpstate, (void *)data,
-					   sizeof(struct user_fp)) ? -EFAULT : 0;
+		case PTRACE_SETOPTIONS:
+			if (data & PTRACE_O_TRACESYSGOOD)
+				child->ptrace |= PT_TRACESYSGOOD;
+			else
+				child->ptrace &= ~PT_TRACESYSGOOD;
+			ret = 0;
 			break;
 
 		default:
diff -Nru a/arch/arm/kernel/ptrace.h b/arch/arm/kernel/ptrace.h
--- a/arch/arm/kernel/ptrace.h	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/kernel/ptrace.h	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/kernel/ptrace.h
  *
- *  Copyright (C) 2000 Russell King
+ *  Copyright (C) 2000-2002 Russell King
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -9,6 +9,7 @@
  */
 extern void __ptrace_cancel_bpt(struct task_struct *);
 extern int ptrace_set_bpt(struct task_struct *);
+extern void ptrace_break(struct task_struct *, struct pt_regs *);
 
 /*
  * Clear a breakpoint, if one exists.
diff -Nru a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
--- a/arch/arm/kernel/signal.c	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/kernel/signal.c	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/kernel/signal.c
  *
- *  Copyright (C) 1995-2001 Russell King
+ *  Copyright (C) 1995-2002 Russell King
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,15 +17,15 @@
 #include <linux/signal.h>
 #include <linux/wait.h>
 #include <linux/ptrace.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
 #include <linux/personality.h>
 #include <linux/tty.h>
+#include <linux/binfmts.h>
 #include <linux/elf.h>
 
 #include <asm/pgalloc.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
+#include <asm/unistd.h>
 
 #include "ptrace.h"
 
@@ -49,7 +49,7 @@
 	SWI_SYS_RT_SIGRETURN,	SWI_THUMB_RT_SIGRETURN
 };
 
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
+static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
 
 /*
  * atomically swap in the new signal mask, and wait for a signal.
@@ -325,7 +325,7 @@
 	unsigned long retcode;
 	int thumb = 0;
 #ifdef CONFIG_CPU_32
-	unsigned long cpsr = regs->ARM_cpsr;
+	unsigned long cpsr = regs->ARM_cpsr & ~PSR_f;
 
 	/*
 	 * Maybe we need to deliver a 32-bit signal to a 26-bit task.
@@ -501,7 +501,7 @@
  * the kernel can handle, and then we build all the user-level signal handling
  * stack-frames in one go after that.
  */
-int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
+static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
 {
 	struct k_sigaction *ka;
 	siginfo_t info;
@@ -516,9 +516,6 @@
 	if (!user_mode(regs))
 		return 0;
 
-	if (!oldset)
-		oldset = &current->blocked;
-
 	single_stepping = ptrace_cancel_bpt(current);
 
 	for (;;) {
@@ -598,6 +595,7 @@
 				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
+				single_stepping |= ptrace_cancel_bpt(current);
 				continue;
 			}
 
@@ -655,5 +653,5 @@
 do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
 {
 	if (thread_flags & _TIF_SIGPENDING)
-		do_signal(NULL, regs, syscall);
+		do_signal(&current->blocked, regs, syscall);
 }
diff -Nru a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
--- a/arch/arm/kernel/traps.c	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/kernel/traps.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/kernel/traps.c
  *
- *  Copyright (C) 1995, 1996 Russell King
+ *  Copyright (C) 1995-2002 Russell King
  *  Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds
  *
  * This program is free software; you can redistribute it and/or modify
@@ -66,8 +66,17 @@
 static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
 {
 	unsigned long p = bottom & ~31;
+	mm_segment_t fs;
 	int i;
 
+	/*
+	 * We need to switch to kernel mode so that we can use __get_user
+	 * to safely read from kernel space.  Note that we now dump the
+	 * code first, just in case the backtrace kills us.
+	 */
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
 	printk("%s", str);
 	printk("(0x%08lx to 0x%08lx)\n", bottom, top);
 
@@ -86,6 +95,8 @@
 		}
 		printk ("\n");
 	}
+
+	set_fs(fs);
 }
 
 static void dump_instr(struct pt_regs *regs)
@@ -93,8 +104,17 @@
 	unsigned long addr = instruction_pointer(regs);
 	const int thumb = thumb_mode(regs);
 	const int width = thumb ? 4 : 8;
+	mm_segment_t fs;
 	int i;
 
+	/*
+	 * We need to switch to kernel mode so that we can use __get_user
+	 * to safely read from kernel space.  Note that we now dump the
+	 * code first, just in case the backtrace kills us.
+	 */
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
 	printk("Code: ");
 	for (i = -4; i < 1; i++) {
 		unsigned int val, bad;
@@ -112,6 +132,8 @@
 		}
 	}
 	printk("\n");
+
+	set_fs(fs);
 }
 
 static void dump_stack(struct task_struct *tsk, unsigned long sp)
@@ -171,22 +193,9 @@
 		current->comm, current->pid, tsk->thread_info + 1);
 
 	if (!user_mode(regs) || in_interrupt()) {
-		mm_segment_t fs;
-
-		/*
-		 * We need to switch to kernel mode so that we can
-		 * use __get_user to safely read from kernel space.
-		 * Note that we now dump the code first, just in case
-		 * the backtrace kills us.
-		 */
-		fs = get_fs();
-		set_fs(KERNEL_DS);
-
 		dump_stack(tsk, (unsigned long)(regs + 1));
 		dump_backtrace(regs, tsk);
 		dump_instr(regs);
-
-		set_fs(fs);
 	}
 
 	spin_unlock_irq(&die_lock);
@@ -233,7 +242,7 @@
 }
 
 #ifdef CONFIG_CPU_26
-asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode)
+asmlinkage void do_excpt(unsigned long address, struct pt_regs *regs, int mode)
 {
 	siginfo_t info;
 
@@ -274,7 +283,6 @@
 asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode)
 {
 	unsigned int vectors = vectors_base();
-	mm_segment_t fs;
 
 	console_verbose();
 
@@ -282,24 +290,14 @@
 		handler[reason], processor_modes[proc_mode]);
 
 	/*
-	 * We need to switch to kernel mode so that we can use __get_user
-	 * to safely read from kernel space.  Note that we now dump the
-	 * code first, just in case the backtrace kills us.
-	 */
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-
-	/*
 	 * Dump out the vectors and stub routines.  Maybe a better solution
 	 * would be to dump them out only if we detect that they are corrupted.
 	 */
 	dump_mem(KERN_CRIT "Vectors: ", vectors, vectors + 0x40);
 	dump_mem(KERN_CRIT "Stubs: ", vectors + 0x200, vectors + 0x4b8);
 
-	set_fs(fs);
-
 	die("Oops", regs, 0);
-	cli();
+	local_irq_disable();
 	panic("bad mode");
 }
 
@@ -308,13 +306,7 @@
 	struct thread_info *thread = current_thread_info();
 	siginfo_t info;
 
-	/* You might think just testing `handler' would be enough, but PER_LINUX
-	 * points it to no_lcall7 to catch undercover SVr4 binaries.  Gutted.
-	 */
 	if (current->personality != PER_LINUX && thread->exec_domain->handler) {
-		/* Hand it off to iBCS.  The extra parameter and consequent type 
-		 * forcing is necessary because of the weird ARM calling convention.
-		 */
 		thread->exec_domain->handler(n, regs);
 		return regs->ARM_r0;
 	}
@@ -380,20 +372,7 @@
 		return 0;
 
 	case NR(breakpoint): /* SWI BREAK_POINT */
-		/*
-		 * The PC is always left pointing at the next
-		 * instruction.  Fix this.
-		 */
-		regs->ARM_pc -= 4;
-		__ptrace_cancel_bpt(current);
-
-		info.si_signo = SIGTRAP;
-		info.si_errno = 0;
-		info.si_code  = TRAP_BRKPT;
-		info.si_addr  = (void *)instruction_pointer(regs) -
-				 (thumb_mode(regs) ? 2 : 4);
-
-		force_sig_info(SIGTRAP, &info, current);
+		ptrace_break(current, regs);
 		return regs->ARM_r0;
 
 #ifdef CONFIG_CPU_32
@@ -418,13 +397,13 @@
 	case NR(usr26):
 		if (!(elf_hwcap & HWCAP_26BIT))
 			break;
-		regs->ARM_cpsr &= ~0x10;
+		regs->ARM_cpsr &= ~MODE32_BIT;
 		return regs->ARM_r0;
 
 	case NR(usr32):
 		if (!(elf_hwcap & HWCAP_26BIT))
 			break;
-		regs->ARM_cpsr |= 0x10;
+		regs->ARM_cpsr |= MODE32_BIT;
 		return regs->ARM_r0;
 #else
 	case NR(cacheflush):
diff -Nru a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
--- a/arch/arm/lib/backtrace.S	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/lib/backtrace.S	Tue Jul 16 16:49:41 2002
@@ -52,25 +52,32 @@
 3:		tst	frame, mask		@ Check for address exceptions...
 		bne	1b
 
-1001:		ldmda	frame, {r0, r1, r2, r3}	@ fp, sp, lr, pc
-		mov	next, r0
-
+1001:		ldr	next, [frame, #-12]	@ get fp
+1002:		ldr	r2, [frame, #-4]	@ get lr
+1003:		ldr	r3, [frame, #0]		@ get pc
 		sub	save, r3, offset	@ Correct PC for prefetching
 		bic	save, save, mask
+1004:		ldr	r1, [save, #0]		@ get instruction at function
+		mov	r1, r1, lsr #10
+		ldr	r3, .Ldsi+4
+		teq	r1, r3
+		subeq	save, save, #4
 		adr	r0, .Lfe
 		mov	r1, save
 		bic	r2, r2, mask
 		bl	printk			@ print pc and link register
 
-		sub	r0, frame, #16
-1002:		ldr	r1, [save, #4]		@ get instruction at function+4
+		ldr	r0, [frame, #-8]	@ get sp
+		sub	r0, r0, #4
+1005:		ldr	r1, [save, #4]		@ get instruction at function+4
 		mov	r3, r1, lsr #10
 		ldr	r2, .Ldsi+4
 		teq	r3, r2			@ Check for stmia sp!, {args}
 		addeq	save, save, #4		@ next instruction
 		bleq	.Ldumpstm
 
-1003:		ldr	r1, [save, #4]		@ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction
+		sub	r0, frame, #16
+1006:		ldr	r1, [save, #4]		@ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction
 		mov	r3, r1, lsr #10
 		ldr	r2, .Ldsi
 		teq	r3, r2
@@ -87,7 +94,7 @@
  */
 		.section .fixup,"ax"
 		.align	0
-1004:		ldr	r0, =.Lbad
+1007:		ldr	r0, =.Lbad
 		mov	r1, frame
 		bl	printk
 		LOADREGS(fd, sp!, {r4 - r8, pc})
@@ -96,9 +103,12 @@
 		
 		.section __ex_table,"a"
 		.align	3
-		.long	1001b, 1004b
-		.long	1002b, 1004b
-		.long	1003b, 1004b
+		.long	1001b, 1007b
+		.long	1002b, 1007b
+		.long	1003b, 1007b
+		.long	1004b, 1007b
+		.long	1005b, 1007b
+		.long	1006b, 1007b
 		.previous
 
 #define instr r4
diff -Nru a/arch/arm/mach-arc/small_page.c b/arch/arm/mach-arc/small_page.c
--- a/arch/arm/mach-arc/small_page.c	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/mach-arc/small_page.c	Tue Jul 16 16:49:41 2002
@@ -50,7 +50,7 @@
  */
 
 struct order {
-	struct page *queue;
+	struct list_head queue;
 	unsigned int mask;		/* (1 << shift) - 1		*/
 	unsigned int shift;		/* (1 << shift) size of page	*/
 	unsigned int block_mask;	/* nr_blocks - 1		*/
@@ -60,10 +60,10 @@
 
 static struct order orders[] = {
 #if PAGE_SIZE == 4096
-	{ NULL, 2047, 11,  1, 0x00000003 }
+	{ LIST_HEAD_INIT(orders[0].queue), 2047, 11,  1, 0x00000003 }
 #elif PAGE_SIZE == 32768
-	{ NULL, 2047, 11, 15, 0x0000ffff },
-	{ NULL, 8191, 13,  3, 0x0000000f }
+	{ LIST_HEAD_INIT(orders[0].queue), 2047, 11, 15, 0x0000ffff },
+	{ LIST_HEAD_INIT(orders[1].queue), 8191, 13,  3, 0x0000000f }
 #else
 #error unsupported page size
 #endif
@@ -75,70 +75,49 @@
 
 static spinlock_t small_page_lock = SPIN_LOCK_UNLOCKED;
 
-static void add_page_to_queue(struct page *page, struct page **p)
-{
-#ifdef PEDANTIC
-	if (page->pprev_hash)
-		PAGE_BUG(page);
-#endif
-	page->next_hash = *p;
-	if (*p)
-		(*p)->pprev_hash = &page->next_hash;
-	*p = page;
-	page->pprev_hash = p;
-}
-
-static void remove_page_from_queue(struct page *page)
-{
-	if (page->pprev_hash) {
-		if (page->next_hash)
-			page->next_hash->pprev_hash = page->pprev_hash;
-		*page->pprev_hash = page->next_hash;
-		page->pprev_hash = NULL;
-	}
-}
-
 static unsigned long __get_small_page(int priority, struct order *order)
 {
 	unsigned long flags;
 	struct page *page;
 	int offset;
 
-	if (!order->queue)
-		goto need_new_page;
+	do {
+		spin_lock_irqsave(&small_page_lock, flags);
+
+		if (list_empty(&order->queue))
+			goto need_new_page;
 
-	spin_lock_irqsave(&small_page_lock, flags);
-	page = order->queue;
+		page = list_entry(order->queue.next, struct page, list);
 again:
 #ifdef PEDANTIC
-	if (USED_MAP(page) & ~order->all_used)
-		PAGE_BUG(page);
+		if (USED_MAP(page) & ~order->all_used)
+			PAGE_BUG(page);
 #endif
-	offset = ffz(USED_MAP(page));
-	SET_USED(page, offset);
-	if (USED_MAP(page) == order->all_used)
-		remove_page_from_queue(page);
-	spin_unlock_irqrestore(&small_page_lock, flags);
+		offset = ffz(USED_MAP(page));
+		SET_USED(page, offset);
+		if (USED_MAP(page) == order->all_used)
+			list_del_init(&page->list);
+		spin_unlock_irqrestore(&small_page_lock, flags);
 
-	return (unsigned long) page_address(page) + (offset << order->shift);
+		return (unsigned long) page_address(page) + (offset << order->shift);
 
 need_new_page:
-	page = alloc_page(priority);
+		spin_unlock_irqrestore(&small_page_lock, flags);
+		page = alloc_page(priority);
+		spin_lock_irqsave(&small_page_lock, flags);
+
+		if (list_empty(&order->queue)) {
+			if (!page)
+				goto no_page;
+			SetPageReserved(page);
+			USED_MAP(page) = 0;
+			list_add(&page->list, &order->queue);
+			goto again;
+		}
 
-	spin_lock_irqsave(&small_page_lock, flags);
-	if (!order->queue) {
-		if (!page)
-			goto no_page;
-		SetPageReserved(page);
-		USED_MAP(page) = 0;
-		cli();
-		add_page_to_queue(page, &order->queue);
-	} else {
+		spin_unlock_irqrestore(&small_page_lock, flags);
 		__free_page(page);
-		cli();
-		page = order->queue;
-	}
-	goto again;
+	} while (1);
 
 no_page:
 	spin_unlock_irqrestore(&small_page_lock, flags);
@@ -173,7 +152,7 @@
 		spin_lock_irqsave(&small_page_lock, flags);
 
 		if (USED_MAP(page) == order->all_used)
-			add_page_to_queue(page, &order->queue);
+			list_add(&page->list, &order->queue);
 
 		if (!TEST_AND_CLEAR_USED(page, spage))
 			goto already_free;
@@ -189,7 +168,7 @@
 	/*
 	 * unlink the page from the small page queue and free it
 	 */
-	remove_page_from_queue(page);
+	list_del_init(&page->list);
 	spin_unlock_irqrestore(&small_page_lock, flags);
 	ClearPageReserved(page);
 	__free_page(page);
diff -Nru a/arch/arm/mach-footbridge/personal-pci.c b/arch/arm/mach-footbridge/personal-pci.c
--- a/arch/arm/mach-footbridge/personal-pci.c	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/mach-footbridge/personal-pci.c	Tue Jul 16 16:49:42 2002
@@ -53,4 +53,4 @@
 	return 0;
 }
 
-subsys_initcall(&personal_pci_init);
+subsys_initcall(personal_pci_init);
diff -Nru a/arch/arm/mach-integrator/arch.c b/arch/arm/mach-integrator/arch.c
--- a/arch/arm/mach-integrator/arch.c	Tue Jul 16 16:49:43 2002
+++ b/arch/arm/mach-integrator/arch.c	Tue Jul 16 16:49:43 2002
@@ -56,6 +56,7 @@
 	register_kmi(&integrator_keyboard);
 	register_kmi(&integrator_mouse);
 #endif
+	return 0;
 }
 
 __initcall(integrator_init);
diff -Nru a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c
--- a/arch/arm/mach-integrator/cpu.c	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/mach-integrator/cpu.c	Tue Jul 16 16:49:42 2002
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2001 Deep Blue Solutions Ltd.
  *
- *  $Id: cpu.c,v 1.4 2002/05/29 11:41:55 rmk Exp $
+ *  $Id: cpu.c,v 1.5 2002/07/06 16:53:17 rmk Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -121,8 +121,16 @@
 	cpu_freq_khz = vco_to_freq(vco, 1);
 
 #ifdef CONFIG_CPU_FREQ
-	cpufreq_init(cpu_freq_khz, 1000, 0);
-	cpufreq_setfunctions(integrator_validatespeed, integrator_setspeed);
+	{
+		struct cpufreq_driver cpufreq_driver;
+
+		cpufreq_driver.freq.min = 12000;
+		cpufreq_driver.freq.max = 160000;
+		cpufreq_driver.freq.cur = cpu_freq_khz;
+		cpufreq_driver.validate = &integrator_validatespeed;
+		cpufreq_driver.setspeed = &integrator_setspeed;
+		cpufreq_register(cpufreq_driver);
+	}
 #endif
 
 	cm_stat = __raw_readl(CM_STAT);
diff -Nru a/arch/arm/mach-iop310/iq80310-pci.c b/arch/arm/mach-iop310/iq80310-pci.c
--- a/arch/arm/mach-iop310/iq80310-pci.c	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/mach-iop310/iq80310-pci.c	Tue Jul 16 16:49:42 2002
@@ -25,10 +25,11 @@
  * format for those systems that do not already have PCI
  * interrupts properly routed.  We assume 1 <= pin <= 4
  */
-#define PCI_IRQ_TABLE_LOOKUP(minid,maxid)			 \
-({ int _ctl_ = -1;						 \
-   if (idsel >= minid && idsel <= maxid && pin >= 1 && pin <= 4) \
-      _ctl_ = pci_irq_table[idsel - minid][pin-1];		 \
+#define PCI_IRQ_TABLE_LOOKUP(minid,maxid)	\
+({ int _ctl_ = -1;				\
+   unsigned int _idsel = idsel - minid;		\
+   if (_idsel <= maxid)				\
+      _ctl_ = pci_irq_table[_idsel][pin-1];	\
    _ctl_; })
 
 #define INTA	IRQ_IQ80310_INTA
@@ -64,6 +65,8 @@
 {
 	irq_table *pci_irq_table;
 
+	BUG_ON(pin < 1 || pin > 4);
+
 	if (!system_rev) {
 		pci_irq_table = pci_pri_d_irq_table;
 	} else {
@@ -98,6 +101,8 @@
 iq80310_sec_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
 {
 	irq_table *pci_irq_table;
+
+	BUG_ON(pin < 1 || pin > 4);
 
 	if (!system_rev) {
 		pci_irq_table = pci_sec_d_irq_table;
diff -Nru a/arch/arm/mach-sa1100/adsbitsy.c b/arch/arm/mach-sa1100/adsbitsy.c
--- a/arch/arm/mach-sa1100/adsbitsy.c	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/mach-sa1100/adsbitsy.c	Tue Jul 16 16:49:41 2002
@@ -59,7 +59,7 @@
 	/*
 	 * Enable PWM control for LCD
 	 */
-	SKPCR |= SKPCR_PWMCLKEN;
+	sa1111_enable_device(SKPCR_PWMCLKEN);
 	SKPWM0 = 0x7F;				// VEE
 	SKPEN0 = 1;
 	SKPWM1 = 0x01;				// Backlight
diff -Nru a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
--- a/arch/arm/mach-sa1100/assabet.c	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/mach-sa1100/assabet.c	Tue Jul 16 16:49:41 2002
@@ -88,9 +88,21 @@
 		return -EINVAL;
 
 	/*
-	 * Set the IRQ edges
+	 * Ensure that these pins are set as outputs and are driving
+	 * logic 0.  This ensures that we won't inadvertently toggle
+	 * the WS latch in the CPLD, and we don't float causing
+	 * excessive power drain.  --rmk
 	 */
-	set_irq_type(IRQ_GPIO23, IRQT_RISING);	/* UCB1300 */
+	GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
+	GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
+
+	/*
+	 * Set up registers for sleep mode.
+	 */
+	PWER = PWER_GPIO0;
+	PGSR = 0;
+	PCFR = 0;
+	PSDR = 0;
 
 	sa1100fb_lcd_power = assabet_lcd_power;
 	sa1100fb_backlight_power = assabet_backlight_power;
@@ -254,13 +266,19 @@
 
 static void __init assabet_map_io(void)
 {
-	extern void neponset_map_io(void);
-
 	sa1100_map_io();
 	iotable_init(assabet_io_desc, ARRAY_SIZE(assabet_io_desc));
 
+	/*
+	 * Set SUS bit in SDCR0 so serial port 1 functions.
+	 * Its called GPCLKR0 in my SA1110 manual.
+	 */
+	Ser1SDCR0 |= SDCR0_SUS;
+
 	if (machine_has_neponset()) {
 #ifdef CONFIG_ASSABET_NEPONSET
+		extern void neponset_map_io(void);
+
 		/*
 		 * We map Neponset registers even if it isn't present since
 		 * many drivers will try to probe their stuff (and fail).
@@ -279,33 +297,11 @@
 		 */
 		sa1100_register_uart(0, 3);
 		sa1100_register_uart(2, 1);
-		/*
-		 * Set SUS bit in SDCR0 so serial port 1 functions.
-		 * Its called GPCLKR0 in my SA1110 manual.
-		 */
-		Ser1SDCR0 |= SDCR0_SUS;
 	} else {
 		sa1100_register_uart_fns(&assabet_port_fns);
 		sa1100_register_uart(0, 1);	/* com port */
 		sa1100_register_uart(2, 3);	/* radio module */
 	}
-
-	/*
-	 * Ensure that these pins are set as outputs and are driving
-	 * logic 0.  This ensures that we won't inadvertently toggle
-	 * the WS latch in the CPLD, and we don't float causing
-	 * excessive power drain.  --rmk
-	 */
-	GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
-	GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
-
-	/*
-	 * Set up registers for sleep mode.
-	 */
-	PWER = PWER_GPIO0;
-	PGSR = 0;
-	PCFR = 0;
-	PSDR = 0;
 }
 
 
diff -Nru a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c
--- a/arch/arm/mach-sa1100/cpu-sa1100.c	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/mach-sa1100/cpu-sa1100.c	Tue Jul 16 16:49:41 2002
@@ -92,7 +92,7 @@
 
 extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
 extern unsigned int sa11x0_validatespeed(unsigned int khz);
-
+extern unsigned int sa11x0_getspeed(void);
 
 typedef struct {
 	int speed;
@@ -187,7 +187,7 @@
 static int sa1100_dram_notifier(struct notifier_block *nb, 
 				unsigned long val, void *data)
 {
-	struct cpufreq_info *ci = data;
+	struct cpufreq_freqs *ci = data;
 	
 	switch(val) {
 	case CPUFREQ_MINMAX:
@@ -195,13 +195,13 @@
 		break;
 
 	case CPUFREQ_PRECHANGE:
-		if(ci->new_freq > ci->old_freq)
-			sa1100_update_dram_timings(ci->old_freq, ci->new_freq);
+		if(ci->new > ci->cur)
+			sa1100_update_dram_timings(ci->cur, ci->new);
 		break;
 
 	case CPUFREQ_POSTCHANGE:
-		if(ci->new_freq < ci->old_freq)
-			sa1100_update_dram_timings(ci->old_freq, ci->new_freq);
+		if(ci->new < ci->cur)
+			sa1100_update_dram_timings(ci->cur, ci->new);
 		break;
 		
 	default:
@@ -230,9 +230,19 @@
 	int ret = -ENODEV;
 
 	if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID) {
+		cpufreq_driver_t cpufreq_driver;
+
 		ret = cpufreq_register_notifier(&sa1100_dram_block);
+		if (ret)
+			return ret;
+
+		cpufreq_driver.freq.min = 59000;
+		cpufreq_driver.freq.max = 287000;
+		cpufreq_driver.freq.cur = sa11x0_getspeed();
+		cpufreq_driver.validate = &sa11x0_validatespeed;
+		cpufreq_driver.setspeed = &sa1100_setspeed;
 
-		cpufreq_setfunctions(sa11x0_validatespeed, sa1100_setspeed);
+		ret = cpufreq_register(cpufreq_driver);<
 	}
 
 	return ret;
diff -Nru a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c
--- a/arch/arm/mach-sa1100/cpu-sa1110.c	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/mach-sa1100/cpu-sa1110.c	Tue Jul 16 16:49:41 2002
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2001 Russell King
  *
- *  $Id: cpu-sa1110.c,v 1.8 2002/01/09 17:13:27 rmk Exp $
+ *  $Id: cpu-sa1110.c,v 1.9 2002/07/06 16:53:18 rmk Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -31,6 +31,7 @@
 
 extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
 extern unsigned int sa11x0_validatespeed(unsigned int khz);
+extern unsigned int sa11x0_getspeed(void);
 
 struct sdram_params {
 	u_char  rows;		/* bits				 */
@@ -88,6 +89,16 @@
 	cas_latency:	     3,
 };
 
+static struct sdram_params wbond_w982516ah75l_cl3_params __initdata = {
+	rows:		    16,
+	tck:		     8,
+	trcd:		    20,
+	trp:		    20,
+	twr:		     8,
+	refresh:	 64000,
+	cas_latency:	     3,
+};
+
 static struct sdram_params sdram_params;
 
 /*
@@ -287,6 +298,8 @@
 		sdram = &samsung_km416s4030ct;
 
 	if (sdram) {
+		struct cpufreq_driver cpufreq_driver;
+
 		printk(KERN_DEBUG "SDRAM: tck: %d trcd: %d trp: %d"
 			" twr: %d refresh: %d cas_latency: %d\n",
 			sdram->tck, sdram->trcd, sdram->trp,
@@ -294,8 +307,15 @@
 
 		memcpy(&sdram_params, sdram, sizeof(sdram_params));
 
-		sa1110_setspeed(cpufreq_get(0));
-		cpufreq_setfunctions(sa11x0_validatespeed, sa1110_setspeed);
+		sa1110_setspeed(sa11x0_getspeed());
+
+		cpufreq_driver.freq.min = 59000;
+		cpufreq_driver.freq.max = 287000;
+		cpufreq_driver.freq.cur = sa11x0_getspeed();
+		cpufreq_driver.validate = &sa11x0_validatespeed;
+		cpufreq_driver.setspeed = &sa1110_setspeed;
+
+		return cpufreq_register(cpufreq_driver);
 	}
 
 	return 0;
diff -Nru a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
--- a/arch/arm/mach-sa1100/generic.c	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/mach-sa1100/generic.c	Tue Jul 16 16:49:42 2002
@@ -76,13 +76,10 @@
 	return cclk_frequency_100khz[sa11x0_freq_to_ppcr(khz)] * 100;
 }
 
-static int __init sa11x0_init_clock(void)
+unsigned int sa11x0_getspeed(void)
 {
-	cpufreq_init(cclk_frequency_100khz[PPCR & 0xf] * 100, 59000, 287000);
-	return 0;
+	return cclk_frequency_100khz[PPCR & 0xf] * 100;
 }
-
-__initcall(sa11x0_init_clock);
 #else
 /*
  * We still need to provide this so building without cpufreq works.
@@ -100,7 +97,7 @@
 static void sa1100_power_off(void)
 {
 	mdelay(100);
-	cli();
+	local_irq_disable();
 	/* disable internal oscillator, float CS lines */
 	PCFR = (PCFR_OPDE | PCFR_FP | PCFR_FS);
 	/* enable wake-up on GPIO0 (Assabet...) */
diff -Nru a/arch/arm/mach-sa1100/graphicsmaster.c b/arch/arm/mach-sa1100/graphicsmaster.c
--- a/arch/arm/mach-sa1100/graphicsmaster.c	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/mach-sa1100/graphicsmaster.c	Tue Jul 16 16:49:42 2002
@@ -49,7 +49,7 @@
 	/*
 	 * Enable PWM control for LCD
 	 */
-	SKPCR |= SKPCR_PWMCLKEN;
+	sa1111_enable_device(SKPCR_PWMCLKEN);
 	SKPWM0 = 0x7F;				// VEE
 	SKPEN0 = 1;
 	SKPWM1 = 0x01;				// Backlight
diff -Nru a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
--- a/arch/arm/mach-sa1100/irq.c	Tue Jul 16 16:49:43 2002
+++ b/arch/arm/mach-sa1100/irq.c	Tue Jul 16 16:49:43 2002
@@ -55,6 +55,12 @@
 	else
 		mask = GPIO11_27_MASK(irq);
 
+	if (type == IRQT_PROBE) {
+		if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask)
+			return 0;
+		type = __IRQT_RISEDGE | __IRQT_FALEDGE;
+	}
+
 	if (type & __IRQT_RISEDGE) {
 		GPIO_IRQ_rising_edge |= mask;
 	} else
diff -Nru a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c
--- a/arch/arm/mach-sa1100/pm.c	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/mach-sa1100/pm.c	Tue Jul 16 16:49:41 2002
@@ -73,7 +73,7 @@
 {
 	unsigned long sleep_save[SLEEP_SAVE_SIZE];
 
-	cli();
+	local_irq_disable();
 
 	leds_event(led_stop);
 
@@ -157,7 +157,7 @@
 
 	leds_event(led_start);
 
-	sti();
+	local_irq_enable();
 
 	/*
 	 * Restore the CPU frequency settings.
diff -Nru a/arch/arm/mach-sa1100/sa1111.c b/arch/arm/mach-sa1100/sa1111.c
--- a/arch/arm/mach-sa1100/sa1111.c	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/mach-sa1100/sa1111.c	Tue Jul 16 16:49:42 2002
@@ -117,11 +117,12 @@
 {
 	unsigned int mask = SA1111_IRQMASK_LO(irq);
 
+	if (flags == IRQT_PROBE)
+		return 0;
+
 	if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0)
 		return -EINVAL;
 
-	printk("IRQ%d: %s edge\n", irq, flags & __IRQT_RISEDGE ? "rising" : "falling");
-
 	if (flags & __IRQT_RISEDGE)
 		INTPOL0 &= ~mask;
 	else
@@ -181,11 +182,12 @@
 {
 	unsigned int mask = SA1111_IRQMASK_HI(irq);
 
+	if (flags == IRQT_PROBE)
+		return 0;
+
 	if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0)
 		return -EINVAL;
 
-	printk("IRQ%d: %s edge\n", irq, flags & __IRQT_RISEDGE ? "rising" : "falling");
-
 	if (flags & __IRQT_RISEDGE)
 		INTPOL1 &= ~mask;
 	else
@@ -302,7 +304,7 @@
 	/*
 	 * Probe for the chip.  Only touch the SBI registers.
 	 */
-	id = readl(sa->base + SA1111_SKID);
+	id = sa1111_readl(sa->base + SA1111_SKID);
 	if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
 		printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id);
 		ret = -ENODEV;
@@ -370,11 +372,11 @@
 	/*
 	 * Turn VCO on, and disable PLL Bypass.
 	 */
-	r = readl(sa->base + SA1111_SKCR);
+	r = sa1111_readl(sa->base + SA1111_SKCR);
 	r &= ~SKCR_VCO_OFF;
-	writel(r, sa->base + SA1111_SKCR);
+	sa1111_writel(r, sa->base + SA1111_SKCR);
 	r |= SKCR_PLL_BYPASS | SKCR_OE_EN;
-	writel(r, sa->base + SA1111_SKCR);
+	sa1111_writel(r, sa->base + SA1111_SKCR);
 
 	/*
 	 * Wait lock time.  SA1111 manual _doesn't_
@@ -386,7 +388,7 @@
 	 * Enable RCLK.  We also ensure that RDYEN is set.
 	 */
 	r |= SKCR_RCLKEN | SKCR_RDYEN;
-	writel(r, sa->base + SA1111_SKCR);
+	sa1111_writel(r, sa->base + SA1111_SKCR);
 
 	/*
 	 * Wait 14 RCLK cycles for the chip to finish coming out
@@ -397,7 +399,7 @@
 	/*
 	 * Ensure all clocks are initially off.
 	 */
-	writel(0, sa->base + SA1111_SKPCR);
+	sa1111_writel(0, sa->base + SA1111_SKPCR);
 
 	local_irq_restore(flags);
 }
@@ -406,16 +408,18 @@
 {
 	struct sa1111_device *sa = sa1111;
 	unsigned long flags;
+	unsigned int val;
 
 	local_irq_save(flags);
 
-	if (readl(sa->base + SA1111_SKPCR) & SKPCR_UCLKEN) {
+	if (sa1111_readl(sa->base + SA1111_SKPCR) & SKPCR_UCLKEN) {
 		local_irq_restore(flags);
 		printk("SA1111 doze mode refused\n");
 		return;
 	}
 
-	writel(readl(sa->base + SA1111_SKCR) & ~SKCR_RCLKEN, sa->base + SA1111_SKCR);
+	val = sa1111_readl(sa->base + SA1111_SKCR);
+	sa1111_writel(val & ~SKCR_RCLKEN, sa->base + SA1111_SKCR);
 	local_irq_restore(flags);
 }
 
@@ -430,9 +434,37 @@
 	if (cas_latency == 3)
 		smcr |= SMCR_CLAT;
 
-	writel(smcr, sa->base + SA1111_SMCR);
+	sa1111_writel(smcr, sa->base + SA1111_SMCR);
+}
+
+EXPORT_SYMBOL(sa1111_wake);
+EXPORT_SYMBOL(sa1111_doze);
+
+void sa1111_enable_device(unsigned int mask)
+{
+	struct sa1111_device *sa = sa1111;
+	unsigned int val;
+
+	preempt_disable();
+	val = sa1111_readl(sa->base + SA1111_SKPCR);
+	sa1111_writel(val | mask, sa->base + SA1111_SKPCR);
+	preempt_enable();
+}
+
+void sa1111_disable_device(unsigned int mask)
+{
+	struct sa1111_device *sa = sa1111;
+	unsigned int val;
+
+	preempt_disable();
+	val = sa1111_readl(sa->base + SA1111_SKPCR);
+	sa1111_writel(val & ~mask, sa->base + SA1111_SKPCR);
+	preempt_enable();
 }
 
+EXPORT_SYMBOL(sa1111_enable_device);
+EXPORT_SYMBOL(sa1111_disable_device);
+
 /* According to the "Intel StrongARM SA-1111 Microprocessor Companion
  * Chip Specification Update" (June 2000), erratum #7, there is a
  * significant bug in Serial Audio Controller DMA. If the SAC is
@@ -527,7 +559,7 @@
 	 * We only need to turn on DCLK whenever we want to use the
 	 * DMA.  It can otherwise be held firmly in the off position.
 	 */
-	SKPCR |= SKPCR_DCLKEN;
+	sa1111_enable_device(SKPCR_DCLKEN);
 
 	/*
 	 * Enable the SA1110 memory bus request and grant signals.
diff -Nru a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
--- a/arch/arm/mach-sa1100/shannon.c	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/mach-sa1100/shannon.c	Tue Jul 16 16:49:41 2002
@@ -13,6 +13,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
+#include <asm/arch/shannon.h>
 
 #include "generic.h"
 
@@ -23,13 +24,16 @@
 
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
+
 	Ser1SDCR0 |= SDCR0_SUS;
 	GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
-	GPDR |= GPIO_UART_TXD;
+	GPDR |= GPIO_UART_TXD | SHANNON_GPIO_CODEC_RESET;
 	GPDR &= ~GPIO_UART_RXD;
 	PPAR |= PPAR_UPR;
 
-	set_GPIO_IRQ_edge(SHANNON_GPIO_IRQ_CODEC);
+	/* reset the codec */
+	GPCR = SHANNON_GPIO_CODEC_RESET;
+	GPSR = SHANNON_GPIO_CODEC_RESET;
 }
 
 MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
diff -Nru a/arch/arm/mach-sa1100/sleep.S b/arch/arm/mach-sa1100/sleep.S
--- a/arch/arm/mach-sa1100/sleep.S	Tue Jul 16 16:49:43 2002
+++ b/arch/arm/mach-sa1100/sleep.S	Tue Jul 16 16:49:43 2002
@@ -44,7 +44,8 @@
 	mrc 	p15, 0, r7, c1, c0, 0		@ control reg
 
 	@ store them plus current virtual stack ptr on stack
-	stmfd	sp!, {r4 - r7, sp}
+	mov	r8, sp
+	stmfd	sp!, {r4 - r8}
 
 	@ preserve phys address of stack
 	mov	r0, sp
diff -Nru a/arch/arm/mach-sa1100/system3.c b/arch/arm/mach-sa1100/system3.c
--- a/arch/arm/mach-sa1100/system3.c	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/mach-sa1100/system3.c	Tue Jul 16 16:49:42 2002
@@ -309,7 +309,7 @@
 	PTCTRL0_set( PT_CTRL0_LCD_EN );
 
 	/* brightness / contrast */
-	SKPCR |= SKPCR_PWMCLKEN;
+	sa1111_enable_device(SKPCR_PWMCLKEN);
 	PB_DDR = 0xFFFFFFFF;
 	SKPEN0 = 1;
 	SKPEN1 = 1;
@@ -325,7 +325,7 @@
 	PTCTRL0_clear( PT_CTRL0_LCD_EN );
 	SKPEN0 = 0;
 	SKPEN1 = 0;
-	SKPCR &= ~SKPCR_PWMCLKEN;
+	sa1111_disable_device(SKPCR_PWMCLKEN);
 }
 
 /**
diff -Nru a/arch/arm/mach-sa1100/xp860.c b/arch/arm/mach-sa1100/xp860.c
--- a/arch/arm/mach-sa1100/xp860.c	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/mach-sa1100/xp860.c	Tue Jul 16 16:49:42 2002
@@ -22,7 +22,7 @@
 
 static void xp860_power_off(void)
 {
-	cli();
+	local_irq_disable();
 	GPDR |= GPIO_GPIO20;
 	GPSR = GPIO_GPIO20;
 	mdelay(1000);
diff -Nru a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
--- a/arch/arm/mm/Makefile	Tue Jul 16 16:49:43 2002
+++ b/arch/arm/mm/Makefile	Tue Jul 16 16:49:43 2002
@@ -42,7 +42,7 @@
 
 # ARMv5
 p-$(CONFIG_CPU_ARM926T)	+= proc-arm926.o  tlb-v4wb.o copypage-v4wb.o abort-ev5ej.o
-p-$(CONFIG_CPU_XSCALE)	+= proc-xscale.o  tlb-v4wb.o copypage-v5te.o abort-ev4t.o  minicache.o
+p-$(CONFIG_CPU_XSCALE)	+= proc-xscale.o  tlb-v4wb.o copypage-xscale.o abort-xscale.o minicache.o
 
 obj-y		+= $(sort $(p-y))
 
diff -Nru a/arch/arm/mm/abort-ev4.S b/arch/arm/mm/abort-ev4.S
--- a/arch/arm/mm/abort-ev4.S	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/mm/abort-ev4.S	Tue Jul 16 16:49:42 2002
@@ -7,7 +7,7 @@
  *         : r3 = saved SPSR
  *
  * Returns : r0 = address of abort
- *	   : r1 = FSR, bit 8 = write
+ *	   : r1 = FSR, bit 11 = write
  *	   : r2-r8 = corrupted
  *	   : r9 = preserved
  *	   : sp = pointer to registers
@@ -22,8 +22,9 @@
 	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
 	ldr	r3, [r2]			@ read aborted ARM instruction
+	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
 	tst	r3, #1 << 20			@ L = 1 -> write?
-	orreq	r1, r1, #1 << 8			@ yes.
+	orreq	r1, r1, #1 << 11		@ yes.
 	mov	pc, lr
 
 
diff -Nru a/arch/arm/mm/abort-ev4t.S b/arch/arm/mm/abort-ev4t.S
--- a/arch/arm/mm/abort-ev4t.S	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/mm/abort-ev4t.S	Tue Jul 16 16:49:42 2002
@@ -7,7 +7,7 @@
  *         : r3 = saved SPSR
  *
  * Returns : r0 = address of abort
- *	   : r1 = FSR, bit 8 = write
+ *	   : r1 = FSR, bit 11 = write
  *	   : r2-r8 = corrupted
  *	   : r9 = preserved
  *	   : sp = pointer to registers
@@ -24,8 +24,8 @@
 	tst	r3, #PSR_T_BIT
 	ldrneh	r3, [r2]			@ read aborted thumb instruction
 	ldreq	r3, [r2]			@ read aborted ARM instruction
-	bic	r1, r1, #1 << 8
+	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
 	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
 	tst	r3, #1 << 20			@ check write
-	orreq	r1, r1, #1 << 8
+	orreq	r1, r1, #1 << 11
 	mov	pc, lr
diff -Nru a/arch/arm/mm/abort-ev5ej.S b/arch/arm/mm/abort-ev5ej.S
--- a/arch/arm/mm/abort-ev5ej.S	Tue Jul 16 16:49:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,35 +0,0 @@
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-/*
- * Function: v5ej_early_abort
- *
- * Params  : r2 = address of aborted instruction
- *         : r3 = saved SPSR
- *
- * Returns : r0 = address of abort
- *	   : r1 = FSR, bit 8 = write
- *	   : r2-r8 = corrupted
- *	   : r9 = preserved
- *	   : sp = pointer to registers
- *
- * Purpose : obtain information about current aborted instruction.
- * Note: we read user space.  This means we might cause a data
- * abort here if the I-TLB and D-TLB aren't seeing the same
- * picture.  Unfortunately, this does happen.  We live with it.
- */
-	.align	5
-ENTRY(v5ej_early_abort)
-	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
-	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
-	tst	r3, #PSR_J_BIT
-	orrne	r1, r1, #1 << 8			@ always assume write
-	bne	1f
-	tst	r3, #PSR_T_BIT
-	ldrneh	r3, [r2]			@ read aborted thumb instruction
-	ldreq	r3, [r2]			@ read aborted ARM instruction
-	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
-	tst	r3, #1 << 20			@ L = 1 -> write
-	orreq	r1, r1, #1 << 8			@ yes.
-1:	mov	pc, lr
-
-
diff -Nru a/arch/arm/mm/abort-ev5tej.S b/arch/arm/mm/abort-ev5tej.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mm/abort-ev5tej.S	Tue Jul 16 16:49:41 2002
@@ -0,0 +1,36 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: v5tej_early_abort
+ *
+ * Params  : r2 = address of aborted instruction
+ *         : r3 = saved SPSR
+ *
+ * Returns : r0 = address of abort
+ *	   : r1 = FSR, bit 11 = write
+ *	   : r2-r8 = corrupted
+ *	   : r9 = preserved
+ *	   : sp = pointer to registers
+ *
+ * Purpose : obtain information about current aborted instruction.
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
+ */
+	.align	5
+ENTRY(v5tej_early_abort)
+	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
+	tst	r3, #PSR_J_BIT
+	orrne	r1, r1, #1 << 11		@ always assume write
+	bne	1f
+	tst	r3, #PSR_T_BIT
+	ldrneh	r3, [r2]			@ read aborted thumb instruction
+	ldreq	r3, [r2]			@ read aborted ARM instruction
+	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
+	tst	r3, #1 << 20			@ L = 1 -> write
+	orreq	r1, r1, #1 << 11		@ yes.
+1:	mov	pc, lr
+
+
diff -Nru a/arch/arm/mm/abort-lv4t.S b/arch/arm/mm/abort-lv4t.S
--- a/arch/arm/mm/abort-lv4t.S	Tue Jul 16 16:49:43 2002
+++ b/arch/arm/mm/abort-lv4t.S	Tue Jul 16 16:49:43 2002
@@ -7,7 +7,7 @@
  *         : r3 = saved SPSR
  *
  * Returns : r0 = address of abort
- *	   : r1 = FSR, bit 8 = writing
+ *	   : r1 = FSR, bit 11 = write
  *	   : r2-r8 = corrupted
  *	   : r9 = preserved
  *	   : sp = pointer to registers
@@ -21,10 +21,11 @@
 	tst	r3, #PSR_T_BIT			@ check for thumb mode
 	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
 	ldreq	r8, [r2]			@ read arm instruction
 	bne	.data_thumb_abort
 	tst	r8, #1 << 20			@ L = 1 -> write?
-	orreq	r1, r1, #1 << 8			@ yes.
+	orreq	r1, r1, #1 << 11		@ yes.
 	and	r7, r8, #15 << 24
 	add	pc, pc, r7, lsr #22		@ Now branch to the relevant processing routine
 	nop
diff -Nru a/arch/arm/mm/abort-xscale.S b/arch/arm/mm/abort-xscale.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mm/abort-xscale.S	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,34 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: xscale_abort
+ *
+ * Params  : r2 = address of aborted instruction
+ *         : r3 = saved SPSR
+ *
+ * Returns : r0 = address of abort
+ *	   : r1 = FSR, bit 11 = write
+ *	   : r2-r8 = corrupted
+ *	   : r9 = preserved
+ *	   : sp = pointer to registers
+ *
+ * Purpose : obtain information about current aborted instruction.
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
+ *
+ * Note: Xscale is contains non-standard architecture extensions.
+ * It requires its own early abort handler
+ */
+	.align	5
+ENTRY(xscale_abort)
+	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+	tst	r3, #PSR_T_BIT
+	ldrneh	r3, [r2]			@ read aborted thumb instruction
+	ldreq	r3, [r2]			@ read aborted ARM instruction
+	bic	r1, r1, #1 << 11		@ clear bits 11 of FSR
+	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
+	tst	r3, #1 << 20			@ check write
+	orreq	r1, r1, #1 << 11
+	mov	pc, lr
diff -Nru a/arch/arm/mm/copypage-v5te.S b/arch/arm/mm/copypage-v5te.S
--- a/arch/arm/mm/copypage-v5te.S	Tue Jul 16 16:49:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,85 +0,0 @@
-/*
- *  linux/arch/arm/lib/copypage-armv5te.S
- *
- *  Copyright (C) 2001 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/linkage.h>
-#include <asm/constants.h>
-
-/*
- * General note:
- *  We don't really want write-allocate cache behaviour for these functions
- *  since that will just eat through 8K of the cache.
- */
-
-	.text
-	.align	5
-/*
- * ARMv5TE optimised copy_user_page
- *  r0 = destination
- *  r1 = source
- *  r2 = virtual user address of ultimate destination page
- *
- * The source page may have some clean entries in the cache already, but we
- * can safely ignore them - break_cow() will flush them out of the cache
- * if we eventually end up using our copied page.
- *
- * What we could do is use the mini-cache to buffer reads from the source
- * page.  We rely on the mini-cache being smaller than one page, so we'll
- * cycle through the complete cache anyway.
- */
-ENTRY(v5te_mc_copy_user_page)
-	stmfd	sp!, {r4, r5, lr}
-	mov	r5, r0
-	mov	r0, r1
-	bl	map_page_minicache
-	mov	r1, r5
-	mov	lr, #PAGE_SZ/32
-
-1:	mov	ip, r1
-	ldrd	r2, [r0], #8
-	ldrd	r4, [r0], #8
-	strd	r2, [r1], #8
-	ldrd	r2, [r0], #8
-	strd	r4, [r1], #8
-	ldrd	r4, [r0], #8
-	strd	r2, [r1], #8
-	strd	r4, [r1], #8
-	mcr	p15, 0, ip, c7, c10, 1		@ clean D line
-	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line
-	subs	lr, lr, #1
-	bne	1b
-
-	ldmfd	sp!, {r4, r5, pc}
-
-	.align	5
-/*
- * ARMv5TE optimised clear_user_page
- *  r0 = destination
- *  r1 = virtual user address of ultimate destination page
- */
-ENTRY(v5te_mc_clear_user_page)
-	str	lr, [sp, #-4]!
-	mov	r1, #PAGE_SZ/32
-	mov	r2, #0
-	mov	r3, #0
-1:	mov	ip, r0
-	strd	r2, [r0], #8
-	strd	r2, [r0], #8
-	strd	r2, [r0], #8
-	strd	r2, [r0], #8
-	mcr	p15, 0, ip, c7, c10, 1		@ clean D line
-	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line
-	subs	r1, r1, #1
-	bne	1b
-	ldr	pc, [sp], #4
-
-	.section ".text.init", #alloc, #execinstr
-
-ENTRY(v5te_mc_user_fns)
-	.long	v5te_mc_clear_user_page
-	.long	v5te_mc_copy_user_page
diff -Nru a/arch/arm/mm/copypage-xscale.S b/arch/arm/mm/copypage-xscale.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mm/copypage-xscale.S	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,85 @@
+/*
+ *  linux/arch/arm/lib/copypage-xscale.S
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <asm/constants.h>
+
+/*
+ * General note:
+ *  We don't really want write-allocate cache behaviour for these functions
+ *  since that will just eat through 8K of the cache.
+ */
+
+	.text
+	.align	5
+/*
+ * XScale optimised copy_user_page
+ *  r0 = destination
+ *  r1 = source
+ *  r2 = virtual user address of ultimate destination page
+ *
+ * The source page may have some clean entries in the cache already, but we
+ * can safely ignore them - break_cow() will flush them out of the cache
+ * if we eventually end up using our copied page.
+ *
+ * What we could do is use the mini-cache to buffer reads from the source
+ * page.  We rely on the mini-cache being smaller than one page, so we'll
+ * cycle through the complete cache anyway.
+ */
+ENTRY(xscale_mc_copy_user_page)
+	stmfd	sp!, {r4, r5, lr}
+	mov	r5, r0
+	mov	r0, r1
+	bl	map_page_minicache
+	mov	r1, r5
+	mov	lr, #PAGE_SZ/32
+
+1:	mov	ip, r1
+	ldrd	r2, [r0], #8
+	ldrd	r4, [r0], #8
+	strd	r2, [r1], #8
+	ldrd	r2, [r0], #8
+	strd	r4, [r1], #8
+	ldrd	r4, [r0], #8
+	strd	r2, [r1], #8
+	strd	r4, [r1], #8
+	mcr	p15, 0, ip, c7, c10, 1		@ clean D line
+	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line
+	subs	lr, lr, #1
+	bne	1b
+
+	ldmfd	sp!, {r4, r5, pc}
+
+	.align	5
+/*
+ * XScale optimised clear_user_page
+ *  r0 = destination
+ *  r1 = virtual user address of ultimate destination page
+ */
+ENTRY(xscale_mc_clear_user_page)
+	str	lr, [sp, #-4]!
+	mov	r1, #PAGE_SZ/32
+	mov	r2, #0
+	mov	r3, #0
+1:	mov	ip, r0
+	strd	r2, [r0], #8
+	strd	r2, [r0], #8
+	strd	r2, [r0], #8
+	strd	r2, [r0], #8
+	mcr	p15, 0, ip, c7, c10, 1		@ clean D line
+	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line
+	subs	r1, r1, #1
+	bne	1b
+	ldr	pc, [sp], #4
+
+	.section ".text.init", #alloc, #execinstr
+
+ENTRY(xscale_mc_user_fns)
+	.long	xscale_mc_clear_user_page
+	.long	xscale_mc_copy_user_page
diff -Nru a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
--- a/arch/arm/mm/fault-armv.c	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/mm/fault-armv.c	Tue Jul 16 16:49:41 2002
@@ -47,6 +47,10 @@
 	int	sig;
 	const char *name;
 } fsr_info[] = {
+	/*
+	 * The following are the standard ARMv3 and ARMv4 aborts.  ARMv5
+	 * defines these to be "precise" aborts.
+	 */
 	{ do_bad,		SIGSEGV, "vector exception"		   },
 	{ do_bad,		SIGILL,	 "alignment exception"		   },
 	{ do_bad,		SIGKILL, "terminal exception"		   },
@@ -62,14 +66,35 @@
 	{ do_bad,		SIGBUS,	 "external abort on translation"   },
 	{ do_sect_fault,	SIGSEGV, "section permission fault"	   },
 	{ do_bad,		SIGBUS,	 "external abort on translation"   },
-	{ do_page_fault,	SIGSEGV, "page permission fault"	   }
+	{ do_page_fault,	SIGSEGV, "page permission fault"	   },
+	/*
+	 * The following are "imprecise" aborts, which are signalled by bit
+	 * 10 of the FSR, and may not be recoverable.  These are only
+	 * supported if the CPU abort handler supports bit 10.
+	 */
+	{ do_bad,		SIGBUS,  "unknown 16"			   },
+	{ do_bad,		SIGBUS,  "unknown 17"			   },
+	{ do_bad,		SIGBUS,  "unknown 18"			   },
+	{ do_bad,		SIGBUS,  "unknown 19"			   },
+	{ do_bad,		SIGBUS,  "lock abort"			   }, /* xscale */
+	{ do_bad,		SIGBUS,  "unknown 21"			   },
+	{ do_bad,		SIGBUS,  "imprecise external abort"	   }, /* xscale */
+	{ do_bad,		SIGBUS,  "unknown 23"			   },
+	{ do_bad,		SIGBUS,  "dcache parity error"		   }, /* xscale */
+	{ do_bad,		SIGBUS,  "unknown 25"			   },
+	{ do_bad,		SIGBUS,  "unknown 26"			   },
+	{ do_bad,		SIGBUS,  "unknown 27"			   },
+	{ do_bad,		SIGBUS,  "unknown 28"			   },
+	{ do_bad,		SIGBUS,  "unknown 29"			   },
+	{ do_bad,		SIGBUS,  "unknown 30"			   },
+	{ do_bad,		SIGBUS,  "unknown 31"			   }
 };
 
 void __init
 hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
 		int sig, const char *name)
 {
-	if (nr >= 0 && nr < 16) {
+	if (nr >= 0 && nr < ARRAY_SIZE(fsr_info)) {
 		fsr_info[nr].fn   = fn;
 		fsr_info[nr].sig  = sig;
 		fsr_info[nr].name = name;
@@ -82,7 +107,7 @@
 asmlinkage void
 do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
-	const struct fsr_info *inf = fsr_info + (fsr & 15);
+	const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6);
 
 	if (!inf->fn(addr, fsr, regs))
 		return;
diff -Nru a/arch/arm/mm/fault-common.c b/arch/arm/mm/fault-common.c
--- a/arch/arm/mm/fault-common.c	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/mm/fault-common.c	Tue Jul 16 16:49:41 2002
@@ -34,12 +34,10 @@
 #define READ_FAULT(m)		(!((m) & FAULT_CODE_WRITE))
 #else
 /*
- * On 32-bit processors, we define "mode" to be zero when reading,
- * non-zero when writing.  This now ties up nicely with the polarity
- * of the 26-bit machines, and also means that we avoid the horrible
- * gcc code for "int val = !other_val;".
+ * "code" is actually the FSR register.  Bit 11 set means the
+ * isntruction was performing a write.
  */
-#define DO_COW(code)		((code) & (1 << 8))
+#define DO_COW(code)		((code) & (1 << 11))
 #define READ_FAULT(code)	(!DO_COW(code))
 #endif
 
@@ -56,7 +54,7 @@
 
 	printk(KERN_ALERT "pgd = %p\n", mm->pgd);
 	pgd = pgd_offset(mm, addr);
-	printk(KERN_ALERT "*pgd = %08lx", pgd_val(*pgd));
+	printk(KERN_ALERT "*pgd=%08lx", pgd_val(*pgd));
 
 	do {
 		pmd_t *pmd;
@@ -71,7 +69,9 @@
 		}
 
 		pmd = pmd_offset(pgd, addr);
-		printk(", *pmd = %08lx", pmd_val(*pmd));
+#if PTRS_PER_PMD != 1
+		printk(", *pmd=%08lx", pmd_val(*pmd));
+#endif
 
 		if (pmd_none(*pmd))
 			break;
@@ -84,9 +84,9 @@
 #ifndef CONFIG_HIGHMEM
 		/* We must not map this if we have highmem enabled */
 		pte = pte_offset_map(pmd, addr);
-		printk(", *pte = %08lx", pte_val(*pte));
+		printk(", *pte=%08lx", pte_val(*pte));
 #ifdef CONFIG_CPU_32
-		printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE]));
+		printk(", *ppte=%08lx", pte_val(pte[-PTRS_PER_PTE]));
 #endif
 		pte_unmap(pte);
 #endif
diff -Nru a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
--- a/arch/arm/mm/proc-arm1020.S	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/mm/proc-arm1020.S	Tue Jul 16 16:49:41 2002
@@ -394,8 +394,6 @@
  */
 	.align	5
 ENTRY(cpu_arm1020_set_pte)
-	tst	r0, #2048
-	streq	r0, [r0, -r0]			@ BUG_ON
 	str	r1, [r0], #-2048		@ linux version
 
 	eor	r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
@@ -553,7 +551,7 @@
 	b	__arm1020_setup
 	.long	cpu_arch_name
 	.long	cpu_elf_name
-	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
 	.long	cpu_arm1020_info
 	.long	arm1020_processor_functions
 	.long	v4wbi_tlb_fns
diff -Nru a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S
--- a/arch/arm/mm/proc-arm6_7.S	Tue Jul 16 16:49:43 2002
+++ b/arch/arm/mm/proc-arm6_7.S	Tue Jul 16 16:49:43 2002
@@ -272,8 +272,6 @@
 		.align	5
 ENTRY(cpu_arm6_set_pte)
 ENTRY(cpu_arm7_set_pte)
-		tst	r0, #2048
-		streq	r0, [r0, -r0]			@ BUG_ON
 		str	r1, [r0], #-2048		@ linux version
 
 		eor	r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
diff -Nru a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S
--- a/arch/arm/mm/proc-arm720.S	Tue Jul 16 16:49:43 2002
+++ b/arch/arm/mm/proc-arm720.S	Tue Jul 16 16:49:43 2002
@@ -135,8 +135,6 @@
  */
 		.align	5
 ENTRY(cpu_arm720_set_pte)
-		tst	r0, #2048
-		streq	r0, [r0, -r0]			@ BUG_ON
 		str	r1, [r0], #-2048		@ linux version
 
 		eor	r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
@@ -257,7 +255,7 @@
 		b	__arm720_setup				@ cpu_flush
 		.long	cpu_arch_name				@ arch_name
 		.long	cpu_elf_name				@ elf_name
-		.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_26BIT	@ elf_hwcap
+		.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB	@ elf_hwcap
 		.long	cpu_arm720_info				@ info
 		.long	arm720_processor_functions
 		.long	v4_tlb_fns
diff -Nru a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
--- a/arch/arm/mm/proc-arm920.S	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/mm/proc-arm920.S	Tue Jul 16 16:49:41 2002
@@ -539,7 +539,7 @@
 	b	__arm920_setup
 	.long	cpu_arch_name
 	.long	cpu_elf_name
-	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
 	.long	cpu_arm920_info
 	.long	arm920_processor_functions
 	.long	v4wbi_tlb_fns
diff -Nru a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S
--- a/arch/arm/mm/proc-arm922.S	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/mm/proc-arm922.S	Tue Jul 16 16:49:42 2002
@@ -395,8 +395,6 @@
  */
 	.align	5
 ENTRY(cpu_arm922_set_pte)
-	tst	r0, #2048
-	streq	r0, [r0, -r0]			@ BUG_ON
 	str	r1, [r0], #-2048		@ linux version
 
 	eor	r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
@@ -540,7 +538,7 @@
 	b	__arm922_setup
 	.long	cpu_arch_name
 	.long	cpu_elf_name
-	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
 	.long	cpu_arm922_info
 	.long	arm922_processor_functions
 	.long	v4wbi_tlb_fns
diff -Nru a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
--- a/arch/arm/mm/proc-arm926.S	Tue Jul 16 16:49:41 2002
+++ b/arch/arm/mm/proc-arm926.S	Tue Jul 16 16:49:41 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/arm/mm/arm926.S: MMU functions for ARM926EJ-S
+ *  linux/arch/arm/mm/proc-arm926.S: MMU functions for ARM926EJ-S
  *
  *  Copyright (C) 1999-2001 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
@@ -378,8 +378,6 @@
  */
 	.align	5
 ENTRY(cpu_arm926_set_pte)
-	tst	r0, #2048
-	streq	r0, [r0, -r0]			@ BUG_ON
 	str	r1, [r0], #-2048		@ linux version
 
 	eor	r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
@@ -442,7 +440,7 @@
 	mcr	p15, 0, r4, c2, c0		@ load page table pointer
 
 
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
 	mov	r0, #4				@ disable write-back on caches explicitly
 	mcr	p15, 7, r0, c15, c0, 0
 #endif 
@@ -483,7 +481,7 @@
  */
 	.type	arm926_processor_functions, #object
 arm926_processor_functions:
-	.word	v5ej_early_abort
+	.word	v5tej_early_abort
 	.word	cpu_arm926_check_bugs
 	.word	cpu_arm926_proc_init
 	.word	cpu_arm926_proc_fin
@@ -519,12 +517,12 @@
 
 	.type	cpu_arch_name, #object
 cpu_arch_name:
-	.asciz	"armv5EJ"
+	.asciz	"armv5tej"
 	.size	cpu_arch_name, . - cpu_arch_name
 
 	.type	cpu_elf_name, #object
 cpu_elf_name:
-	.asciz	"v5EJ"
+	.asciz	"v5"
 	.size	cpu_elf_name, . - cpu_elf_name
 	.align
 
@@ -538,7 +536,8 @@
 	b	__arm926_setup
 	.long	cpu_arch_name
 	.long	cpu_elf_name
-	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | \
+		HWCAP_FAST_MULT | HWCAP_JAVA
 	.long	cpu_arm926_info
 	.long	arm926_processor_functions
 	.long	v4wbi_tlb_fns
diff -Nru a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
--- a/arch/arm/mm/proc-xscale.S	Tue Jul 16 16:49:43 2002
+++ b/arch/arm/mm/proc-xscale.S	Tue Jul 16 16:49:43 2002
@@ -602,8 +602,6 @@
  */
 	.align	5
 ENTRY(cpu_xscale_set_pte)
-	tst	r0, #2048
-	streq	r0, [r0, -r0]			@ BUG_ON
 	str	r1, [r0], #-2048		@ linux version
 
 	bic	r2, r1, #0xff0
@@ -681,6 +679,9 @@
 	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
 	mov	r0, #0x1f			@ Domains 0, 1 = client
 	mcr	p15, 0, r0, c3, c0, 0		@ load domain access register
+	mov	r0, #1				@ Allow access to CP0 and CP13
+	orr	r0, r0, #1 << 13		@ Its undefined whether this
+	mcr	p15, 0, r0, c15, c1, 0		@ affects USR or SVC modes
 	mrc	p15, 0, r0, c1, c0, 0		@ get control register
 	bic	r0, r0, #0x0200			@ .... ..R. .... ....
 	bic	r0, r0, #0x0082			@ .... .... B... ..A.
@@ -697,7 +698,7 @@
 
 	.type	xscale_processor_functions, #object
 ENTRY(xscale_processor_functions)
-	.word	v4t_early_abort
+	.word	xscale_abort
 	.word	cpu_xscale_check_bugs
 	.word	cpu_xscale_proc_init
 	.word	cpu_xscale_proc_fin
@@ -739,7 +740,7 @@
 
 	.type	cpu_arch_name, #object
 cpu_arch_name:
-	.asciz	"armv5"
+	.asciz	"armv5te"
 	.size	cpu_arch_name, . - cpu_arch_name
 
 	.type	cpu_elf_name, #object
@@ -762,7 +763,7 @@
 	.long	cpu_80200_info
 	.long	xscale_processor_functions
 	.long	v4wbi_tlb_fns
-	.long	v5te_mc_user_fns
+	.long	xscale_mc_user_fns
 	.size	__80200_proc_info, . - __80200_proc_info
 
 	.type	__pxa250_proc_info,#object
@@ -777,6 +778,6 @@
 	.long	cpu_pxa250_info
 	.long	xscale_processor_functions
 	.long	v4wbi_tlb_fns
-	.long	v5te_mc_user_fns
+	.long	xscale_mc_user_fns
 	.size	__pxa250_proc_info, . - __pxa250_proc_info
 
diff -Nru a/arch/arm/nwfpe/fpa11.c b/arch/arm/nwfpe/fpa11.c
--- a/arch/arm/nwfpe/fpa11.c	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/nwfpe/fpa11.c	Tue Jul 16 16:49:42 2002
@@ -142,9 +142,6 @@
 unsigned int EmulateAll(unsigned int opcode)
 {
   unsigned int nRc = 1, code;
-  unsigned long flags;
-
-  save_flags(flags); sti();
 
   code = opcode & 0x00000f00;
   if (code == 0x00000100 || code == 0x00000200)
@@ -179,8 +176,6 @@
       nRc = 0;
     }
   }
-
-  restore_flags(flags);
 
   return(nRc);
 }
diff -Nru a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
--- a/arch/arm/tools/mach-types	Tue Jul 16 16:49:42 2002
+++ b/arch/arm/tools/mach-types	Tue Jul 16 16:49:42 2002
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Tue May 21 14:19:05 2002
+# Last update: Fri Jul 5 21:32:20 2002
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -192,3 +192,18 @@
 brh			ARCH_BRH		BRH			181
 s3c2410			ARCH_S3C2410		S3C2410			182
 possio_px30		ARCH_POSSIO_PX30	POSSIO_PX30		183
+s3c2800			ARCH_S3C2800		S3C2800			184
+fleetwood		SA1100_FLEETWOOD	FLEETWOOD		185
+omaha			ARCH_OMAHA		OMAHA			186
+ta7			ARCH_TA7		TA7			187
+nova			SA1100_NOVA		NOVA			188
+hmk			ARCH_HMK		HMK			189
+inphinity		ARCH_INPHINITY		INPHINITY		190
+fester			SA1100_FESTER		FESTER			191
+gpi			ARCH_GPI		GPI			192
+smdk2410		ARCH_SMDK2410		SMDK2410		193
+premium			ARCH_PREMIUM		PREMIUM			194
+nexio			SA1100_NEXIO		NEXIO			195
+bitbox			SA1100_BITBOX		BITBOX			196
+g200			SA1100_G200		G200			197
+gill			SA1100_GILL		GILL			198
diff -Nru a/arch/arm/vmlinux-armo.lds.in b/arch/arm/vmlinux-armo.lds.in
--- a/arch/arm/vmlinux-armo.lds.in	Tue Jul 16 16:49:43 2002
+++ b/arch/arm/vmlinux-armo.lds.in	Tue Jul 16 16:49:43 2002
@@ -8,10 +8,9 @@
 SECTIONS
 {
 	. = TEXTADDR;
-
-	.init : {
+	.init : {			/* Init code and data		*/
 		_stext = .;
-		__init_begin = .;	/* Init code and data		*/
+		__init_begin = .;
 			*(.text.init)
 		__proc_info_begin = .;
 			*(.proc.info)
@@ -50,7 +49,7 @@
 		*(.exitcall.exit)
 	}
 
-	.text : {
+	.text : {			/* Real text segment		*/
 		_text = .;		/* Text and read-only data	*/
 			*(.text)
 			*(.fixup)
@@ -59,19 +58,24 @@
 			*(.rodata.*)
 			*(.glue_7)
 			*(.glue_7t)
-			*(.kstrtab)
-		. = ALIGN(16);		/* Exception table		*/
+		*(.got)			/* Global offset table		*/
+
+		_etext = .;		/* End of text section		*/
+	}
+
+	.kstrtab : { *(.kstrtab) }
+
+	. = ALIGN(16);
+	__ex_table : {			/* Exception table		*/
 		__start___ex_table = .;
 			*(__ex_table)
 		__stop___ex_table = .;
+	}
 
-		__start___ksymtab = .;	/* Kernel symbol table		*/
+	__ksymtab : {			/* Kernel symbol table		*/
+		__start___ksymtab = .;
 			*(__ksymtab)
 		__stop___ksymtab = .;
-
-		*(.got)			/* Global offset table		*/
-
-		_etext = .;		/* End of text section		*/
 	}
 
 	.data : {
@@ -90,14 +94,12 @@
 		_edata = .;
 	}
 
-
 	.bss : {
 		__bss_start = .;	/* BSS				*/
 		*(.bss)
 		*(COMMON)
 		_end = . ;
 	}
-
 					/* Stabs debugging sections.	*/
 	.stab 0 : { *(.stab) }
 	.stabstr 0 : { *(.stabstr) }
diff -Nru a/arch/cris/drivers/ide.c b/arch/cris/drivers/ide.c
--- a/arch/cris/drivers/ide.c	Tue Jul 16 16:49:41 2002
+++ b/arch/cris/drivers/ide.c	Tue Jul 16 16:49:41 2002
@@ -703,11 +703,11 @@
 				i -= rq->current_nr_sectors;
 				ide_end_request(drive, rq, 1);
 			}
-			return ide_stopped;
+			return ATA_OP_FINISHED;
 		}
 		printk("%s: bad DMA status\n", drive->name);
 	}
-	return ata_error(drive, __FUNCTION__);
+	return ata_error(drive, rq, __FUNCTION__);
 }
 
 /*
diff -Nru a/arch/cris/kernel/signal.c b/arch/cris/kernel/signal.c
--- a/arch/cris/kernel/signal.c	Tue Jul 16 16:49:41 2002
+++ b/arch/cris/kernel/signal.c	Tue Jul 16 16:49:41 2002
@@ -43,42 +43,6 @@
 
 int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs);
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
-		int err;
-
-		/* If you change siginfo_t structure, please be sure
-		   this code is fixed accordingly.
-		   It should never copy any pad contained in the structure
-		   to avoid security leaks, but must copy the generic
-		   3 ints plus the relevant union member.  */
-		err = __put_user(from->si_signo, &to->si_signo);
-		err |= __put_user(from->si_errno, &to->si_errno);
-		err |= __put_user((short)from->si_code, &to->si_code);
-		/* First 32bits of unions are always present.  */
-		err |= __put_user(from->si_pid, &to->si_pid);
-		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-                        err |= __put_user(from->si_addr, &to->si_addr);
-			break;
-		case __SI_CHLD >> 16:
-			err |= __put_user(from->si_utime, &to->si_utime);
-			err |= __put_user(from->si_stime, &to->si_stime);
-			err |= __put_user(from->si_status, &to->si_status);
-		default:
-			err |= __put_user(from->si_uid, &to->si_uid);
-			break;
-		/* case __SI_RT: This is not generated by the kernel as of now.  */
-		}
-		return err;
-	}
-}
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.  Define 
  * dummy arguments to be able to reach the regs argument.  (Note that this
diff -Nru a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
--- a/arch/i386/boot/compressed/misc.c	Tue Jul 16 16:49:42 2002
+++ b/arch/i386/boot/compressed/misc.c	Tue Jul 16 16:49:42 2002
@@ -99,15 +99,11 @@
 static uch *output_data;
 static unsigned long output_ptr = 0;
 
- 
 static void *malloc(int size);
 static void free(void *where);
-static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
- 
+
 static void puts(const char *);
-  
+
 extern int end;
 static long free_mem_ptr = (long)&end;
 static long free_mem_end_ptr;
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
--- a/arch/i386/config.in	Tue Jul 16 16:49:42 2002
+++ b/arch/i386/config.in	Tue Jul 16 16:49:42 2002
@@ -407,7 +407,7 @@
 mainmenu_option next_comment
 comment 'Kernel hacking'
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   dep_bool 'Software Suspend' CONFIG_SOFTWARE_SUSPEND $CONFIG_PM
+   dep_bool 'Software Suspend (EXPERIMENTAL)' CONFIG_SOFTWARE_SUSPEND $CONFIG_PM
 fi
 
 bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
--- a/arch/i386/kernel/apic.c	Tue Jul 16 16:49:42 2002
+++ b/arch/i386/kernel/apic.c	Tue Jul 16 16:49:42 2002
@@ -1058,7 +1058,7 @@
 /*
  * Local APIC timer interrupt. This is the most natural way for doing
  * local interrupts, but local timer interrupts can be emulated by
- * broadcast interrupts too. [in case the hw doesnt support APIC timers]
+ * broadcast interrupts too. [in case the hw doesn't support APIC timers]
  *
  * [ if a single-CPU system runs an SMP kernel then we call the local
  *   interrupt as well. Thus we cannot inline the local irq ... ]
diff -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
--- a/arch/i386/kernel/apm.c	Tue Jul 16 16:49:41 2002
+++ b/arch/i386/kernel/apm.c	Tue Jul 16 16:49:41 2002
@@ -923,7 +923,7 @@
  */
 
 static void handle_poweroff (int key, struct pt_regs *pt_regs,
-		struct kbd_struct *kbd, struct tty_struct *tty)
+			     struct tty_struct *tty)
 {
         apm_power_off();
 }
diff -Nru a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c
--- a/arch/i386/kernel/bluesmoke.c	Tue Jul 16 16:49:42 2002
+++ b/arch/i386/kernel/bluesmoke.c	Tue Jul 16 16:49:42 2002
@@ -9,6 +9,7 @@
 #include <linux/smp.h>
 #include <linux/config.h>
 #include <linux/irq.h>
+#include <linux/tqueue.h>
 #include <asm/processor.h> 
 #include <asm/system.h>
 #include <asm/msr.h>
@@ -273,9 +274,6 @@
 {
 	u32 low, high;
 	int i;
-	unsigned int *cpu = info;
-
-	BUG_ON (*cpu != smp_processor_id());
 
 	for (i=0; i<banks; i++) {
 		rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high);
@@ -293,24 +291,32 @@
 	}
 }
 
+static void do_mce_timer(void *data)
+{ 
+	preempt_disable(); 
+	mce_checkregs(NULL);
+	smp_call_function (mce_checkregs, NULL, 1, 1);
+	preempt_enable();
+	mce_timer.expires = jiffies + MCE_RATE;
+	add_timer (&mce_timer);
+} 
+
+static struct tq_struct mce_task = { 
+	routine: do_mce_timer	
+};
 
 static void mce_timerfunc (unsigned long data)
 {
-	unsigned int i;
-
-	for (i=0; i<NR_CPUS; i++) {
-		if (!cpu_online(i))
-			continue;
-		if (i == smp_processor_id())
-			mce_checkregs(&i);
-		else
-			smp_call_function (mce_checkregs, &i, 1, 1);
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > 1) { 
+		schedule_task(&mce_task); 
+		return;
 	}
-
-	/* Refresh the timer. */
+#endif
+	mce_checkregs(NULL);
 	mce_timer.expires = jiffies + MCE_RATE;
 	add_timer (&mce_timer);
-}
+}	
 #endif
 
 
@@ -446,7 +452,7 @@
 	{
 		case X86_VENDOR_AMD:
 			/* AMD K7 machine check is Intel like */
-			if(c->x86 == 6) {
+			if(c->x86 == 6 || c->x86 == 15) {
 				intel_mcheck_init(c);
 #ifdef CONFIG_X86_MCE_NONFATAL
 				if (timerset == 0) {
diff -Nru a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
--- a/arch/i386/kernel/cpu/common.c	Tue Jul 16 16:49:41 2002
+++ b/arch/i386/kernel/cpu/common.c	Tue Jul 16 16:49:41 2002
@@ -15,9 +15,6 @@
 
 struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {};
 
-static struct cpu_dev default_cpu;
-static struct cpu_dev * this_cpu = &default_cpu;
-
 extern void mcheck_init(struct cpuinfo_x86 *c);
 
 static void default_init(struct cpuinfo_x86 * c)
@@ -36,6 +33,7 @@
 static struct cpu_dev default_cpu = {
 	c_init:	default_init,
 };
+static struct cpu_dev * this_cpu = &default_cpu;
 
 static int __init cachesize_setup(char *str)
 {
diff -Nru a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
--- a/arch/i386/kernel/cpu/intel.c	Tue Jul 16 16:49:42 2002
+++ b/arch/i386/kernel/cpu/intel.c	Tue Jul 16 16:49:42 2002
@@ -91,6 +91,46 @@
 }
 __setup("noht", P4_disable_ht);
 
+#define LVL_1_INST	1
+#define LVL_1_DATA	2
+#define LVL_2		3
+#define LVL_3		4
+
+struct _cache_table
+{
+	unsigned char descriptor;
+	char cache_type;
+	short size;
+};
+
+/* all the cache descriptor types we care about (no TLB or trace cache entries) */
+static struct _cache_table cache_table[] __initdata =
+{
+	{ 0x06, LVL_1_INST, 8 },
+	{ 0x08, LVL_1_INST, 16 },
+	{ 0x0A, LVL_1_DATA, 8 },
+	{ 0x0C, LVL_1_DATA, 16 },
+	{ 0x22, LVL_3,      512 },
+	{ 0x23, LVL_3,      1024 },
+	{ 0x25, LVL_3,      2048 },
+	{ 0x29, LVL_3,      4096 },
+	{ 0x41, LVL_2,      128 },
+	{ 0x42, LVL_2,      256 },
+	{ 0x43, LVL_2,      512 },
+	{ 0x44, LVL_2,      1024 },
+	{ 0x45, LVL_2,      2048 },
+	{ 0x66, LVL_1_DATA, 8 },
+	{ 0x67, LVL_1_DATA, 16 },
+	{ 0x68, LVL_1_DATA, 32 },
+	{ 0x79, LVL_2,      128 },
+	{ 0x7A, LVL_2,      256 },
+	{ 0x7B, LVL_2,      512 },
+	{ 0x7C, LVL_2,      1024 },
+	{ 0x82, LVL_2,      256 },
+	{ 0x84, LVL_2,      1024 },
+	{ 0x85, LVL_2,      2048 },
+	{ 0x00, 0, 0}
+};
 
 static void __init init_intel(struct cpuinfo_x86 *c)
 {
@@ -137,83 +177,31 @@
 			/* Byte 0 is level count, not a descriptor */
 			for ( j = 1 ; j < 16 ; j++ ) {
 				unsigned char des = dp[j];
-				unsigned char dl, dh;
-				unsigned int cs;
-
-				dh = des >> 4;
-				dl = des & 0x0F;
+				unsigned char k = 0;
 
-				/* Black magic... */
-
-				switch ( dh )
+				/* look up this descriptor in the table */
+				while (cache_table[k].descriptor != 0)
 				{
-				case 0:
-					switch ( dl ) {
-					case 6:
-						/* L1 I cache */
-						l1i += 8;
-						break;
-					case 8:
-						/* L1 I cache */
-						l1i += 16;
-						break;
-					case 10:
-						/* L1 D cache */
-						l1d += 8;
-						break;
-					case 12:
-						/* L1 D cache */
-						l1d += 16;
-						break;
-					default:;
-						/* TLB, or unknown */
-					}
-					break;
-				case 2:
-					if ( dl ) {
-						/* L3 cache */
-						cs = (dl-1) << 9;
-						l3 += cs;
-					}
-					break;
-				case 4:
-					if ( c->x86 > 6 && dl ) {
-						/* P4 family */
-						/* L3 cache */
-						cs = 128 << (dl-1);
-						l3 += cs;
+					if (cache_table[k].descriptor == des) {
+						switch (cache_table[k].cache_type) {
+						case LVL_1_INST:
+							l1i += cache_table[k].size;
+							break;
+						case LVL_1_DATA:
+							l1d += cache_table[k].size;
+							break;
+						case LVL_2:
+							l2 += cache_table[k].size;
+							break;
+						case LVL_3:
+							l3 += cache_table[k].size;
+							break;
+						}
+
 						break;
 					}
-					/* else same as 8 - fall through */
-				case 8:
-					if ( dl ) {
-						/* L2 cache */
-						cs = 128 << (dl-1);
-						l2 += cs;
-					}
-					break;
-				case 6:
-					if (dl > 5) {
-						/* L1 D cache */
-						cs = 8<<(dl-6);
-						l1d += cs;
-					}
-					break;
-				case 7:
-					if ( dl >= 8 ) 
-					{
-						/* L2 cache */
-						cs = 64<<(dl-8);
-						l2 += cs;
-					} else {
-						/* L0 I cache, count as L1 */
-						cs = dl ? (16 << (dl-1)) : 12;
-						l1i += cs;
-					}
-					break;
-				default:
-					/* TLB, or something else we don't know about */
-					break;
+
+					k++;
 				}
 			}
 		}
diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
--- a/arch/i386/kernel/io_apic.c	Tue Jul 16 16:49:42 2002
+++ b/arch/i386/kernel/io_apic.c	Tue Jul 16 16:49:42 2002
@@ -219,6 +219,7 @@
 #define IRQ_ALLOWED(cpu,allowed_mask) \
 		((1 << cpu) & (allowed_mask))
 
+#if CONFIG_SMP
 static unsigned long move(int curr_cpu, unsigned long allowed_mask, unsigned long now, int direction)
 {
 	int search_idle = 1;
@@ -247,7 +248,6 @@
 
 static inline void balance_irq(int irq)
 {
-#if CONFIG_SMP
 	irq_balance_t *entry = irq_balance + irq;
 	unsigned long now = jiffies;
 
@@ -263,8 +263,10 @@
 		entry->cpu = move(entry->cpu, allowed_mask, now, random_number);
 		set_ioapic_affinity(irq, 1 << entry->cpu);
 	}
-#endif
 }
+#else /* !SMP */
+static inline void balance_irq(int irq) { }
+#endif
 
 /*
  * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
@@ -724,7 +726,14 @@
 		}
 
 		irq = pin_2_irq(idx, apic, pin);
-		add_pin_to_irq(irq, apic, pin);
+		/*
+		 * skip adding the timer int on secondary nodes, which causes
+		 * a small but painful rift in the time-space continuum
+		 */
+		if (clustered_apic_mode && (apic != 0) && (irq == 0))
+			continue;
+		else
+			add_pin_to_irq(irq, apic, pin);
 
 		if (!apic && !IO_APIC_IRQ(irq))
 			continue;
diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
--- a/arch/i386/kernel/mpparse.c	Tue Jul 16 16:49:42 2002
+++ b/arch/i386/kernel/mpparse.c	Tue Jul 16 16:49:42 2002
@@ -779,7 +779,7 @@
 
 /*
  * The Visual Workstation is Intel MP compliant in the hardware
- * sense, but it doesnt have a BIOS(-configuration table).
+ * sense, but it doesn't have a BIOS(-configuration table).
  * No problem for Linux.
  */
 void __init find_visws_smp(void)
@@ -1051,8 +1051,6 @@
 	return;
 }
 
-#endif /*CONFIG_X86_IO_APIC*/
-
 #ifdef CONFIG_ACPI_PCI
 
 void __init mp_parse_prt (void)
@@ -1119,5 +1117,7 @@
 }
 
 #endif /*CONFIG_ACPI_PCI*/
+
+#endif /*CONFIG_X86_IO_APIC*/
 
 #endif /*CONFIG_ACPI_BOOT*/
diff -Nru a/arch/i386/kernel/semaphore.c b/arch/i386/kernel/semaphore.c
--- a/arch/i386/kernel/semaphore.c	Tue Jul 16 16:49:42 2002
+++ b/arch/i386/kernel/semaphore.c	Tue Jul 16 16:49:42 2002
@@ -28,8 +28,8 @@
  * needs to do something only if count was negative before
  * the increment operation.
  *
- * "sleeping" and the contention routine ordering is
- * protected by the semaphore spinlock.
+ * "sleeping" and the contention routine ordering is protected
+ * by the spinlock in the semaphore's waitqueue head.
  *
  * Note that these functions are only called when there is
  * contention on the lock, and as such all this is the
@@ -53,39 +53,41 @@
 	wake_up(&sem->wait);
 }
 
-static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
-
 void __down(struct semaphore * sem)
 {
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
+	unsigned long flags;
+
 	tsk->state = TASK_UNINTERRUPTIBLE;
-	add_wait_queue_exclusive(&sem->wait, &wait);
+	spin_lock_irqsave(&sem->wait.lock, flags);
+	add_wait_queue_exclusive_locked(&sem->wait, &wait);
 
-	spin_lock_irq(&semaphore_lock);
 	sem->sleepers++;
 	for (;;) {
 		int sleepers = sem->sleepers;
 
 		/*
 		 * Add "everybody else" into it. They aren't
-		 * playing, because we own the spinlock.
+		 * playing, because we own the spinlock in
+		 * the wait_queue_head.
 		 */
 		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
 			sem->sleepers = 0;
 			break;
 		}
 		sem->sleepers = 1;	/* us - see -1 above */
-		spin_unlock_irq(&semaphore_lock);
+		spin_unlock_irqrestore(&sem->wait.lock, flags);
 
 		schedule();
+
+		spin_lock_irqsave(&sem->wait.lock, flags);
 		tsk->state = TASK_UNINTERRUPTIBLE;
-		spin_lock_irq(&semaphore_lock);
 	}
-	spin_unlock_irq(&semaphore_lock);
-	remove_wait_queue(&sem->wait, &wait);
+	remove_wait_queue_locked(&sem->wait, &wait);
+	wake_up_locked(&sem->wait);
+	spin_unlock_irqrestore(&sem->wait.lock, flags);
 	tsk->state = TASK_RUNNING;
-	wake_up(&sem->wait);
 }
 
 int __down_interruptible(struct semaphore * sem)
@@ -93,11 +95,13 @@
 	int retval = 0;
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
+	unsigned long flags;
+
 	tsk->state = TASK_INTERRUPTIBLE;
-	add_wait_queue_exclusive(&sem->wait, &wait);
+	spin_lock_irqsave(&sem->wait.lock, flags);
+	add_wait_queue_exclusive_locked(&sem->wait, &wait);
 
-	spin_lock_irq(&semaphore_lock);
-	sem->sleepers ++;
+	sem->sleepers++;
 	for (;;) {
 		int sleepers = sem->sleepers;
 
@@ -117,25 +121,27 @@
 
 		/*
 		 * Add "everybody else" into it. They aren't
-		 * playing, because we own the spinlock. The
-		 * "-1" is because we're still hoping to get
-		 * the lock.
+		 * playing, because we own the spinlock in
+		 * wait_queue_head. The "-1" is because we're
+		 * still hoping to get the semaphore.
 		 */
 		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
 			sem->sleepers = 0;
 			break;
 		}
 		sem->sleepers = 1;	/* us - see -1 above */
-		spin_unlock_irq(&semaphore_lock);
+		spin_unlock_irqrestore(&sem->wait.lock, flags);
 
 		schedule();
+
+		spin_lock_irqsave(&sem->wait.lock, flags);
 		tsk->state = TASK_INTERRUPTIBLE;
-		spin_lock_irq(&semaphore_lock);
 	}
-	spin_unlock_irq(&semaphore_lock);
+	remove_wait_queue_locked(&sem->wait, &wait);
+	wake_up_locked(&sem->wait);
+	spin_unlock_irqrestore(&sem->wait.lock, flags);
+
 	tsk->state = TASK_RUNNING;
-	remove_wait_queue(&sem->wait, &wait);
-	wake_up(&sem->wait);
 	return retval;
 }
 
@@ -152,18 +158,20 @@
 	int sleepers;
 	unsigned long flags;
 
-	spin_lock_irqsave(&semaphore_lock, flags);
+	spin_lock_irqsave(&sem->wait.lock, flags);
 	sleepers = sem->sleepers + 1;
 	sem->sleepers = 0;
 
 	/*
 	 * Add "everybody else" and us into it. They aren't
-	 * playing, because we own the spinlock.
+	 * playing, because we own the spinlock in the
+	 * wait_queue_head.
 	 */
-	if (!atomic_add_negative(sleepers, &sem->count))
-		wake_up(&sem->wait);
+	if (!atomic_add_negative(sleepers, &sem->count)) {
+		wake_up_locked(&sem->wait);
+	}
 
-	spin_unlock_irqrestore(&semaphore_lock, flags);
+	spin_unlock_irqrestore(&sem->wait.lock, flags);
 	return 1;
 }
 
diff -Nru a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
--- a/arch/i386/kernel/smp.c	Tue Jul 16 16:49:41 2002
+++ b/arch/i386/kernel/smp.c	Tue Jul 16 16:49:41 2002
@@ -67,7 +67,7 @@
  *	an L1cache=Writethrough or L1cache=off option.
  *
  *		B stepping CPUs may hang. There are hardware work arounds
- *	for this. We warn about it in case your board doesnt have the work
+ *	for this. We warn about it in case your board doesn't have the work
  *	arounds. Basically thats so I can tell anyone with a B stepping
  *	CPU and SMP problems "tough".
  *
diff -Nru a/arch/i386/kernel/suspend.c b/arch/i386/kernel/suspend.c
--- a/arch/i386/kernel/suspend.c	Tue Jul 16 16:49:43 2002
+++ b/arch/i386/kernel/suspend.c	Tue Jul 16 16:49:43 2002
@@ -97,6 +97,14 @@
 	asm volatile ("pushfl ; popl (%0)" : "=m" (saved_context.eflags));
 }
 
+static void
+do_fpu_end(void)
+{
+        /* restore FPU regs if necessary */
+	/* Do it out of line so that gcc does not move cr0 load to some stupid place */
+        kernel_fpu_end();
+}
+
 /*
  * restore_processor_context
  * 
@@ -220,13 +228,6 @@
 
 }
 
-static void
-do_fpu_end(void)
-{
-        /* restore FPU regs if necessary */
-	/* Do it out of line so that gcc does not move cr0 load to some stupid place */
-        kernel_fpu_end();
-}
 
 #ifdef CONFIG_SOFTWARE_SUSPEND
 /* Local variables for do_magic */
diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c
--- a/arch/i386/mm/init.c	Tue Jul 16 16:49:41 2002
+++ b/arch/i386/mm/init.c	Tue Jul 16 16:49:41 2002
@@ -291,7 +291,7 @@
 
 #if CONFIG_X86_PAE
 	/*
-	 * We will bail out later - printk doesnt work right now so
+	 * We will bail out later - printk doesn't work right now so
 	 * the user would just see a hanging kernel.
 	 */
 	if (cpu_has_pae)
diff -Nru a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
--- a/arch/i386/mm/ioremap.c	Tue Jul 16 16:49:42 2002
+++ b/arch/i386/mm/ioremap.c	Tue Jul 16 16:49:42 2002
@@ -213,9 +213,9 @@
 void iounmap(void *addr)
 {
 	struct vm_struct *p;
-	if (addr < high_memory) 
+	if (addr <= high_memory) 
 		return; 
-	p = remove_kernel_area(addr); 
+	p = remove_kernel_area(PAGE_MASK & (unsigned long) addr); 
 	if (!p) { 
 		printk("__iounmap: bad address %p\n", addr);
 		return;
diff -Nru a/arch/ia64/sn/fakeprom/README b/arch/ia64/sn/fakeprom/README
--- a/arch/ia64/sn/fakeprom/README	Tue Jul 16 16:49:42 2002
+++ b/arch/ia64/sn/fakeprom/README	Tue Jul 16 16:49:42 2002
@@ -71,7 +71,7 @@
     1GB*<dn>, where dn is the digit number. The amount of memory
     is 8MB*2**<d>. (If <d> = 0, the memory size is 0).
 
-    SN1 doesnt support dimms this small but small memory systems 
+    SN1 doesn't support dimms this small but small memory systems 
     boot faster on Medusa.
 
 
diff -Nru a/arch/m68k/config.in b/arch/m68k/config.in
--- a/arch/m68k/config.in	Tue Jul 16 16:49:43 2002
+++ b/arch/m68k/config.in	Tue Jul 16 16:49:43 2002
@@ -522,7 +522,7 @@
 mainmenu_option next_comment
 comment 'Sound support'
 
-tristate 'Sound support' CONFIG_SOUND
+tristate 'Sound card support' CONFIG_SOUND
 if [ "$CONFIG_SOUND" != "n" ]; then
    source sound/oss/dmasound/Config.in
 fi
diff -Nru a/arch/mips/config.in b/arch/mips/config.in
--- a/arch/mips/config.in	Tue Jul 16 16:49:43 2002
+++ b/arch/mips/config.in	Tue Jul 16 16:49:43 2002
@@ -12,13 +12,13 @@
 mainmenu_option next_comment
 comment 'Machine selection'
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   bool 'Support for Acer PICA 1 chipset' CONFIG_ACER_PICA_61
+   bool 'Support for Acer PICA 1 chipset (EXPERIMENTAL)' CONFIG_ACER_PICA_61
    bool 'Support for Algorithmics P4032 (EXPERIMENTAL)' CONFIG_ALGOR_P4032
    bool 'Support for BAGET MIPS series (EXPERIMENTAL)' CONFIG_BAGET_MIPS
    bool 'Support for DECstations (EXPERIMENTAL)' CONFIG_DECSTATION
    bool 'Support for NEC DDB Vrc-5074 (EXPERIMENTAL)' CONFIG_DDB5074
-   bool 'Support for Galileo EV96100 Evaluation board' CONFIG_MIPS_EV96100
-   bool 'Support for Galileo EV64120 Evaluation board' CONFIG_MIPS_EV64120
+   bool 'Support for Galileo EV96100 Evaluation board (EXPERIMENTAL)' CONFIG_MIPS_EV96100
+   bool 'Support for Galileo EV64120 Evaluation board (EXPERIMENTAL)' CONFIG_MIPS_EV64120
    if [ "$CONFIG_MIPS_EV64120" = "y" ]; then
 		  bool 'Enable Second PCI (PCI1)' CONFIG_EVB_PCI1
       choice 'Galileo Chip Clock' \
@@ -26,8 +26,8 @@
          83.3 CONFIG_SYSCLK_83\
          100 CONFIG_SYSCLK_100" CONFIG_SYSCLK_83
    fi
-   bool 'Support for MIPS Atlas board' CONFIG_MIPS_ATLAS
-   bool 'Support for MIPS Malta board' CONFIG_MIPS_MALTA
+   bool 'Support for MIPS Atlas board (EXPERIMENTAL)' CONFIG_MIPS_ATLAS
+   bool 'Support for MIPS Malta board (EXPERIMENTAL)' CONFIG_MIPS_MALTA
    bool 'Support for Philips Nino (EXPERIMENTAL)' CONFIG_NINO
    if [ "$CONFIG_NINO" = "y" ]; then
       choice 'Nino Model Number' \
diff -Nru a/arch/mips/dec/wbflush.c b/arch/mips/dec/wbflush.c
--- a/arch/mips/dec/wbflush.c	Tue Jul 16 16:49:43 2002
+++ b/arch/mips/dec/wbflush.c	Tue Jul 16 16:49:43 2002
@@ -97,7 +97,7 @@
 }
 
 /*
- * The DS500/2x0 doesnt need to write back the WB.
+ * The DS500/2x0 doesn't need to write back the WB.
  */
 static void wbflush_kn03(void)
 {
diff -Nru a/arch/mips64/math-emu/ieee754.c b/arch/mips64/math-emu/ieee754.c
--- a/arch/mips64/math-emu/ieee754.c	Tue Jul 16 16:49:42 2002
+++ b/arch/mips64/math-emu/ieee754.c	Tue Jul 16 16:49:42 2002
@@ -3,7 +3,7 @@
  *
  * BUGS
  * not much dp done
- * doesnt generate IEEE754_INEXACT
+ * doesn't generate IEEE754_INEXACT
  *
  */
 /*
diff -Nru a/arch/parisc/config.in b/arch/parisc/config.in
--- a/arch/parisc/config.in	Tue Jul 16 16:49:43 2002
+++ b/arch/parisc/config.in	Tue Jul 16 16:49:43 2002
@@ -24,14 +24,14 @@
 # bool 'GSC/Gecko bus support' CONFIG_GSC y
 define_bool CONFIG_GSC y
 
-bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO y
-bool 'LASI I/O support' CONFIG_GSC_LASI y
+bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO
+bool 'LASI I/O support' CONFIG_GSC_LASI
 
-bool 'PCI support' CONFIG_PCI y
+bool 'PCI support' CONFIG_PCI
 
 if [ "$CONFIG_PCI" = "y" ]; then
-	bool 'GSCtoPCI/DINO PCI support' CONFIG_GSC_DINO y
-	bool 'LBA/Elroy PCI support' CONFIG_PCI_LBA n
+	bool 'GSCtoPCI/DINO PCI support' CONFIG_GSC_DINO
+	bool 'LBA/Elroy PCI support' CONFIG_PCI_LBA
 fi 
 
 if [ "$CONFIG_PCI_LBA" = "y" ]; then
diff -Nru a/arch/ppc/4xx_io/stb_kb.c b/arch/ppc/4xx_io/stb_kb.c
--- a/arch/ppc/4xx_io/stb_kb.c	Tue Jul 16 16:49:42 2002
+++ b/arch/ppc/4xx_io/stb_kb.c	Tue Jul 16 16:49:42 2002
@@ -283,11 +283,7 @@
 {
 	extern struct machdep_calls ppc_md;
 
-	ppc_md.kbd_setkeycode           = rawirkbd_setkeycode;
-	ppc_md.kbd_getkeycode           = rawirkbd_getkeycode;
 	ppc_md.kbd_translate            = rawirkbd_translate;
 	ppc_md.kbd_unexpected_up        = rawirkbd_unexpected_up;
-	ppc_md.kbd_leds                 = NULL; /*rawirkbd_leds;*/
-	ppc_md.kbd_init_hw              = rawirkbd_init_hw;
 }
 
diff -Nru a/arch/ppc/Config.help b/arch/ppc/Config.help
--- a/arch/ppc/Config.help	Tue Jul 16 16:49:42 2002
+++ b/arch/ppc/Config.help	Tue Jul 16 16:49:42 2002
@@ -321,19 +321,6 @@
   answer will get "defaulted" for you if you enable any of the Linux
   CD-ROM drivers).
 
-CONFIG_INPUT_ADBHID
-  Say Y here if you want to have ADB (Apple Desktop Bus) HID devices
-  such as keyboards, mice, joysticks, or graphic tablets handled by
-  the input layer.  If you say Y here, make sure to say Y to the
-  corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV),
-  "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface
-  support" (CONFIG_INPUT_EVDEV) as well.
-
-  If you say N here, you still have the option of using the old ADB
-  keyboard and mouse drivers.
-
-  If unsure, say Y.
-
 CONFIG_PREP_RESIDUAL
   Some PReP systems have residual data passed to the kernel by the
   firmware.  This allows detection of memory size, devices present and
@@ -382,14 +369,26 @@
   also includes a MESH II SCSI controller, DBDMA controller, VIA chip,
   OpenPIC controller and two RS422/Geoports.)
 
-CONFIG_ADB_KEYBOARD
-  This option allows you to use an ADB keyboard attached to your
-  machine. Note that this disables any other (ie. PS/2) keyboard
-  support, even if your machine is physically capable of using both at
-  the same time.
+CONFIG_INPUT_ADBHID
+  Say Y here if you want to have ADB (Apple Desktop Bus) HID devices
+  such as keyboards, mice, joysticks, trackpads  or graphic tablets
+  handled by the input layer.  If you say Y here, make sure to say Y to
+  the corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV),
+  "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface
+  support" (CONFIG_INPUT_EVDEV) as well.
 
-  If you use an ADB keyboard (4 pin connector), say Y here.
-  If you use a PS/2 keyboard (6 pin connector), say N here.
+  If unsure, say Y.
+
+CONFIG_MAC_EMUMOUSEBTN
+  This provides generic support for emulating the 2nd and 3rd mouse
+  button with keypresses.  If you say Y here, the emulation is still
+  disabled by default.  The emulation is controlled by these sysctl
+  entries:
+      /proc/sys/dev/mac_hid/mouse_button_emulation
+      /proc/sys/dev/mac_hid/mouse_button2_keycode
+      /proc/sys/dev/mac_hid/mouse_button3_keycode
+
+  If you have an Apple machine with a 1-button mouse, say Y here.
 
 CONFIG_SERIAL_CONSOLE
   If you say Y here, it will be possible to use a serial port as the
@@ -885,28 +884,6 @@
     Date of Release: early 2001 (?)
     End of life: -
     URL: <http://www.microsys.de/html/cu824.html>
-
-CONFIG_MAC_ADBKEYCODES
-  This provides support for sending ADB keycodes to console devices in
-  raw mode, rather than generic "Linux" keycodes.  This is the default
-  up to 2.4.0, but in future this may be phased out in favor of
-  generic Linux keycodes.  If you say Y here, you can dynamically
-  switch via the /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes
-  sysctl and with the "keyboard_sends_linux_keycodes=" kernel
-  argument.
-
-  If unsure, say Y here.
-
-CONFIG_MAC_EMUMOUSEBTN
-  This provides generic support for emulating the 2nd and 3rd mouse
-  button with keypresses.  If you say Y here, the emulation is still
-  disabled by default.  The emulation is controlled by these sysctl
-  entries:
-      /proc/sys/dev/mac_hid/mouse_button_emulation
-      /proc/sys/dev/mac_hid/mouse_button2_keycode
-      /proc/sys/dev/mac_hid/mouse_button3_keycode
-
-  If you have an Apple machine with a 1-button mouse, say Y here.
 
 CONFIG_PPC_RTC
   If you say Y here and create a character special file /dev/rtc with
diff -Nru a/arch/ppc/config.in b/arch/ppc/config.in
--- a/arch/ppc/config.in	Tue Jul 16 16:49:41 2002
+++ b/arch/ppc/config.in	Tue Jul 16 16:49:41 2002
@@ -475,7 +475,7 @@
 mainmenu_option next_comment
 comment 'Console drivers'
 if [ "$CONFIG_4xx" != "y" -a "$CONFIG_8xx" != "y" ]; then
-   bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
+   bool 'VGA text console' CONFIG_VGA_CONSOLE
 fi
 source drivers/video/Config.in
 if [ "$CONFIG_FB" = "y" -a "$CONFIG_ALL_PPC" = "y" ]; then
@@ -536,12 +536,9 @@
    bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB
    if [ "$CONFIG_ADB" = "y" ]; then
       bool '   Include MacIO (CHRP) ADB driver' CONFIG_ADB_MACIO
-      dep_bool '   Use input layer for ADB devices' CONFIG_INPUT_ADBHID $CONFIG_INPUT
+      dep_bool '   Support for ADB input devices (keyboard, mice, ...)' CONFIG_INPUT_ADBHID $CONFIG_INPUT
       if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then
-         bool '     Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES
          bool '     Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN
-      else
-         bool '   Support for ADB keyboard (old driver)' CONFIG_ADB_KEYBOARD
       fi
    fi
    # This is for drivers/macintosh/mac_hid.o, which is needed if the input
diff -Nru a/arch/ppc/kernel/m8260_setup.c b/arch/ppc/kernel/m8260_setup.c
--- a/arch/ppc/kernel/m8260_setup.c	Tue Jul 16 16:49:42 2002
+++ b/arch/ppc/kernel/m8260_setup.c	Tue Jul 16 16:49:42 2002
@@ -266,14 +266,6 @@
 
 	ppc_md.find_end_of_memory	= m8260_find_end_of_memory;
 	ppc_md.setup_io_mappings	= m8260_map_io;
-
-	ppc_md.kbd_setkeycode		= NULL;
-	ppc_md.kbd_getkeycode		= NULL;
-	ppc_md.kbd_translate		= NULL;
-	ppc_md.kbd_unexpected_up	= NULL;
-	ppc_md.kbd_leds			= NULL;
-	ppc_md.kbd_init_hw		= NULL;
-	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
 }
 
 /* Mainly for ksyms.
diff -Nru a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c
--- a/arch/ppc/kernel/m8xx_setup.c	Tue Jul 16 16:49:42 2002
+++ b/arch/ppc/kernel/m8xx_setup.c	Tue Jul 16 16:49:42 2002
@@ -396,14 +396,6 @@
 	ppc_md.find_end_of_memory	= m8xx_find_end_of_memory;
 	ppc_md.setup_io_mappings	= m8xx_map_io;
 
-	ppc_md.kbd_setkeycode		= NULL;
-	ppc_md.kbd_getkeycode		= NULL;
-	ppc_md.kbd_translate		= NULL;
-	ppc_md.kbd_unexpected_up	= NULL;
-	ppc_md.kbd_leds			= NULL;
-	ppc_md.kbd_init_hw		= NULL;
-	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
-
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	m8xx_ide_init();
 #endif
diff -Nru a/arch/ppc/kernel/ppc4xx_setup.c b/arch/ppc/kernel/ppc4xx_setup.c
--- a/arch/ppc/kernel/ppc4xx_setup.c	Tue Jul 16 16:49:41 2002
+++ b/arch/ppc/kernel/ppc4xx_setup.c	Tue Jul 16 16:49:41 2002
@@ -59,15 +59,6 @@
 extern void abort(void);
 extern void ppc4xx_find_bridges(void);
 
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-
 extern void ppc4xx_wdt_heartbeat(void);
 extern int wdt_enable;
 extern unsigned long wdt_period;
@@ -357,13 +348,6 @@
 #if defined(CONFIG_VT) && defined(CONFIG_PC_KEYBOARD)
 #if defined(CONFIG_REDWOOD_4) && defined(CONFIG_STB_KB)
 	redwood_irkb_init();
-#else
-	ppc_md.kbd_setkeycode = pckbd_setkeycode;
-	ppc_md.kbd_getkeycode = pckbd_getkeycode;
-	ppc_md.kbd_translate = pckbd_translate;
-	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-	ppc_md.kbd_leds = pckbd_leds;
-	ppc_md.kbd_init_hw = pckbd_init_hw;
 #endif
 #endif
 
diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
--- a/arch/ppc/kernel/setup.c	Tue Jul 16 16:49:43 2002
+++ b/arch/ppc/kernel/setup.c	Tue Jul 16 16:49:43 2002
@@ -83,7 +83,7 @@
 #endif /* CONFIG_ALL_PPC */
 
 #ifdef CONFIG_MAGIC_SYSRQ
-unsigned long SYSRQ_KEY;
+unsigned long SYSRQ_KEY = 0x54;
 #endif /* CONFIG_MAGIC_SYSRQ */
 
 #ifdef CONFIG_VGA_CONSOLE
diff -Nru a/arch/ppc/platforms/apus_setup.c b/arch/ppc/platforms/apus_setup.c
--- a/arch/ppc/platforms/apus_setup.c	Tue Jul 16 16:49:42 2002
+++ b/arch/ppc/platforms/apus_setup.c	Tue Jul 16 16:49:42 2002
@@ -854,13 +854,6 @@
 
 	/* These should not be used for the APUS yet, since it uses
 	   the M68K keyboard now. */
-	ppc_md.kbd_setkeycode    = apus_kbd_setkeycode;
-	ppc_md.kbd_getkeycode    = apus_kbd_getkeycode;
 	ppc_md.kbd_translate     = amiga_kbd_translate;
 	ppc_md.kbd_unexpected_up = apus_kbd_unexpected_up;
-	ppc_md.kbd_init_hw       = apus_kbd_init_hw;
-#ifdef CONFIG_SYSRQ
-	ppc_md.ppc_kbd_sysrq_xlate = amiga_sysrq_xlate;
-	SYSRQ_KEY                = 0xff;
-#endif
 }
diff -Nru a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c
--- a/arch/ppc/platforms/chrp_setup.c	Tue Jul 16 16:49:42 2002
+++ b/arch/ppc/platforms/chrp_setup.c	Tue Jul 16 16:49:42 2002
@@ -69,14 +69,6 @@
 void btext_progress(char *, unsigned short);
 
 extern unsigned long pmac_find_end_of_memory(void);
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[128];
 extern void select_adb_keyboard(void);
 extern int of_show_percpuinfo(struct seq_file *, int);
 
@@ -389,7 +381,7 @@
 	int i;
 	unsigned long chrp_int_ack;
 	unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
-#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)	
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)	
 	struct device_node *kbd;
 #endif
 
@@ -417,7 +409,7 @@
 		irq_desc[i].handler = &i8259_pic;
 	i8259_init(chrp_int_ack);
 
-#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
 	/* see if there is a keyboard in the device tree
 	   with a parent of type "adb" */
 	for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
@@ -447,7 +439,7 @@
 	if (ppc_md.progress)
 		ppc_md.progress("  Have fun!    ", 0x7777);
 
-#if defined(CONFIG_VT) && (defined(CONFIG_ADB_KEYBOARD) || defined(CONFIG_INPUT))
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT)
 	/* see if there is a keyboard in the device tree
 	   with a parent of type "adb" */
 	{
@@ -461,7 +453,7 @@
 			}
 		}
 	}
-#endif /* CONFIG_VT && (CONFIG_ADB_KEYBOARD || CONFIG_INPUT) */
+#endif /* CONFIG_VT && CONFIG_INPUT */
 }
 
 void __init
@@ -501,20 +493,6 @@
 	ppc_md.calibrate_decr = chrp_calibrate_decr;
 
 	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
-
-#ifdef CONFIG_VT
-	/* these are adjusted in chrp_init2 if we have an ADB keyboard */
-	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
-	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
-	ppc_md.kbd_translate     = pckbd_translate;
-	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-	ppc_md.kbd_leds          = pckbd_leds;
-	ppc_md.kbd_init_hw       = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
-	SYSRQ_KEY = 0x54;
-#endif /* CONFIG_MAGIC_SYSRQ */
-#endif /* CONFIG_VT */
 
 	if (rtas_data) {
 		struct device_node *rtas;
diff -Nru a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c
--- a/arch/ppc/platforms/gemini_setup.c	Tue Jul 16 16:49:42 2002
+++ b/arch/ppc/platforms/gemini_setup.c	Tue Jul 16 16:49:42 2002
@@ -576,14 +576,6 @@
 	ppc_md.find_end_of_memory = gemini_find_end_of_memory;
 	ppc_md.setup_io_mappings = gemini_map_io;
 
-	/* no keyboard/mouse/video stuff yet.. */
-	ppc_md.kbd_setkeycode = NULL;
-	ppc_md.kbd_getkeycode = NULL;
-	ppc_md.kbd_translate = NULL;
-	ppc_md.kbd_unexpected_up = NULL;
-	ppc_md.kbd_leds = NULL;
-	ppc_md.kbd_init_hw = NULL;
-	ppc_md.ppc_kbd_sysrq_xlate = NULL;
 	ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup;
 
 #ifdef CONFIG_SMP
diff -Nru a/arch/ppc/platforms/iSeries_setup.c b/arch/ppc/platforms/iSeries_setup.c
--- a/arch/ppc/platforms/iSeries_setup.c	Tue Jul 16 16:49:42 2002
+++ b/arch/ppc/platforms/iSeries_setup.c	Tue Jul 16 16:49:42 2002
@@ -216,12 +216,6 @@
 	ppc_md.progress			= iSeries_progress;
 	ppc_md.find_end_of_memory	= iSeries_find_end_of_memory;
 
-	ppc_md.kbd_setkeycode    	= NULL;
-	ppc_md.kbd_getkeycode    	= NULL;
-	ppc_md.kbd_translate     	= NULL;
-	ppc_md.kbd_unexpected_up 	= NULL;
-	ppc_md.kbd_leds          	= NULL;
-	ppc_md.kbd_init_hw       	= NULL;
 #ifdef CONFIG_PCI
 	ppc_md.pcibios_fixup_bus        = iSeries_fixup_bus;
 	ppc_md.pcibios_fixup            = iSeries_fixup;
@@ -229,10 +223,6 @@
 	ppc_md.pcibios_fixup_bus        = NULL;
 	ppc_md.pcibios_fixup            = NULL;
 #endif /* CONFIG_PCI         */
-
-#if defined(CONFIG_MAGIC_SYSRQ)
-	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
-#endif
 
 #ifdef CONFIG_SMP
 	ppc_md.smp_ops			= &iSeries_smp_ops;
diff -Nru a/arch/ppc/platforms/oak_setup.c b/arch/ppc/platforms/oak_setup.c
--- a/arch/ppc/platforms/oak_setup.c	Tue Jul 16 16:49:42 2002
+++ b/arch/ppc/platforms/oak_setup.c	Tue Jul 16 16:49:42 2002
@@ -117,14 +117,6 @@
 	ppc_md.set_rtc_time	 	= oak_set_rtc_time;
 	ppc_md.get_rtc_time	 	= oak_get_rtc_time;
 	ppc_md.calibrate_decr	 	= oak_calibrate_decr;
-
-	ppc_md.kbd_setkeycode    	= NULL;
-	ppc_md.kbd_getkeycode    	= NULL;
-	ppc_md.kbd_translate     	= NULL;
-	ppc_md.kbd_unexpected_up 	= NULL;
-	ppc_md.kbd_leds          	= NULL;
-	ppc_md.kbd_init_hw       	= NULL;
-	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
 }
 
 /*
diff -Nru a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c
--- a/arch/ppc/platforms/pmac_setup.c	Tue Jul 16 16:49:43 2002
+++ b/arch/ppc/platforms/pmac_setup.c	Tue Jul 16 16:49:43 2002
@@ -88,26 +88,6 @@
 extern int pmac_ide_check_base(ide_ioreg_t base);
 extern ide_ioreg_t pmac_ide_get_base(int index);
 
-extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int mackbd_getkeycode(unsigned int scancode);
-extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
-		     char raw_mode);
-extern char mackbd_unexpected_up(unsigned char keycode);
-extern void mackbd_leds(unsigned char leds);
-extern void __init mackbd_init_hw(void);
-extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
-				 char raw_mode);
-extern char mac_hid_kbd_unexpected_up(unsigned char keycode);
-extern void mac_hid_init_hw(void);
-extern unsigned char mac_hid_kbd_sysrq_xlate[];
-extern unsigned char pckbd_sysrq_xlate[];
-extern unsigned char mackbd_sysrq_xlate[];
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern int keyboard_sends_linux_keycodes;
 extern void pmac_nvram_update(void);
 extern unsigned char pmac_nvram_read_byte(int addr);
 extern void pmac_nvram_write_byte(int addr, unsigned char val);
@@ -641,37 +621,8 @@
 select_adb_keyboard(void)
 {
 #ifdef CONFIG_VT
-#ifdef CONFIG_INPUT
-	ppc_md.kbd_init_hw       = mac_hid_init_hw;
 	ppc_md.kbd_translate     = mac_hid_kbd_translate;
 	ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up;
-	ppc_md.kbd_setkeycode    = 0;
-	ppc_md.kbd_getkeycode    = 0;
-	ppc_md.kbd_leds		 = 0;
-#ifdef CONFIG_MAGIC_SYSRQ
-#ifdef CONFIG_MAC_ADBKEYCODES
-	if (!keyboard_sends_linux_keycodes) {
-		ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
-		SYSRQ_KEY = 0x69;
-	} else
-#endif /* CONFIG_MAC_ADBKEYCODES */
-	{
-		ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
-		SYSRQ_KEY = 0x54;
-	}
-#endif /* CONFIG_MAGIC_SYSRQ */
-#elif defined(CONFIG_ADB_KEYBOARD)
-	ppc_md.kbd_setkeycode       = mackbd_setkeycode;
-	ppc_md.kbd_getkeycode       = mackbd_getkeycode;
-	ppc_md.kbd_translate        = mackbd_translate;
-	ppc_md.kbd_unexpected_up    = mackbd_unexpected_up;
-	ppc_md.kbd_leds             = mackbd_leds;
-	ppc_md.kbd_init_hw          = mackbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.ppc_kbd_sysrq_xlate  = mackbd_sysrq_xlate;
-	SYSRQ_KEY = 0x69;
-#endif /* CONFIG_MAGIC_SYSRQ */
-#endif /* CONFIG_INPUT_ADBHID/CONFIG_ADB_KEYBOARD */
 #endif /* CONFIG_VT */
 }
 
diff -Nru a/arch/ppc/platforms/pplus_setup.c b/arch/ppc/platforms/pplus_setup.c
--- a/arch/ppc/platforms/pplus_setup.c	Tue Jul 16 16:49:43 2002
+++ b/arch/ppc/platforms/pplus_setup.c	Tue Jul 16 16:49:43 2002
@@ -77,15 +77,6 @@
 
 TODC_ALLOC();
 
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-		char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[128];
-
 extern void pplus_setup_hose(void);
 
 extern void pplus_set_VIA_IDE_native(void);
@@ -506,19 +497,6 @@
 	ppc_ide_md.default_irq = pplus_ide_default_irq;
 	ppc_ide_md.default_io_base = pplus_ide_default_io_base;
 	ppc_ide_md.ide_init_hwif = pplus_ide_init_hwif_ports;
-#endif
-
-#ifdef CONFIG_VT
-	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
-	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
-	ppc_md.kbd_translate     = pckbd_translate;
-	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-	ppc_md.kbd_leds          = pckbd_leds;
-	ppc_md.kbd_init_hw       = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
-	SYSRQ_KEY = 0x54;
-#endif
 #endif
 
 #ifdef CONFIG_SMP
diff -Nru a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
--- a/arch/ppc/platforms/prep_setup.c	Tue Jul 16 16:49:43 2002
+++ b/arch/ppc/platforms/prep_setup.c	Tue Jul 16 16:49:43 2002
@@ -79,15 +79,6 @@
 				 unsigned char val);
 extern void ibm_prep_init(void);
 
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-		char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[];
-
 extern void prep_find_bridges(void);
 extern char saved_command_line[];
 
@@ -893,19 +884,6 @@
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	ppc_ide_md.default_irq = prep_ide_default_irq;
 	ppc_ide_md.default_io_base = prep_ide_default_io_base;
-#endif
-
-#ifdef CONFIG_VT
-	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
-	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
-	ppc_md.kbd_translate     = pckbd_translate;
-	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-	ppc_md.kbd_leds          = pckbd_leds;
-	ppc_md.kbd_init_hw       = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
-	SYSRQ_KEY = 0x54;
-#endif
 #endif
 
 #ifdef CONFIG_SMP
diff -Nru a/arch/ppc/platforms/sandpoint_setup.c b/arch/ppc/platforms/sandpoint_setup.c
--- a/arch/ppc/platforms/sandpoint_setup.c	Tue Jul 16 16:49:43 2002
+++ b/arch/ppc/platforms/sandpoint_setup.c	Tue Jul 16 16:49:43 2002
@@ -97,15 +97,6 @@
 extern u_int openpic_irq(void);
 extern void openpic_eoi(void);
 
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-		                           char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[128];
-
 static void	sandpoint_halt(void);
 
 
@@ -644,19 +635,6 @@
 #else	/* !CONFIG_SERIAL_TEXT_DEBUG */
 	ppc_md.progress = NULL;
 #endif	/* CONFIG_SERIAL_TEXT_DEBUG */
-
-#ifdef CONFIG_VT
-	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
-	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
-	ppc_md.kbd_translate     = pckbd_translate;
-	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-	ppc_md.kbd_leds          = pckbd_leds;
-	ppc_md.kbd_init_hw       = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.ppc_kbd_sysrq_xlate       = pckbd_sysrq_xlate;
-	SYSRQ_KEY = 0x54;
-#endif
-#endif
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
         ppc_ide_md.default_irq = sandpoint_ide_default_irq;
diff -Nru a/arch/ppc/platforms/spruce_setup.c b/arch/ppc/platforms/spruce_setup.c
--- a/arch/ppc/platforms/spruce_setup.c	Tue Jul 16 16:49:41 2002
+++ b/arch/ppc/platforms/spruce_setup.c	Tue Jul 16 16:49:41 2002
@@ -64,13 +64,6 @@
 extern int spruce_get_irq(struct pt_regs *);
 extern void spruce_setup_hose(void);
 
-extern int pckbd_setkeycode(unsigned int, unsigned int);
-extern int pckbd_getkeycode(unsigned int);
-extern int pckbd_translate(unsigned char, unsigned char *, char);
-extern char pckbd_unexpected_up(unsigned char);
-extern void pckbd_leds(unsigned char);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[128];
 extern char cmd_line[];
 
 /*
@@ -279,18 +272,4 @@
 
 	ppc_md.nvram_read_val = todc_direct_read_val;
 	ppc_md.nvram_write_val = todc_direct_write_val;
-
-#ifdef CONFIG_VT
-	/* Spruce has a PS2 style keyboard */
-	ppc_md.kbd_setkeycode = pckbd_setkeycode;
-	ppc_md.kbd_getkeycode = pckbd_getkeycode;
-	ppc_md.kbd_translate = pckbd_translate;
-	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-	ppc_md.kbd_leds = pckbd_leds;
-	ppc_md.kbd_init_hw = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
-	SYSRQ_KEY = 0x54;
-#endif
-#endif
 }
diff -Nru a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c
--- a/arch/ppc/xmon/start.c	Tue Jul 16 16:49:41 2002
+++ b/arch/ppc/xmon/start.c	Tue Jul 16 16:49:41 2002
@@ -98,7 +98,7 @@
 
 #ifdef CONFIG_MAGIC_SYSRQ
 static void sysrq_handle_xmon(int key, struct pt_regs *regs,
-			      struct kbd_struct *kbd, struct tty_struct *tty)
+			      struct tty_struct *tty) 
 {
 	xmon(regs);
 }
diff -Nru a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c
--- a/arch/ppc64/kernel/pSeries_pci.c	Tue Jul 16 16:49:43 2002
+++ b/arch/ppc64/kernel/pSeries_pci.c	Tue Jul 16 16:49:43 2002
@@ -491,7 +491,7 @@
 					 0x100000); 
 
 		/* 
-		 * Firmware doesnt always clear this bit which is critical
+		 * Firmware doesn't always clear this bit which is critical
 		 * for good performance - Anton
 		 */
 		{
diff -Nru a/arch/ppc64/xmon/start.c b/arch/ppc64/xmon/start.c
--- a/arch/ppc64/xmon/start.c	Tue Jul 16 16:49:42 2002
+++ b/arch/ppc64/xmon/start.c	Tue Jul 16 16:49:42 2002
@@ -52,7 +52,7 @@
 }
 #endif
 
-static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, struct kbd_struct *kbd, struct tty_struct *tty) 
+static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, struct tty_struct *tty) 
 {
   xmon(pt_regs);
 }
diff -Nru a/arch/sh/config.in b/arch/sh/config.in
--- a/arch/sh/config.in	Tue Jul 16 16:49:42 2002
+++ b/arch/sh/config.in	Tue Jul 16 16:49:42 2002
@@ -175,7 +175,7 @@
    if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
       define_bool CONFIG_PCI_DIRECT y
    fi
-   bool 'Cache and PCI noncoherent' CONFIG_SH_PCIDMA_NONCOHERENT n
+   bool 'Cache and PCI noncoherent' CONFIG_SH_PCIDMA_NONCOHERENT
 fi
 
 source drivers/pci/Config.in
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Tue Jul 16 16:49:42 2002
+++ b/arch/sparc64/defconfig	Tue Jul 16 16:49:42 2002
@@ -389,10 +389,7 @@
 # Fusion MPT device support
 #
 CONFIG_FUSION=m
-
-#
-# (ability to boot linux kernel from Fusion device is DISABLED!)
-#
+# CONFIG_FUSION_BOOT is not set
 CONFIG_FUSION_ISENSE=m
 CONFIG_FUSION_CTL=m
 CONFIG_FUSION_LAN=m
@@ -576,22 +573,51 @@
 # Input device support
 #
 CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
 CONFIG_INPUT_KEYBDEV=y
 CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
 CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
 # CONFIG_GAMEPORT_NS558 is not set
 # CONFIG_GAMEPORT_L4 is not set
 # CONFIG_INPUT_EMU10K1 is not set
-# CONFIG_GAMEPORT_PCIGAME is not set
+# CONFIG_GAMEPORT_VORTEX is not set
 # CONFIG_GAMEPORT_FM801 is not set
 # CONFIG_GAMEPORT_CS461x is not set
 # CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
 # CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_PS2SERKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_JOYSTICK_ANALOG is not set
 # CONFIG_JOYSTICK_A3D is not set
@@ -599,6 +625,7 @@
 # CONFIG_JOYSTICK_COBRA is not set
 # CONFIG_JOYSTICK_GF2K is not set
 # CONFIG_JOYSTICK_GRIP is not set
+# CONFIG_JOYSTICK_GUILLEMOT is not set
 # CONFIG_JOYSTICK_INTERACT is not set
 # CONFIG_JOYSTICK_SIDEWINDER is not set
 # CONFIG_JOYSTICK_TMDC is not set
@@ -609,9 +636,13 @@
 # CONFIG_JOYSTICK_SPACEORB is not set
 # CONFIG_JOYSTICK_SPACEBALL is not set
 # CONFIG_JOYSTICK_STINGER is not set
+# CONFIG_JOYSTICK_TWIDDLER is not set
 # CONFIG_JOYSTICK_DB9 is not set
 # CONFIG_JOYSTICK_GAMECON is not set
 # CONFIG_JOYSTICK_TURBOGRAFX is not set
+# CONFIG_INPUT_JOYDUMP is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
 
 #
 # File systems
@@ -780,7 +811,6 @@
 #
 CONFIG_USB_EHCI_HCD=m
 CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_UHCI_HCD=m
 # CONFIG_USB_UHCI_HCD_ALT is not set
 
 #
diff -Nru a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
--- a/arch/sparc64/kernel/binfmt_elf32.c	Tue Jul 16 16:49:42 2002
+++ b/arch/sparc64/kernel/binfmt_elf32.c	Tue Jul 16 16:49:42 2002
@@ -136,6 +136,16 @@
 #define NEW_TO_OLD_UID(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
 #define NEW_TO_OLD_GID(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
 
+#include <linux/time.h>
+
+#define jiffies_to_timeval jiffies_to_timeval32
+static __inline__ void
+jiffies_to_timeval32(unsigned long jiffies, struct timeval32 *value)
+{
+	value->tv_usec = (jiffies % HZ) * (1000000L / HZ);
+	value->tv_sec = jiffies / HZ;
+}
+
 #define elf_addr_t	u32
 #define elf_caddr_t	u32
 #undef start_thread
diff -Nru a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
--- a/arch/sparc64/kernel/time.c	Tue Jul 16 16:49:42 2002
+++ b/arch/sparc64/kernel/time.c	Tue Jul 16 16:49:42 2002
@@ -688,7 +688,7 @@
 
 	/* 
 	 * Not having a register set can lead to trouble.
-	 * Also starfire doesnt have a tod clock.
+	 * Also starfire doesn't have a tod clock.
 	 */
 	if (!mregs && !dregs) 
 		return -1;
diff -Nru a/drivers/acorn/scsi/Config.in b/drivers/acorn/scsi/Config.in
--- a/drivers/acorn/scsi/Config.in	Tue Jul 16 16:49:41 2002
+++ b/drivers/acorn/scsi/Config.in	Tue Jul 16 16:49:41 2002
@@ -14,10 +14,10 @@
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    comment 'The following drivers are not fully supported'
 
-   dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI
+   dep_tristate 'CumanaSCSI I support (EXPERIMENTAL)' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI
    if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then
-      dep_tristate 'EcoScsi support' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI
+      dep_tristate 'EcoScsi support (EXPERIMENTAL)' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI
    fi
-   dep_tristate 'Oak SCSI support' CONFIG_SCSI_OAK1 $CONFIG_SCSI
+   dep_tristate 'Oak SCSI support (EXPERIMENTAL)' CONFIG_SCSI_OAK1 $CONFIG_SCSI
 fi
 
diff -Nru a/drivers/acpi/Config.help b/drivers/acpi/Config.help
--- a/drivers/acpi/Config.help	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/Config.help	Tue Jul 16 16:49:42 2002
@@ -91,3 +91,25 @@
   of verbosity. Saying Y enables these statements. This will increase
   your kernel size by around 50K.
 
+CONFIG_ACPI_TOSHIBA
+  This driver adds support for access to certain system settings
+  on "legacy free" Toshiba laptops.  These laptops can be recognized by
+  their lack of a BIOS setup menu and APM support.
+
+  On these machines, all system configuration is handled through the
+  ACPI.  This driver is required for access to controls not covered
+  by the general ACPI drivers, such as LCD brightness, video output,
+  etc.
+
+  This driver differs from the non-ACPI Toshiba laptop driver (located
+  under "Processor type and features") in several aspects.
+  Configuration is accessed by reading and writing text files in the
+  /proc tree instead of by program interface to /dev.  Furthermore, no
+  power management functions are exposed, as those are handled by the
+  general ACPI drivers.
+
+  More information about this driver is available at
+  <http://memebeam.org/toys/ToshibaAcpiDriver>.
+
+  If you have a legacy free Toshiba laptop (such as the Libretto L1
+  series), say Y.
diff -Nru a/drivers/acpi/Config.in b/drivers/acpi/Config.in
--- a/drivers/acpi/Config.in	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/Config.in	Tue Jul 16 16:49:43 2002
@@ -31,6 +31,7 @@
       tristate     '  Fan'		CONFIG_ACPI_FAN
       tristate     '  Processor'	CONFIG_ACPI_PROCESSOR
       dep_tristate '  Thermal Zone' 	CONFIG_ACPI_THERMAL $CONFIG_ACPI_PROCESSOR
+      tristate     '  Toshiba Laptop Extras'	CONFIG_ACPI_TOSHIBA
       bool         '  Debug Statements'	CONFIG_ACPI_DEBUG
     fi
   fi
diff -Nru a/drivers/acpi/Makefile b/drivers/acpi/Makefile
--- a/drivers/acpi/Makefile	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/Makefile	Tue Jul 16 16:49:42 2002
@@ -43,5 +43,6 @@
 obj-$(CONFIG_ACPI_PROCESSOR)	+= processor.o
 obj-$(CONFIG_ACPI_THERMAL)	+= thermal.o
 obj-$(CONFIG_ACPI_SYSTEM)	+= system.o
+obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/acpi/acpi_bus.h b/drivers/acpi/acpi_bus.h
--- a/drivers/acpi/acpi_bus.h	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/acpi_bus.h	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_bus.h - ACPI Bus Driver ($Revision: 21 $)
+ *  acpi_bus.h - ACPI Bus Driver ($Revision: 22 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -46,7 +46,6 @@
 
 /* acpi_utils.h */
 acpi_status acpi_extract_package (acpi_object *, acpi_buffer *, acpi_buffer *);
-acpi_status acpi_evaluate (acpi_handle, acpi_string, acpi_object_list *, acpi_buffer *);
 acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *);
 acpi_status acpi_evaluate_reference (acpi_handle, acpi_string, acpi_object_list *, struct acpi_handle_list *);
 
diff -Nru a/drivers/acpi/acpi_drivers.h b/drivers/acpi/acpi_drivers.h
--- a/drivers/acpi/acpi_drivers.h	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/acpi_drivers.h	Tue Jul 16 16:49:43 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_drivers.h  ($Revision: 30 $)
+ *  acpi_drivers.h  ($Revision: 31 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -124,6 +124,7 @@
 
 #ifdef CONFIG_ACPI_EC
 
+int acpi_ec_ecdt_probe (void);
 int acpi_ec_init (void);
 void acpi_ec_exit (void);
 
diff -Nru a/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c
--- a/drivers/acpi/acpi_ksyms.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/acpi_ksyms.c	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_ksyms.c - ACPI Kernel Symbols ($Revision: 15 $)
+ *  acpi_ksyms.c - ACPI Kernel Symbols ($Revision: 16 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -102,7 +102,6 @@
 /* ACPI Utilities (acpi_utils.c) */
 
 EXPORT_SYMBOL(acpi_extract_package);
-EXPORT_SYMBOL(acpi_evaluate);
 EXPORT_SYMBOL(acpi_evaluate_integer);
 EXPORT_SYMBOL(acpi_evaluate_reference);
 
diff -Nru a/drivers/acpi/battery.c b/drivers/acpi/battery.c
--- a/drivers/acpi/battery.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/battery.c	Tue Jul 16 16:49:41 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_battery.c - ACPI Battery Driver ($Revision: 35 $)
+ *  acpi_battery.c - ACPI Battery Driver ($Revision: 36 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -251,7 +251,7 @@
 
 	arg0.integer.value = alarm;
 
-	status = acpi_evaluate(battery->handle, "_BTP", &arg_list, NULL);
+	status = acpi_evaluate_object(battery->handle, "_BTP", &arg_list, NULL);
 	if (ACPI_FAILURE(status))
 		return_VALUE(-ENODEV);
 
diff -Nru a/drivers/acpi/bus.c b/drivers/acpi/bus.c
--- a/drivers/acpi/bus.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/bus.c	Tue Jul 16 16:49:43 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_bus.c - ACPI Bus Driver ($Revision: 77 $)
+ *  acpi_bus.c - ACPI Bus Driver ($Revision: 79 $)
  *
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
  *
@@ -1052,11 +1052,17 @@
 			break;
 		}
 
-		if (!cid[0])
+		if (!cid[0]) {
+			acpi_os_free(buffer.pointer);
 			return -ENOENT;
+		}
 
-		if (strstr(driver->ids, cid))
+		if (strstr(driver->ids, cid)) {
+			acpi_os_free(buffer.pointer);
 			return 0;
+		}
+
+		acpi_os_free(buffer.pointer);
 	}
 
 	return -ENOENT;
@@ -1802,7 +1808,7 @@
 	int			result = 0;
 	struct acpi_device	*device = NULL;
 
-	ACPI_FUNCTION_TRACE("acpi_bus_scan");
+	ACPI_FUNCTION_TRACE("acpi_bus_scan_fixed");
 
 	if (!root)
 		return_VALUE(-ENODEV);
@@ -1929,116 +1935,99 @@
 	int			result = 0;
 	acpi_status		status = AE_OK;
 	acpi_buffer		buffer = {sizeof(acpi_fadt), &acpi_fadt};
-	int			progress = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_bus_init");
 
-	/*
-	 * [0] Initailize the ACPI Core Subsystem.
-	 */
 	status = acpi_initialize_subsystem();
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to initialize the ACPI Interpreter\n");
-		result = -ENODEV;
-		goto end;
+		goto error0;
 	}
 
-	progress++;
-
-	/*
-	 * [1] Load the ACPI tables.
-	 */
 	status = acpi_load_tables();
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to load the System Description Tables\n");
-		result = -ENODEV;
-		goto end;
+		goto error0;
 	}
 
-	progress++;
-
-	/*
-	 * [2] Check the blacklist
-	 */
 	if (acpi_blacklisted()) {
-		result = -ENODEV;
-		goto end;
+		goto error1;
 	}
 
-	progress++;
-
 	/*
-	 * [3] Get a separate copy of the FADT for use by other drivers.
+	 * Get a separate copy of the FADT for use by other drivers.
 	 */
 	status = acpi_get_table(ACPI_TABLE_FADT, 1, &buffer);
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to get the FADT\n");
-		result = -ENODEV;
-		goto end;
+		goto error1;
 	}
 
-	progress++;
+	status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_ERR PREFIX "Unable to start the ACPI Interpreter\n");
+		goto error1;
+	}
 
+#ifdef CONFIG_ACPI_EC
 	/*
-	 * [4] Enable the ACPI Core Subsystem.
+	 * ACPI 2.0 requires the EC driver to be loaded and work before
+	 * the EC device is found in the namespace. This is accomplished
+	 * by looking for the ECDT table, and getting the EC parameters out
+	 * of that.
 	 */
-	status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION);
+	result = acpi_ec_ecdt_probe();
+	if (result) {
+		goto error1;
+	}
+#endif
+
+	status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION);
 	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR PREFIX "Unable to start the ACPI Interpreter\n");
-		result = -ENODEV;
-		goto end;
+		printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n");
+		goto error1;
 	}
 
 	printk(KERN_INFO PREFIX "Interpreter enabled\n");
 
-	progress++;
-
 	/*
-	 * [5] Get the system interrupt model and evaluate \_PIC.
+	 * Get the system interrupt model and evaluate \_PIC.
 	 */
 	result = acpi_bus_init_irq();
 	if (result)
-		goto end;
-
-	progress++;
+		goto error1;
 
 	/*
-	 * [6] Register for all standard device notifications.
+	 * Register the for all standard device notifications.
 	 */
 	status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, &acpi_bus_notify, NULL);
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to register for device notifications\n");
 		result = -ENODEV;
-		goto end;
+		goto error1;
 	}
 
-	progress++;
-
 	/*
-	 * [7] Create the root device.
+	 * Create the root device in the bus's device tree
 	 */
 	result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, 
 		ACPI_BUS_TYPE_SYSTEM);
 	if (result)
-		goto end;
-
-	progress++;
+		goto error2;
 
 	/*
-	 * [8] Create the root file system.
+	 * Create the top ACPI proc directory
 	 */
 	acpi_device_dir(acpi_root) = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);
 	if (!acpi_root) {
 		result = -ENODEV;
-		goto end;
+		goto error3;
 	}
 	acpi_root_dir = acpi_device_dir(acpi_root);
 
-	progress++;
-
 	/*
-	 * [9] Install drivers required for proper enumeration of the
-	 *     ACPI namespace.
+	 * Install drivers required for proper enumeration of the
+	 * ACPI namespace.
 	 */
 	acpi_system_init();	/* ACPI System */
 	acpi_power_init();	/* ACPI Bus Power Management */
@@ -2049,41 +2038,30 @@
 	acpi_pci_link_init();	/* ACPI PCI Interrupt Link */
 	acpi_pci_root_init();	/* ACPI PCI Root Bridge */
 #endif
-	progress++;
-
 	/*
-	 * [10] Enumerate devices in the ACPI namespace.
+	 * Enumerate devices in the ACPI namespace.
 	 */
 	result = acpi_bus_scan_fixed(acpi_root);
 	if (result)
-		goto end;
+		goto error4;
 	result = acpi_bus_scan(acpi_root);
 	if (result)
-		goto end;
-
-end:
-	/*
-	 * Clean up if anything went awry.
-	 */
-	if (result) {
-		switch (progress) {
-		case 10:
-		case 9: remove_proc_entry("ACPI", NULL);
-		case 8: acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
-		case 7: acpi_remove_notify_handler(ACPI_ROOT_OBJECT,
-				ACPI_SYSTEM_NOTIFY, &acpi_bus_notify);
-		case 6:
-		case 5:
-		case 4:
-		case 3:
-		case 2: acpi_terminate();
-		case 1:
-		case 0:
-		default: return_VALUE(-ENODEV);
-		}
-	}
+		goto error4;
 
 	return_VALUE(0);
+
+	/* Mimic structured exception handling */
+error4:
+	remove_proc_entry("ACPI", NULL);
+error3:
+	acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
+error2:
+	acpi_remove_notify_handler(ACPI_ROOT_OBJECT,
+		ACPI_SYSTEM_NOTIFY, &acpi_bus_notify);
+error1:
+	acpi_terminate();
+error0:
+	return_VALUE(-ENODEV);
 }
 
 
diff -Nru a/drivers/acpi/debugger/dbdisasm.c b/drivers/acpi/debugger/dbdisasm.c
--- a/drivers/acpi/debugger/dbdisasm.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/debugger/dbdisasm.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dbdisasm - parser op tree display routines
- *              $Revision: 66 $
+ *              $Revision: 67 $
  *
  ******************************************************************************/
 
@@ -674,7 +674,8 @@
 			(walk_state) &&
 			(walk_state->results) &&
 			(walk_state->results->results.num_results)) {
-			acpi_db_decode_internal_object (walk_state->results->results.obj_desc [walk_state->results->results.num_results-1]);
+			acpi_db_decode_internal_object (
+				walk_state->results->results.obj_desc [walk_state->results->results.num_results-1]);
 		}
 #endif
 		break;
diff -Nru a/drivers/acpi/debugger/dbdisply.c b/drivers/acpi/debugger/dbdisply.c
--- a/drivers/acpi/debugger/dbdisply.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/debugger/dbdisply.c	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dbdisply - debug display commands
- *              $Revision: 75 $
+ *              $Revision: 76 $
  *
  ******************************************************************************/
 
@@ -300,6 +300,11 @@
 		return;
 	}
 
+	if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) {
+		acpi_os_printf ("%p", obj_desc);
+		return;
+	}
+
 	acpi_os_printf (" %s", acpi_ut_get_object_type_name (obj_desc));
 
 	switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
@@ -336,7 +341,8 @@
 
 
 	default:
-		/* No additional display for other types */
+
+		acpi_os_printf ("%p", obj_desc);
 		break;
 	}
 }
@@ -344,6 +350,38 @@
 
 /*******************************************************************************
  *
+ * FUNCTION:    Acpi_db_decode_node
+ *
+ * PARAMETERS:  Node        - Object to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Short display of a namespace node
+ *
+ ******************************************************************************/
+
+void
+acpi_db_decode_node (
+	acpi_namespace_node     *node)
+{
+
+
+	acpi_os_printf ("<Node>          Name %4.4s Type-%s",
+		node->name.ascii, acpi_ut_get_type_name (node->type));
+
+	if (node->flags & ANOBJ_METHOD_ARG) {
+		acpi_os_printf (" [Method Arg]");
+	}
+	if (node->flags & ANOBJ_METHOD_LOCAL) {
+		acpi_os_printf (" [Method Local]");
+	}
+
+	acpi_db_decode_internal_object (acpi_ns_get_attached_object (node));
+}
+
+
+/*******************************************************************************
+ *
  * FUNCTION:    Acpi_db_display_internal_object
  *
  * PARAMETERS:  Obj_desc        - Object to be displayed
@@ -381,16 +419,7 @@
 
 	case ACPI_DESC_TYPE_NAMED:
 
-		acpi_os_printf ("<Node>          Name %4.4s Type-%s",
-				  ((acpi_namespace_node *)obj_desc)->name.ascii,
-				  acpi_ut_get_type_name (((acpi_namespace_node *) obj_desc)->type));
-
-		if (((acpi_namespace_node *) obj_desc)->flags & ANOBJ_METHOD_ARG) {
-			acpi_os_printf (" [Method Arg]");
-		}
-		if (((acpi_namespace_node *) obj_desc)->flags & ANOBJ_METHOD_LOCAL) {
-			acpi_os_printf (" [Method Local]");
-		}
+		acpi_db_decode_node ((acpi_namespace_node *) obj_desc);
 		break;
 
 
@@ -406,8 +435,10 @@
 
 		switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
 		case INTERNAL_TYPE_REFERENCE:
+
 			switch (obj_desc->reference.opcode) {
 			case AML_LOCAL_OP:
+
 				acpi_os_printf ("[Local%d] ", obj_desc->reference.offset);
 				if (walk_state) {
 					obj_desc = walk_state->local_variables[obj_desc->reference.offset].object;
@@ -416,7 +447,9 @@
 				}
 				break;
 
+
 			case AML_ARG_OP:
+
 				acpi_os_printf ("[Arg%d] ", obj_desc->reference.offset);
 				if (walk_state) {
 					obj_desc = walk_state->arguments[obj_desc->reference.offset].object;
@@ -425,24 +458,51 @@
 				}
 				break;
 
+
 			case AML_DEBUG_OP:
+
 				acpi_os_printf ("[Debug] ");
 				break;
 
+
 			case AML_INDEX_OP:
-				acpi_os_printf ("[Index]         ");
+
+				acpi_os_printf ("[Index]        ");
 				acpi_db_decode_internal_object (obj_desc->reference.object);
 				break;
 
+
+			case AML_REF_OF_OP:
+
+				acpi_os_printf ("[Reference]    ");
+
+				/* Reference can be to a Node or an Operand object */
+
+				switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc->reference.object)) {
+				case ACPI_DESC_TYPE_NAMED:
+					acpi_db_decode_node (obj_desc->reference.object);
+					break;
+
+				case ACPI_DESC_TYPE_OPERAND:
+					acpi_db_decode_internal_object (obj_desc->reference.object);
+					break;
+
+				default:
+					break;
+				}
+				break;
+
+
 			default:
+
 				acpi_os_printf ("Unknown Reference opcode %X\n",
 					obj_desc->reference.opcode);
 				break;
-
 			}
 			break;
 
 		default:
+
 			acpi_os_printf ("<Obj> ");
 			acpi_os_printf ("         ");
 			acpi_db_decode_internal_object (obj_desc);
diff -Nru a/drivers/acpi/debugger/dbexec.c b/drivers/acpi/debugger/dbexec.c
--- a/drivers/acpi/debugger/dbexec.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/debugger/dbexec.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dbexec - debugger control method execution
- *              $Revision: 41 $
+ *              $Revision: 42 $
  *
  ******************************************************************************/
 
@@ -223,6 +223,9 @@
 	acpi_gbl_db_method_info.args = args;
 	acpi_gbl_db_method_info.flags = flags;
 
+	return_obj.pointer = NULL;
+	return_obj.length = ACPI_ALLOCATE_BUFFER;
+
 	acpi_db_execute_setup (&acpi_gbl_db_method_info);
 	status = acpi_db_execute_method (&acpi_gbl_db_method_info, &return_obj);
 
@@ -259,6 +262,10 @@
 			acpi_os_printf ("Execution of %s returned object %p Buflen %X\n",
 				acpi_gbl_db_method_info.pathname, return_obj.pointer, return_obj.length);
 			acpi_db_dump_object (return_obj.pointer, 1);
+		}
+		else {
+			acpi_os_printf ("No return object from execution of %s\n",
+				acpi_gbl_db_method_info.pathname);
 		}
 	}
 
diff -Nru a/drivers/acpi/debugger/dbfileio.c b/drivers/acpi/debugger/dbfileio.c
--- a/drivers/acpi/debugger/dbfileio.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/debugger/dbfileio.c	Tue Jul 16 16:49:41 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: dbfileio - Debugger file I/O commands.  These can't usually
  *              be used when running the debugger in Ring 0 (Kernel mode)
- *              $Revision: 63 $
+ *              $Revision: 64 $
  *
  ******************************************************************************/
 
@@ -279,9 +279,13 @@
 		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
 
-	/* Install the new table into the local data structures */
-
 	table_info.pointer = table_ptr;
+	status = acpi_tb_recognize_table (&table_info, ACPI_TABLE_SECONDARY);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	/* Install the new table into the local data structures */
 
 	status = acpi_tb_install_table (&table_info);
 	if (ACPI_FAILURE (status)) {
diff -Nru a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
--- a/drivers/acpi/dispatcher/dsmethod.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/dispatcher/dsmethod.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
- *              $Revision: 86 $
+ *              $Revision: 87 $
  *
  *****************************************************************************/
 
@@ -290,7 +290,7 @@
 
 	/* Create and init a Root Node */
 
-	op = acpi_ps_alloc_op (AML_SCOPE_OP);
+	op = acpi_ps_create_scope_op ();
 	if (!op) {
 		status = AE_NO_MEMORY;
 		goto cleanup;
diff -Nru a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
--- a/drivers/acpi/dispatcher/dsobject.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/dispatcher/dsobject.c	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dsobject - Dispatcher object management routines
- *              $Revision: 103 $
+ *              $Revision: 104 $
  *
  *****************************************************************************/
 
@@ -368,6 +368,8 @@
 
 			obj_desc->reference.opcode = AML_LOCAL_OP;
 			obj_desc->reference.offset = opcode - AML_LOCAL_OP;
+			acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset,
+				walk_state, (acpi_namespace_node **) &obj_desc->reference.object);
 			break;
 
 
diff -Nru a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
--- a/drivers/acpi/dispatcher/dswload.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/dispatcher/dswload.c	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dswload - Dispatcher namespace load callbacks
- *              $Revision: 66 $
+ *              $Revision: 67 $
  *
  *****************************************************************************/
 
@@ -448,12 +448,6 @@
 	if (op->common.aml_opcode == AML_SCOPE_OP) {
 		ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
 			"Ending scope Op=%p State=%p\n", op, walk_state));
-
-		if (op->named.name == ACPI_UINT16_MAX) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unnamed scope! Op=%p State=%p\n",
-				op, walk_state));
-			return (AE_OK);
-		}
 	}
 
 
diff -Nru a/drivers/acpi/ec.c b/drivers/acpi/ec.c
--- a/drivers/acpi/ec.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/ec.c	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 31 $)
+ *  acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 35 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -76,13 +76,18 @@
 struct acpi_ec {
 	acpi_handle		handle;
 	unsigned long		gpe_bit;
-	unsigned long		status_port;
-	unsigned long		command_port;
-	unsigned long		data_port;
+	acpi_generic_address	status_addr;
+	acpi_generic_address	command_addr;
+	acpi_generic_address	data_addr;
 	unsigned long		global_lock;
 	spinlock_t		lock;
 };
 
+/* If we find an EC via the ECDT, we need to keep a ptr to its context */
+static struct acpi_ec	*ec_ecdt;
+/* compare this against UIDs in properly enumerated ECs to determine if we
+   have a dupe */
+static unsigned long		ecdt_uid = 0xFFFFFFFF;
 
 /* --------------------------------------------------------------------------
                              Transaction Management
@@ -93,7 +98,7 @@
 	struct acpi_ec		*ec,
 	u8			event)
 {
-	u8			acpi_ec_status = 0;
+	u32			acpi_ec_status = 0;
 	u32			i = ACPI_EC_UDELAY_COUNT;
 
 	if (!ec)
@@ -103,7 +108,7 @@
 	switch (event) {
 	case ACPI_EC_EVENT_OBF:
 		do {
-			acpi_ec_status = inb(ec->status_port);
+			acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr, 0);
 			if (acpi_ec_status & ACPI_EC_FLAG_OBF)
 				return 0;
 			udelay(ACPI_EC_UDELAY);
@@ -111,7 +116,7 @@
 		break;
 	case ACPI_EC_EVENT_IBE:
 		do {
-			acpi_ec_status = inb(ec->status_port);
+			acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr, 0);
 			if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
 				return 0;
 			udelay(ACPI_EC_UDELAY);
@@ -151,17 +156,18 @@
 	
 	spin_lock_irqsave(&ec->lock, flags);
 
-	outb(ACPI_EC_COMMAND_READ, ec->command_port);
+	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr, 0);
 	result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
 	if (result)
 		goto end;
 
-	outb(address, ec->data_port);
+	acpi_hw_low_level_write(8, address, &ec->data_addr, 0);
 	result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
 	if (result)
 		goto end;
 
-	*data = inb(ec->data_port);
+
+	acpi_hw_low_level_read(8, (u32*) data, &ec->data_addr, 0);
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
 		*data, address));
@@ -200,17 +206,17 @@
 
 	spin_lock_irqsave(&ec->lock, flags);
 
-	outb(ACPI_EC_COMMAND_WRITE, ec->command_port);
+	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr, 0);
 	result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
 	if (result)
 		goto end;
 
-	outb(address, ec->data_port);
+	acpi_hw_low_level_write(8, address, &ec->data_addr, 0);
 	result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
 	if (result)
 		goto end;
 
-	outb(data, ec->data_port);
+	acpi_hw_low_level_write(8, data, &ec->data_addr, 0);
 	result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
 	if (result)
 		goto end;
@@ -256,15 +262,14 @@
 	 * Note that successful completion of the query causes the ACPI_EC_SCI
 	 * bit to be cleared (and thus clearing the interrupt source).
 	 */
-
 	spin_lock_irqsave(&ec->lock, flags);
 
-	outb(ACPI_EC_COMMAND_QUERY, ec->command_port);
+	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr, 0);
 	result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
 	if (result)
 		goto end;
 	
-	*data = inb(ec->data_port);
+	acpi_hw_low_level_read(8, (u32*) data, &ec->data_addr, 0);
 	if (!*data)
 		result = -ENODATA;
 
@@ -309,7 +314,7 @@
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
 
-	acpi_evaluate(query_data->handle, object_name, NULL, NULL);
+	acpi_evaluate_object(query_data->handle, object_name, NULL, NULL);
 
 	kfree(query_data);
 
@@ -331,7 +336,7 @@
 		return;
 
 	spin_lock_irqsave(&ec->lock, flags);
-	value = inb(ec->command_port);
+	acpi_hw_low_level_read(8, (u32*) &value, &ec->command_addr, 0);
 	spin_unlock_irqrestore(&ec->lock, flags);
 
 	/* TBD: Implement asynch events!
@@ -340,7 +345,6 @@
 	 *       treat EC-SCIs as level (versus EDGE!) triggered, preventing
 	 *       a purely interrupt-driven approach (grumble, grumble).
 	 */
-
 	if (!(value & ACPI_EC_FLAG_SCI))
 		return;
 
@@ -459,7 +463,7 @@
 	p += sprintf(p, "gpe bit:                 0x%02x\n",
 		(u32) ec->gpe_bit);
 	p += sprintf(p, "ports:                   0x%02x, 0x%02x\n",
-		(u32) ec->status_port, (u32) ec->data_port);
+		(u32) ec->status_addr.address, (u32) ec->data_addr.address);
 	p += sprintf(p, "use global lock:         %s\n",
 		ec->global_lock?"yes":"no");
 
@@ -535,6 +539,7 @@
 	int			result = 0;
 	acpi_status		status = AE_OK;
 	struct acpi_ec		*ec = NULL;
+	unsigned long		uid;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_add");
 
@@ -555,6 +560,14 @@
 	/* Use the global lock for all EC transactions? */
 	acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock);
 
+	/* If our UID matches ecdt_uid, we already found this EC via the
+	   ECDT. Abort. */
+	acpi_evaluate_integer(ec->handle, "_UID", NULL, &uid);
+	if (ecdt_uid == uid) {
+		result = -ENODEV;
+		goto end;
+	}
+
 	/* Get GPE bit assignment (EC events). */
 	status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe_bit);
 	if (ACPI_FAILURE(status)) {
@@ -623,9 +636,8 @@
 		return_VALUE(-EINVAL);
 
 	/*
-	 * Get I/O port addresses
+	 * Get I/O port addresses. Convert to GAS format.
 	 */
-
 	status = acpi_get_current_resources(ec->handle, &buffer);
 	if (ACPI_FAILURE(status)) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error getting I/O port addresses"));
@@ -638,7 +650,10 @@
 		result = -ENODEV;
 		goto end;
 	}
-	ec->data_port = resource->data.io.min_base_address;
+	ec->data_addr.address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
+	ec->data_addr.register_bit_width = 8;
+	ec->data_addr.register_bit_offset = 0;
+	ec->data_addr.address = resource->data.io.min_base_address;
 
 	resource = ACPI_NEXT_RESOURCE(resource);
 	if (!resource || (resource->id != ACPI_RSTYPE_IO)) {
@@ -646,30 +661,36 @@
 		result = -ENODEV;
 		goto end;
 	}
-	ec->command_port = ec->status_port = resource->data.io.min_base_address;
+	ec->command_addr.address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
+	ec->command_addr.register_bit_width = 8;
+	ec->command_addr.register_bit_offset = 0;
+	ec->command_addr.address = resource->data.io.min_base_address;
+	ec->status_addr = ec->command_addr;
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02x, ports=0x%2x,0x%2x\n",
-		(u32) ec->gpe_bit, (u32) ec->command_port, (u32) ec->data_port));
+		(u32) ec->gpe_bit, (u32) ec->command_addr.address,
+		(u32) ec->data_addr.address));
 
 	/*
 	 * Install GPE handler
 	 */
-
 	status = acpi_install_gpe_handler(ec->gpe_bit,
 		ACPI_EVENT_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec);
-	if (ACPI_FAILURE(status))
-		return_VALUE(-ENODEV);
+	if (ACPI_FAILURE(status)) {
+		result = -ENODEV;
+		goto end;
+	}
 
 	status = acpi_install_address_space_handler (ec->handle,
 			ACPI_ADR_SPACE_EC, &acpi_ec_space_handler,
 			&acpi_ec_space_setup, ec);
 	if (ACPI_FAILURE(status)) {
-		acpi_remove_address_space_handler(ec->handle,
-			ACPI_ADR_SPACE_EC, &acpi_ec_space_handler);
-		return_VALUE(-ENODEV);
+		acpi_remove_gpe_handler(ec->gpe_bit, &acpi_ec_gpe_handler);
+		result = -ENODEV;
+		goto end;
 	}
 end:
-	kfree(buffer.pointer);
+	acpi_os_free(buffer.pointer);
 
 	return_VALUE(result);
 }
@@ -704,6 +725,64 @@
 
 
 int __init
+acpi_ec_ecdt_probe (void)
+{
+	acpi_status		status;
+	struct acpi_table_ecdt 	*ecdt_ptr;
+
+	status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING, 
+		(acpi_table_header **) &ecdt_ptr);
+	if (ACPI_SUCCESS(status)) {
+		printk(KERN_INFO PREFIX "Found ECDT\n");
+
+		/*
+		 * TODO: When the new driver model allows it, simply tell the
+		 * EC driver it has a new device via that, instead if this.
+		 */
+		ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+		if (!ec_ecdt)
+			return -ENOMEM;
+		memset(ec_ecdt, 0, sizeof(struct acpi_ec));
+		
+		ec_ecdt->command_addr = ecdt_ptr->ec_control;
+		ec_ecdt->status_addr = ecdt_ptr->ec_control;
+		ec_ecdt->data_addr = ecdt_ptr->ec_data;
+		ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
+		ec_ecdt->lock = SPIN_LOCK_UNLOCKED;
+		/* use the GL just to be safe */
+		ec_ecdt->global_lock = TRUE;
+		ecdt_uid = ecdt_ptr->uid;
+
+		/*
+		 * Install GPE handler
+		 */
+		status = acpi_install_gpe_handler(ec_ecdt->gpe_bit,
+			ACPI_EVENT_EDGE_TRIGGERED, &acpi_ec_gpe_handler,
+			ec_ecdt);
+		if (ACPI_FAILURE(status)) {
+			goto error;
+		}
+
+		status = acpi_install_address_space_handler (ACPI_ROOT_OBJECT,
+				ACPI_ADR_SPACE_EC, &acpi_ec_space_handler,
+				&acpi_ec_space_setup, ec_ecdt);
+		if (ACPI_FAILURE(status)) {
+			acpi_remove_gpe_handler(ec_ecdt->gpe_bit,
+				&acpi_ec_gpe_handler);
+			goto error;
+		}
+	}
+
+	return 0;
+
+error:
+	kfree(ec_ecdt);
+
+	return -ENODEV;
+}
+
+
+int __init
 acpi_ec_init (void)
 {
 	int			result = 0;
@@ -719,6 +798,19 @@
 	return_VALUE(0);
 }
 
+void __exit
+acpi_ec_ecdt_exit (void)
+{
+	if (!ec_ecdt)
+		return;
+
+	acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
+		ACPI_ADR_SPACE_EC, &acpi_ec_space_handler);
+	
+	acpi_remove_gpe_handler(ec_ecdt->gpe_bit, &acpi_ec_gpe_handler);
+
+	kfree(ec_ecdt);
+}
 
 void __exit
 acpi_ec_exit (void)
@@ -730,6 +822,9 @@
 	result = acpi_bus_unregister_driver(&acpi_ec_driver);
 	if (!result)
 		remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
+
+
+	acpi_ec_ecdt_exit();
 
 	return_VOID;
 }
diff -Nru a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
--- a/drivers/acpi/executer/exconfig.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/executer/exconfig.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes)
- *              $Revision: 66 $
+ *              $Revision: 67 $
  *
  *****************************************************************************/
 
@@ -138,6 +138,7 @@
 	ACPI_FUNCTION_TRACE ("Ex_load_table_op");
 
 
+#if 0
 	/*
 	 * Make sure that the signature does not match one of the tables that
 	 * is already loaded.
@@ -148,6 +149,7 @@
 
 		return_ACPI_STATUS (AE_ALREADY_EXISTS);
 	}
+#endif
 
 	/* Find the ACPI table */
 
diff -Nru a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
--- a/drivers/acpi/executer/exdump.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/executer/exdump.c	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exdump - Interpreter debug output routines
- *              $Revision: 155 $
+ *              $Revision: 156 $
  *
  *****************************************************************************/
 
@@ -121,6 +121,13 @@
 			break;
 
 
+		case AML_REF_OF_OP:
+
+			acpi_os_printf ("Reference: (Ref_of) %p\n",
+					 obj_desc->reference.object);
+			break;
+
+
 		case AML_ARG_OP:
 
 			acpi_os_printf ("Reference: Arg%d",
@@ -157,9 +164,11 @@
 
 
 		case AML_INT_NAMEPATH_OP:
+
 			acpi_os_printf ("Reference.Node->Name %X\n",
 					 obj_desc->reference.node->name.integer);
 			break;
+
 
 		default:
 
diff -Nru a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
--- a/drivers/acpi/executer/exmisc.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/executer/exmisc.c	Tue Jul 16 16:49:43 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
- *              $Revision: 106 $
+ *              $Revision: 107 $
  *
  *****************************************************************************/
 
@@ -39,8 +39,9 @@
  *
  * FUNCTION:    Acpi_ex_get_object_reference
  *
- * PARAMETERS:  Obj_desc        - Create a reference to this object
- *              Return_desc        - Where to store the reference
+ * PARAMETERS:  Obj_desc            - Create a reference to this object
+ *              Return_desc         - Where to store the reference
+ *              Walk_state          - Current state
  *
  * RETURN:      Status
  *
@@ -55,65 +56,75 @@
 	acpi_operand_object     **return_desc,
 	acpi_walk_state         *walk_state)
 {
-	acpi_status             status = AE_OK;
+	acpi_operand_object     *reference_obj;
+	acpi_operand_object     *referenced_obj;
 
 
 	ACPI_FUNCTION_TRACE_PTR ("Ex_get_object_reference", obj_desc);
 
 
+	*return_desc = NULL;
+
 	switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) {
 	case ACPI_DESC_TYPE_OPERAND:
 
 		if (ACPI_GET_OBJECT_TYPE (obj_desc) != INTERNAL_TYPE_REFERENCE) {
-			*return_desc = NULL;
-			status = AE_TYPE;
-			goto cleanup;
+			return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 		}
 
 		/*
-		 * Not a Name -- an indirect name pointer would have
-		 * been converted to a direct name pointer in Acpi_ex_resolve_operands
+		 * Must be a reference to a Local or Arg
 		 */
 		switch (obj_desc->reference.opcode) {
 		case AML_LOCAL_OP:
 		case AML_ARG_OP:
 
-			status = acpi_ds_method_data_get_node (obj_desc->reference.opcode,
-					  obj_desc->reference.offset, walk_state,
-					  ACPI_CAST_INDIRECT_PTR (acpi_namespace_node, return_desc));
+			/* The referenced object is the pseudo-node for the local/arg */
+
+			referenced_obj = obj_desc->reference.object;
 			break;
 
 		default:
 
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(Internal) Unknown Ref subtype %02x\n",
+			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Reference subtype %X\n",
 				obj_desc->reference.opcode));
-			*return_desc = NULL;
-			status = AE_AML_INTERNAL;
-			goto cleanup;
+			return_ACPI_STATUS (AE_AML_INTERNAL);
 		}
 		break;
 
 
 	case ACPI_DESC_TYPE_NAMED:
 
-		/* Must be a named object;  Just return the Node */
-
-		*return_desc = obj_desc;
+		/*
+		 * A named reference that has already been resolved to a Node
+		 */
+		referenced_obj = obj_desc;
 		break;
 
 
 	default:
 
-		*return_desc = NULL;
-		status = AE_TYPE;
-		break;
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid descriptor type %X in %p\n",
+			ACPI_GET_DESCRIPTOR_TYPE (obj_desc), obj_desc));
+		return_ACPI_STATUS (AE_TYPE);
+	}
+
+
+	/* Create a new reference object */
+
+	reference_obj = acpi_ut_create_internal_object (INTERNAL_TYPE_REFERENCE);
+	if (!reference_obj) {
+		return_ACPI_STATUS (AE_NO_MEMORY);
 	}
 
+	reference_obj->reference.opcode = AML_REF_OF_OP;
+	reference_obj->reference.object = referenced_obj;
+	*return_desc = reference_obj;
 
-cleanup:
+	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Object %p Type [%s], returning Reference %p\n",
+		obj_desc, acpi_ut_get_object_type_name (obj_desc), *return_desc));
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p Ref=%p\n", obj_desc, *return_desc));
-	return_ACPI_STATUS (status);
+	return_ACPI_STATUS (AE_OK);
 }
 
 
diff -Nru a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
--- a/drivers/acpi/executer/exoparg1.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/executer/exoparg1.c	Tue Jul 16 16:49:43 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exoparg1 - AML execution - opcodes with 1 argument
- *              $Revision: 139 $
+ *              $Revision: 140 $
  *
  *****************************************************************************/
 
@@ -355,7 +355,7 @@
 				goto cleanup;
 			}
 
-			/* Get the object reference and store it */
+			/* Get the object reference, store it, and remove our reference */
 
 			status = acpi_ex_get_object_reference (operand[0], &return_desc2, walk_state);
 			if (ACPI_FAILURE (status)) {
@@ -363,6 +363,7 @@
 			}
 
 			status = acpi_ex_store (return_desc2, operand[1], walk_state);
+			acpi_ut_remove_reference (return_desc2);
 
 			/* The object exists in the namespace, return TRUE */
 
@@ -729,6 +730,15 @@
 					 * Delete our reference to the input object and
 					 * point to the object just retrieved
 					 */
+					acpi_ut_remove_reference (operand[0]);
+					operand[0] = temp_desc;
+					break;
+
+				case AML_REF_OF_OP:
+
+					/* Get the object to which the reference refers */
+
+					temp_desc = operand[0]->reference.object;
 					acpi_ut_remove_reference (operand[0]);
 					operand[0] = temp_desc;
 					break;
diff -Nru a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
--- a/drivers/acpi/executer/exoparg2.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/executer/exoparg2.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exoparg2 - AML execution - opcodes with 2 arguments
- *              $Revision: 108 $
+ *              $Revision: 109 $
  *
  *****************************************************************************/
 
@@ -359,7 +359,8 @@
 			/* Object to be indexed is a Package */
 
 			if (index >= operand[0]->package.count) {
-				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index value beyond package end\n"));
+				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index value (%X) beyond package end (%X)\n",
+					index, operand[0]->package.count));
 				status = AE_AML_PACKAGE_LIMIT;
 				goto cleanup;
 			}
@@ -401,7 +402,8 @@
 			/* Object to be indexed is a Buffer */
 
 			if (index >= operand[0]->buffer.length) {
-				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index value beyond end of buffer\n"));
+				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index value (%X) beyond end of buffer (%X)\n",
+					index, operand[0]->buffer.length));
 				status = AE_AML_BUFFER_LIMIT;
 				goto cleanup;
 			}
@@ -522,7 +524,8 @@
 
 	default:
 
-		ACPI_REPORT_ERROR (("Acpi_ex_opcode_2A_0T_1R: Unknown opcode %X\n", walk_state->opcode));
+		ACPI_REPORT_ERROR (("Acpi_ex_opcode_2A_0T_1R: Unknown opcode %X\n",
+			walk_state->opcode));
 		status = AE_AML_BAD_OPCODE;
 		goto cleanup;
 	}
diff -Nru a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
--- a/drivers/acpi/executer/exresnte.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/executer/exresnte.c	Tue Jul 16 16:49:41 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exresnte - AML Interpreter object resolution
- *              $Revision: 56 $
+ *              $Revision: 57 $
  *
  *****************************************************************************/
 
@@ -219,7 +219,7 @@
 
 		/* No named references are allowed here */
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported reference opcode %X\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported Reference opcode %X\n",
 			source_desc->reference.opcode));
 
 		return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
diff -Nru a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
--- a/drivers/acpi/executer/exresolv.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/executer/exresolv.c	Tue Jul 16 16:49:42 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exresolv - AML Interpreter object resolution
- *              $Revision: 114 $
+ *              $Revision: 115 $
  *
  *****************************************************************************/
 
@@ -227,9 +227,11 @@
 			break;
 
 
+		case AML_REF_OF_OP:
 		case AML_DEBUG_OP:
 
 			/* Just leave the object as-is */
+
 			break;
 
 
diff -Nru a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
--- a/drivers/acpi/executer/exresop.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/executer/exresop.c	Tue Jul 16 16:49:43 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exresop - AML Interpreter operand/object resolution
- *              $Revision: 53 $
+ *              $Revision: 54 $
  *
  *****************************************************************************/
 
@@ -204,6 +204,7 @@
 				case AML_DEBUG_OP:
 				case AML_NAME_OP:
 				case AML_INDEX_OP:
+				case AML_REF_OF_OP:
 				case AML_ARG_OP:
 				case AML_LOCAL_OP:
 
diff -Nru a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
--- a/drivers/acpi/executer/exstore.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/executer/exstore.c	Tue Jul 16 16:49:42 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exstore - AML Interpreter object store support
- *              $Revision: 167 $
+ *              $Revision: 168 $
  *
  *****************************************************************************/
 
@@ -130,6 +130,7 @@
 	 */
 	switch (ref_desc->reference.opcode) {
 	case AML_NAME_OP:
+	case AML_REF_OF_OP:
 
 		/* Storing an object into a Name "container" */
 
diff -Nru a/drivers/acpi/include/acconfig.h b/drivers/acpi/include/acconfig.h
--- a/drivers/acpi/include/acconfig.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/include/acconfig.h	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acconfig.h - Global configuration constants
- *       $Revision: 104 $
+ *       $Revision: 105 $
  *
  *****************************************************************************/
 
@@ -54,7 +54,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION                 0x20020611
+#define ACPI_CA_VERSION                 0x20020702
 
 /* Version of ACPI supported */
 
diff -Nru a/drivers/acpi/include/acdebug.h b/drivers/acpi/include/acdebug.h
--- a/drivers/acpi/include/acdebug.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/include/acdebug.h	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acdebug.h - ACPI/AML debugger
- *       $Revision: 61 $
+ *       $Revision: 62 $
  *
  *****************************************************************************/
 
@@ -211,6 +211,10 @@
 void
 acpi_db_decode_internal_object (
 	acpi_operand_object     *obj_desc);
+
+void
+acpi_db_decode_node (
+	acpi_namespace_node     *node);
 
 u32
 acpi_db_block_type (
diff -Nru a/drivers/acpi/include/acglobal.h b/drivers/acpi/include/acglobal.h
--- a/drivers/acpi/include/acglobal.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/include/acglobal.h	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acglobal.h - Declarations for global variables
- *       $Revision: 125 $
+ *       $Revision: 126 $
  *
  *****************************************************************************/
 
@@ -72,6 +72,7 @@
  *
  */
 ACPI_EXTERN u32                         acpi_gbl_table_flags;
+ACPI_EXTERN u32                         acpi_gbl_rsdt_table_count;
 ACPI_EXTERN RSDP_DESCRIPTOR            *acpi_gbl_RSDP;
 ACPI_EXTERN xsdt_descriptor            *acpi_gbl_XSDT;
 ACPI_EXTERN FADT_DESCRIPTOR            *acpi_gbl_FADT;
diff -Nru a/drivers/acpi/include/aclocal.h b/drivers/acpi/include/aclocal.h
--- a/drivers/acpi/include/aclocal.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/include/aclocal.h	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: aclocal.h - Internal data types used across the ACPI subsystem
- *       $Revision: 167 $
+ *       $Revision: 168 $
  *
  *****************************************************************************/
 
@@ -32,10 +32,6 @@
 typedef void*                           acpi_mutex;
 typedef u32                             ACPI_MUTEX_HANDLE;
 
-
-#define ACPI_MEMORY_MODE                0x01
-#define ACPI_LOGICAL_ADDRESSING         0x00
-#define ACPI_PHYSICAL_ADDRESSING        0x01
 
 /* Total number of aml opcodes defined */
 
diff -Nru a/drivers/acpi/include/acparser.h b/drivers/acpi/include/acparser.h
--- a/drivers/acpi/include/acparser.h	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/include/acparser.h	Tue Jul 16 16:49:43 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: acparser.h - AML Parser subcomponent prototypes and defines
- *       $Revision: 59 $
+ *       $Revision: 60 $
  *
  *****************************************************************************/
 
@@ -265,6 +265,10 @@
 
 
 /* psutils - parser utilities */
+
+acpi_parse_object *
+acpi_ps_create_scope_op (
+	void);
 
 void
 acpi_ps_init_op (
diff -Nru a/drivers/acpi/include/acpixf.h b/drivers/acpi/include/acpixf.h
--- a/drivers/acpi/include/acpixf.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/include/acpixf.h	Tue Jul 16 16:49:41 2002
@@ -44,6 +44,10 @@
 	u32                     flags);
 
 acpi_status
+acpi_initialize_objects (
+	u32                     flags);
+
+acpi_status
 acpi_terminate (
 	void);
 
diff -Nru a/drivers/acpi/include/actables.h b/drivers/acpi/include/actables.h
--- a/drivers/acpi/include/actables.h	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/include/actables.h	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: actables.h - ACPI table management
- *       $Revision: 41 $
+ *       $Revision: 42 $
  *
  *****************************************************************************/
 
@@ -43,8 +43,7 @@
 
 acpi_status
 acpi_tb_convert_to_xsdt (
-	acpi_table_desc         *table_info,
-	u32                     *number_of_tables);
+	acpi_table_desc         *table_info);
 
 acpi_status
 acpi_tb_convert_table_fadt (
@@ -63,13 +62,31 @@
  * tbget - Table "get" routines
  */
 
-void
-acpi_tb_table_override (
+acpi_status
+acpi_tb_get_table (
+	ACPI_POINTER            *address,
 	acpi_table_desc         *table_info);
 
 acpi_status
-acpi_tb_get_table_with_override (
+acpi_tb_get_table_header (
 	ACPI_POINTER            *address,
+	acpi_table_header       *return_header);
+
+acpi_status
+acpi_tb_get_table_body (
+	ACPI_POINTER            *address,
+	acpi_table_header       *header,
+	acpi_table_desc         *table_info);
+
+acpi_status
+acpi_tb_get_this_table (
+	ACPI_POINTER            *address,
+	acpi_table_header       *header,
+	acpi_table_desc         *table_info);
+
+acpi_status
+acpi_tb_table_override (
+	acpi_table_header       *header,
 	acpi_table_desc         *table_info);
 
 acpi_status
@@ -79,11 +96,6 @@
 	acpi_table_header       **table_ptr_loc);
 
 acpi_status
-acpi_tb_get_table (
-	ACPI_POINTER            *address,
-	acpi_table_desc         *table_info);
-
-acpi_status
 acpi_tb_verify_rsdp (
 	ACPI_POINTER            *address);
 
@@ -96,20 +108,19 @@
 	acpi_table_header       *table_ptr);
 
 acpi_status
-acpi_tb_get_table_pointer (
-	ACPI_POINTER            *address,
-	u32                     flags,
-	ACPI_SIZE               *size,
-	acpi_table_header       **table_ptr);
-
-/*
- * tbgetall - Get all firmware ACPI tables
- */
+acpi_tb_get_required_tables (
+	void);
 
 acpi_status
-acpi_tb_get_all_tables (
-	u32                     number_of_tables);
+acpi_tb_get_primary_table (
+	ACPI_POINTER            *address,
+	acpi_table_desc         *table_info);
 
+acpi_status
+acpi_tb_get_secondary_table (
+	ACPI_POINTER            *address,
+	acpi_string             signature,
+	acpi_table_desc         *table_info);
 
 /*
  * tbinstall - Table installation
@@ -122,11 +133,13 @@
 acpi_status
 acpi_tb_match_signature (
 	NATIVE_CHAR             *signature,
-	acpi_table_desc         *table_info);
+	acpi_table_desc         *table_info,
+	u8                      search_type);
 
 acpi_status
 acpi_tb_recognize_table (
-	acpi_table_desc         *table_info);
+	acpi_table_desc         *table_info,
+	u8                     search_type);
 
 acpi_status
 acpi_tb_init_table_descriptor (
@@ -165,7 +178,7 @@
 
 acpi_status
 acpi_tb_get_table_rsdt (
-	u32                     *number_of_tables);
+	void);
 
 u8 *
 acpi_tb_scan_memory_for_rsdp (
@@ -188,12 +201,6 @@
 	NATIVE_CHAR             *oem_id,
 	NATIVE_CHAR             *oem_table_id,
 	acpi_table_header       **table_ptr);
-
-acpi_status
-acpi_tb_map_acpi_table (
-	ACPI_PHYSICAL_ADDRESS   physical_address,
-	ACPI_SIZE               *size,
-	acpi_table_header       **logical_address);
 
 acpi_status
 acpi_tb_verify_table_checksum (
diff -Nru a/drivers/acpi/include/actbl.h b/drivers/acpi/include/actbl.h
--- a/drivers/acpi/include/actbl.h	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/include/actbl.h	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: actbl.h - Table data structures defined in ACPI specification
- *       $Revision: 52 $
+ *       $Revision: 53 $
  *
  *****************************************************************************/
 
@@ -185,9 +185,15 @@
 
 /* Definitions for the Flags bitfield member of ACPI_TABLE_SUPPORT */
 
-#define ACPI_TABLE_SINGLE       0
-#define ACPI_TABLE_MULTIPLE     1
-#define ACPI_TABLE_EXECUTABLE   2
+#define ACPI_TABLE_SINGLE       0x00
+#define ACPI_TABLE_MULTIPLE     0x01
+#define ACPI_TABLE_EXECUTABLE   0x02
+
+#define ACPI_TABLE_ROOT         0x00
+#define ACPI_TABLE_PRIMARY      0x10
+#define ACPI_TABLE_SECONDARY    0x20
+#define ACPI_TABLE_OTHER        0x30
+#define ACPI_TABLE_TYPE_MASK    0x30
 
 /* Data about each known table type */
 
diff -Nru a/drivers/acpi/include/actypes.h b/drivers/acpi/include/actypes.h
--- a/drivers/acpi/include/actypes.h	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/include/actypes.h	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: actypes.h - Common data types for the entire ACPI subsystem
- *       $Revision: 237 $
+ *       $Revision: 238 $
  *
  *****************************************************************************/
 
@@ -209,8 +209,18 @@
 
 /* Pointer_types for above */
 
-#define ACPI_LOGICAL_POINTER            0x01
-#define ACPI_PHYSICAL_POINTER           0x02
+#define ACPI_PHYSICAL_POINTER           0x01
+#define ACPI_LOGICAL_POINTER            0x02
+
+/* Processor mode */
+
+#define ACPI_PHYSICAL_ADDRESSING        0x04
+#define ACPI_LOGICAL_ADDRESSING         0x08
+#define ACPI_MEMORY_MODE                0x0C
+
+#define ACPI_PHYSMODE_PHYSPTR           ACPI_PHYSICAL_ADDRESSING | ACPI_PHYSICAL_POINTER
+#define ACPI_LOGMODE_PHYSPTR            ACPI_LOGICAL_ADDRESSING  | ACPI_PHYSICAL_POINTER
+#define ACPI_LOGMODE_LOGPTR             ACPI_LOGICAL_ADDRESSING  | ACPI_LOGICAL_POINTER
 
 
 /*
diff -Nru a/drivers/acpi/include/amlresrc.h b/drivers/acpi/include/amlresrc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/acpi/include/amlresrc.h	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,512 @@
+
+/******************************************************************************
+ *
+ * Module Name: aslresource.h - ASL resource descriptors
+ *              $Revision: 19 $
+ *
+ *****************************************************************************/
+
+/*
+ *  Copyright (C) 2000 - 2002, R. Byron Moore
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef __ASLRESOURCE_H
+#define __ASLRESOURCE_H
+
+
+#define ASL_RESNAME_ADDRESS                     "_ADR"
+#define ASL_RESNAME_ALIGNMENT                   "_ALN"
+#define ASL_RESNAME_ADDRESSSPACE                "_ASI"
+#define ASL_RESNAME_BASEADDRESS                 "_BAS"
+#define ASL_RESNAME_BUSMASTER                   "_BM_"  /* Master(1), Slave(0) */
+#define ASL_RESNAME_DECODE                      "_DEC"
+#define ASL_RESNAME_DMA                         "_DMA"
+#define ASL_RESNAME_DMATYPE                     "_TYP"  /* Compatible(0), A(1), B(2), F(3) */
+#define ASL_RESNAME_GRANULARITY                 "_GRA"
+#define ASL_RESNAME_INTERRUPT                   "_INT"
+#define ASL_RESNAME_INTERRUPTLEVEL              "_LL_"  /* Active_lo(1), Active_hi(0) */
+#define ASL_RESNAME_INTERRUPTSHARE              "_SHR"  /* Shareable(1), No_share(0) */
+#define ASL_RESNAME_INTERRUPTTYPE               "_HE_"  /* Edge(1), Level(0) */
+#define ASL_RESNAME_LENGTH                      "_LEN"
+#define ASL_RESNAME_MEMATTRIBUTES               "_MTP"  /* Memory(0), Reserved(1), ACPI(2), NVS(3) */
+#define ASL_RESNAME_MEMTYPE                     "_MEM"  /* Non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */
+#define ASL_RESNAME_MAXADDR                     "_MAX"
+#define ASL_RESNAME_MINADDR                     "_MIN"
+#define ASL_RESNAME_MAXTYPE                     "_MAF"
+#define ASL_RESNAME_MINTYPE                     "_MIF"
+#define ASL_RESNAME_REGISTERBITOFFSET           "_RBO"
+#define ASL_RESNAME_REGISTERBITWIDTH            "_RBW"
+#define ASL_RESNAME_RANGETYPE                   "_RNG"
+#define ASL_RESNAME_READWRITETYPE               "_RW_"  /* Read_only(0), Writeable (1) */
+#define ASL_RESNAME_TRANSLATION                 "_TRA"
+#define ASL_RESNAME_TRANSTYPE                   "_TRS"  /* Sparse(1), Dense(0) */
+#define ASL_RESNAME_TYPE                        "_TTP"  /* Translation(1), Static (0) */
+#define ASL_RESNAME_XFERTYPE                    "_SIZ"  /* 8(0), 8_and16(1), 16(2) */
+
+
+/* Default sizes for "small" resource descriptors */
+
+#define ASL_RDESC_IRQ_SIZE                      0x02
+#define ASL_RDESC_DMA_SIZE                      0x02
+#define ASL_RDESC_ST_DEPEND_SIZE                0x00
+#define ASL_RDESC_END_DEPEND_SIZE               0x00
+#define ASL_RDESC_IO_SIZE                       0x07
+#define ASL_RDESC_FIXED_IO_SIZE                 0x03
+#define ASL_RDESC_END_TAG_SIZE                  0x01
+
+
+typedef struct asl_resource_node
+{
+	u32                         buffer_length;
+	void                        *buffer;
+	struct asl_resource_node    *next;
+
+} ASL_RESOURCE_NODE;
+
+
+/*
+ * Resource descriptors defined in the ACPI specification
+ */
+
+
+#pragma pack(1)
+typedef struct asl_irq_format_desc
+{
+	u8                          descriptor_type;
+	u16                         irq_mask;
+	u8                          flags;
+
+} ASL_IRQ_FORMAT_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_irq_noflags_desc
+{
+	u8                          descriptor_type;
+	u16                         irq_mask;
+
+} ASL_IRQ_NOFLAGS_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_dma_format_desc
+{
+	u8                          descriptor_type;
+	u8                          dma_channel_mask;
+	u8                          flags;
+
+} ASL_DMA_FORMAT_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_start_dependent_desc
+{
+	u8                          descriptor_type;
+	u8                          flags;
+
+} ASL_START_DEPENDENT_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_start_dependent_noprio_desc
+{
+	u8                          descriptor_type;
+
+} ASL_START_DEPENDENT_NOPRIO_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_end_dependent_desc
+{
+	u8                          descriptor_type;
+
+} ASL_END_DEPENDENT_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_io_port_desc
+{
+	u8                          descriptor_type;
+	u8                          information;
+	u16                         address_min;
+	u16                         address_max;
+	u8                          alignment;
+	u8                          length;
+
+} ASL_IO_PORT_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_fixed_io_port_desc
+{
+	u8                          descriptor_type;
+	u16                         base_address;
+	u8                          length;
+
+} ASL_FIXED_IO_PORT_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_small_vendor_desc
+{
+	u8                          descriptor_type;
+	u8                          vendor_defined[7];
+
+} ASL_SMALL_VENDOR_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_end_tag_desc
+{
+	u8                          descriptor_type;
+	u8                          checksum;
+
+} ASL_END_TAG_DESC;
+
+
+/* LARGE descriptors */
+
+#pragma pack(1)
+typedef struct asl_memory_24_desc
+{
+	u8                          descriptor_type;
+	u16                         length;
+	u8                          information;
+	u16                         address_min;
+	u16                         address_max;
+	u16                         alignment;
+	u16                         range_length;
+
+} ASL_MEMORY_24_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_large_vendor_desc
+{
+	u8                          descriptor_type;
+	u16                         length;
+	u8                          vendor_defined[1];
+
+} ASL_LARGE_VENDOR_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_memory_32_desc
+{
+	u8                          descriptor_type;
+	u16                         length;
+	u8                          information;
+	u32                         address_min;
+	u32                         address_max;
+	u32                         alignment;
+	u32                         range_length;
+
+} ASL_MEMORY_32_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_fixed_memory_32_desc
+{
+	u8                          descriptor_type;
+	u16                         length;
+	u8                          information;
+	u32                         base_address;
+	u32                         range_length;
+
+} ASL_FIXED_MEMORY_32_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_qword_address_desc
+{
+	u8                          descriptor_type;
+	u16                         length;
+	u8                          resource_type;
+	u8                          flags;
+	u8                          specific_flags;
+	u64                         granularity;
+	u64                         address_min;
+	u64                         address_max;
+	u64                         translation_offset;
+	u64                         address_length;
+	u8                          optional_fields[2];
+
+} ASL_QWORD_ADDRESS_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_dword_address_desc
+{
+	u8                          descriptor_type;
+	u16                         length;
+	u8                          resource_type;
+	u8                          flags;
+	u8                          specific_flags;
+	u32                         granularity;
+	u32                         address_min;
+	u32                         address_max;
+	u32                         translation_offset;
+	u32                         address_length;
+	u8                          optional_fields[2];
+
+} ASL_DWORD_ADDRESS_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_word_address_desc
+{
+	u8                          descriptor_type;
+	u16                         length;
+	u8                          resource_type;
+	u8                          flags;
+	u8                          specific_flags;
+	u16                         granularity;
+	u16                         address_min;
+	u16                         address_max;
+	u16                         translation_offset;
+	u16                         address_length;
+	u8                          optional_fields[2];
+
+} ASL_WORD_ADDRESS_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_extended_xrupt_desc
+{
+	u8                          descriptor_type;
+	u16                         length;
+	u8                          flags;
+	u8                          table_length;
+	u32                         interrupt_number[1];
+	/* Res_source_index, Res_source optional fields follow */
+
+} ASL_EXTENDED_XRUPT_DESC;
+
+
+#pragma pack(1)
+typedef struct asl_general_register_desc
+{
+	u8                          descriptor_type;
+	u16                         length;
+	u8                          address_space_id;
+	u8                          bit_width;
+	u8                          bit_offset;
+	u8                          reserved;
+	u64                         address;
+
+} ASL_GENERAL_REGISTER_DESC;
+
+
+/* Union of all resource descriptors, sow we can allocate the worst case */
+
+typedef union asl_resource_desc
+{
+	ASL_IRQ_FORMAT_DESC         irq;
+	ASL_DMA_FORMAT_DESC         dma;
+	ASL_START_DEPENDENT_DESC    std;
+	ASL_END_DEPENDENT_DESC      end;
+	ASL_IO_PORT_DESC            iop;
+	ASL_FIXED_IO_PORT_DESC      fio;
+	ASL_SMALL_VENDOR_DESC       smv;
+	ASL_END_TAG_DESC            et;
+
+	ASL_MEMORY_24_DESC          M24;
+	ASL_LARGE_VENDOR_DESC       lgv;
+	ASL_MEMORY_32_DESC          M32;
+	ASL_FIXED_MEMORY_32_DESC    F32;
+	ASL_QWORD_ADDRESS_DESC      qas;
+	ASL_DWORD_ADDRESS_DESC      das;
+	ASL_WORD_ADDRESS_DESC       was;
+	ASL_EXTENDED_XRUPT_DESC     exx;
+	ASL_GENERAL_REGISTER_DESC   grg;
+	u32                         U32_item;
+	u16                         U16_item;
+	u8                          U8item;
+
+} ASL_RESOURCE_DESC;
+
+
+#define NEXT_RESOURCE_DESC(a,b)     (ASL_RESOURCE_DESC *) (((char *) (a)) + sizeof(b))
+
+#define DEFAULT_RESOURCE_DESC_SIZE  (sizeof (ASL_RESOURCE_DESC) + sizeof (ASL_END_TAG_DESC))
+
+
+/*
+ * Resource utilities
+ */
+
+ASL_RESOURCE_NODE *
+rs_allocate_resource_node (
+	u32                     size);
+
+	void
+rs_create_bit_field (
+	acpi_parse_object       *op,
+	char                    *name,
+	u32                     byte_offset,
+	u32                     bit_offset);
+
+void
+rs_create_byte_field (
+	acpi_parse_object       *op,
+	char                    *name,
+	u32                     byte_offset);
+
+void
+rs_set_flag_bits (
+	u8                      *flags,
+	acpi_parse_object       *op,
+	u8                      position,
+	u8                      default);
+
+acpi_parse_object *
+rs_complete_node_and_get_next (
+	acpi_parse_object       *op);
+
+ASL_RESOURCE_NODE *
+rs_do_one_resource_descriptor (
+	acpi_parse_object       *descriptor_type_op,
+	u32                     current_byte_offset);
+
+u32
+rs_link_descriptor_chain (
+	ASL_RESOURCE_NODE       **previous_rnode,
+	ASL_RESOURCE_NODE       *rnode);
+
+
+/*
+ * Small descriptors
+ */
+
+ASL_RESOURCE_NODE *
+rs_do_dma_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_end_dependent_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_fixed_io_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_interrupt_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_io_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_irq_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_irq_no_flags_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_memory24_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_memory32_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_memory32_fixed_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_start_dependent_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_start_dependent_no_pri_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_vendor_small_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+
+/*
+ * Large descriptors
+ */
+
+u32
+rs_get_string_data_length (
+	acpi_parse_object       *initializer_op);
+
+ASL_RESOURCE_NODE *
+rs_do_dword_io_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_dword_memory_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_qword_io_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_qword_memory_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_word_io_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_word_bus_number_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_vendor_large_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+ASL_RESOURCE_NODE *
+rs_do_general_register_descriptor (
+	acpi_parse_object       *op,
+	u32                     current_byte_offset);
+
+
+#endif
+
diff -Nru a/drivers/acpi/include/platform/aclinux.h b/drivers/acpi/include/platform/aclinux.h
--- a/drivers/acpi/include/platform/aclinux.h	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/include/platform/aclinux.h	Tue Jul 16 16:49:43 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: aclinux.h - OS specific defines, etc.
- *       $Revision: 25 $
+ *       $Revision: 26 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
--- a/drivers/acpi/namespace/nseval.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/namespace/nseval.c	Tue Jul 16 16:49:42 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: nseval - Object evaluation interfaces -- includes control
  *                       method lookup and execution.
- *              $Revision: 116 $
+ *              $Revision: 117 $
  *
  ******************************************************************************/
 
@@ -485,7 +485,8 @@
 		if (ACPI_SUCCESS (status)) {
 			status = AE_CTRL_RETURN_VALUE;
 			*return_obj_desc = ACPI_CAST_PTR (acpi_operand_object, resolved_node);
-			ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning obj %p\n", resolved_node));
+			ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning object %p [%s]\n",
+				*return_obj_desc, acpi_ut_get_object_type_name (*return_obj_desc)));
 		}
 	}
 
diff -Nru a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
--- a/drivers/acpi/namespace/nsload.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/namespace/nsload.c	Tue Jul 16 16:49:43 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: nsload - namespace loading/expanding/contracting procedures
- *              $Revision: 55 $
+ *              $Revision: 56 $
  *
  *****************************************************************************/
 
@@ -115,12 +115,11 @@
 
 	/* Create and init a Root Node */
 
-	parse_root = acpi_ps_alloc_op (AML_SCOPE_OP);
+	parse_root = acpi_ps_create_scope_op ();
 	if (!parse_root) {
 		return_ACPI_STATUS (AE_NO_MEMORY);
 	}
 
-	parse_root->named.name = ACPI_ROOT_NAME;
 
 	/* Create and initialize a new walk state */
 
diff -Nru a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
--- a/drivers/acpi/namespace/nsnames.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/namespace/nsnames.c	Tue Jul 16 16:49:43 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: nsnames - Name manipulation and search
- *              $Revision: 77 $
+ *              $Revision: 78 $
  *
  ******************************************************************************/
 
@@ -179,7 +179,7 @@
 	size = 0;
 	next_node = node;
 
-	while (next_node != acpi_gbl_root_node) {
+	while (next_node && (next_node != acpi_gbl_root_node)) {
 		size += PATH_SEGMENT_LENGTH;
 		next_node = acpi_ns_get_parent_node (next_node);
 	}
diff -Nru a/drivers/acpi/osl.c b/drivers/acpi/osl.c
--- a/drivers/acpi/osl.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/osl.c	Tue Jul 16 16:49:43 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_osl.c - OS-dependent functions ($Revision: 78 $)
+ *  acpi_osl.c - OS-dependent functions ($Revision: 83 $)
  *
  *  Copyright (C) 2000       Andrew Henroid
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
@@ -42,7 +42,7 @@
 u64 efi_mem_attributes (u64 phys_addr);
 #endif
 
-#ifdef _IA64
+#ifdef CONFIG_IA64
 #include <asm/hw_irq.h>
 #include <asm/delay.h>
 #endif
@@ -176,7 +176,7 @@
 acpi_os_map_memory(ACPI_PHYSICAL_ADDRESS phys, ACPI_SIZE size, void **virt)
 {
 #ifdef CONFIG_ACPI_EFI
-	if (EFI_MEMORY_UC & efi_mem_attributes(phys)) {
+	if (!(EFI_MEMORY_WB & efi_mem_attributes(phys))) {
 		*virt = ioremap(phys, size);
 	} else {
 		*virt = phys_to_virt(phys);
@@ -234,9 +234,9 @@
 acpi_status
 acpi_os_install_interrupt_handler(u32 irq, OSD_HANDLER handler, void *context)
 {
-#ifdef _IA64
-	irq = isa_irq_to_vector(irq);
-#endif /*_IA64*/
+#ifdef CONFIG_IA64
+	irq = gsi_to_vector(irq);
+#endif
 	acpi_irq_irq = irq;
 	acpi_irq_handler = handler;
 	acpi_irq_context = context;
@@ -252,9 +252,9 @@
 acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler)
 {
 	if (acpi_irq_handler) {
-#ifdef _IA64
-		irq = isa_irq_to_vector(irq);
-#endif /*_IA64*/
+#ifdef CONFIG_IA64
+		irq = gsi_to_vector(irq);
+#endif
 		free_irq(irq, acpi_irq);
 		acpi_irq_handler = NULL;
 	}
@@ -349,12 +349,13 @@
 #ifdef CONFIG_ACPI_EFI
 	int			iomem = 0;
 
-	if (EFI_MEMORY_UC & efi_mem_attributes(phys_addr)) {
+	if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
+		virt_addr = phys_to_virt(phys_addr);
+	}
+	else {
 		iomem = 1;
 		virt_addr = ioremap(phys_addr, width);
-	} 
-	else
-		virt_addr = phys_to_virt(phys_addr);
+	}
 #else
 	virt_addr = phys_to_virt(phys_addr);
 #endif
@@ -394,12 +395,13 @@
 #ifdef CONFIG_ACPI_EFI
 	int			iomem = 0;
 
-	if (EFI_MEMORY_UC & efi_mem_attributes(phys_addr)) {
-		iomem = 1;
-		virt_addr = ioremap(phys_addr,width);
-	} 
-	else
+	if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
 		virt_addr = phys_to_virt(phys_addr);
+	}
+	else {
+		iomem = 1;
+		virt_addr = ioremap(phys_addr, width);
+	}
 #else
 	virt_addr = phys_to_virt(phys_addr);
 #endif
@@ -627,31 +629,35 @@
 
 	case OSD_PRIORITY_GPE:
 	{
-		static struct tq_struct task;
-
 		/*
 		 * Allocate/initialize DPC structure.  Note that this memory will be
-		 * freed by the callee.
+		 * freed by the callee.  The kernel handles the tq_struct list  in a
+		 * way that allows us to also free its memory inside the callee.
+		 * Because we may want to schedule several tasks with different
+		 * parameters we can't use the approach some kernel code uses of
+		 * having a static tq_struct.
+		 * We can save time and code by allocating the DPC and tq_structs
+		 * from the same memory.
 		 */
-		dpc = kmalloc(sizeof(ACPI_OS_DPC), GFP_ATOMIC);
+		struct tq_struct *task;
+
+		dpc = kmalloc(sizeof(ACPI_OS_DPC)+sizeof(struct tq_struct), GFP_ATOMIC);
 		if (!dpc)
 			return_ACPI_STATUS (AE_NO_MEMORY);
 
 		dpc->function = function;
 		dpc->context = context;
 
-		memset(&task, 0, sizeof(struct tq_struct));
+		task = (void *)(dpc+1);
+		INIT_TQUEUE(task, acpi_os_schedule_exec, (void*)dpc);
 
-		task.routine = acpi_os_schedule_exec;
-		task.data = (void*)dpc;
-
-		if (schedule_task(&task) < 0) {
+		if (schedule_task(task) < 0) {
 			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Call to schedule_task() failed.\n"));
+			kfree(dpc);
 			status = AE_ERROR;
 		}
 	}
 	break;
-
 	default:
 		/*
 		 * Allocate/initialize DPC structure.  Note that this memory will be
diff -Nru a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
--- a/drivers/acpi/parser/psparse.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/parser/psparse.c	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: psparse - Parser top level AML parse routines
- *              $Revision: 127 $
+ *              $Revision: 128 $
  *
  *****************************************************************************/
 
@@ -581,6 +581,10 @@
 				pre_op.common.value.arg = NULL;
 				pre_op.common.aml_opcode = walk_state->opcode;
 
+				/*
+				 * Get and append arguments until we find the node that contains
+				 * the name (the type ARGP_NAME).
+				 */
 				while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) != ARGP_NAME) {
 					arg = acpi_ps_get_next_arg (parser_state,
 							 GET_CURRENT_ARG_TYPE (walk_state->arg_types),
diff -Nru a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
--- a/drivers/acpi/parser/psutils.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/parser/psutils.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: psutils - Parser miscellaneous utilities (Parser only)
- *              $Revision: 51 $
+ *              $Revision: 52 $
  *
  *****************************************************************************/
 
@@ -27,9 +27,40 @@
 #include "acpi.h"
 #include "acparser.h"
 #include "amlcode.h"
+#include "acnamesp.h"
 
 #define _COMPONENT          ACPI_PARSER
 	 ACPI_MODULE_NAME    ("psutils")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ps_create_scope_op
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Scope_op
+ *
+ * DESCRIPTION: Create a Scope and associated namepath op with the root name
+ *
+ ******************************************************************************/
+
+acpi_parse_object *
+acpi_ps_create_scope_op (
+	void)
+{
+	acpi_parse_object       *scope_op;
+
+
+	scope_op = acpi_ps_alloc_op (AML_SCOPE_OP);
+	if (!scope_op) {
+		return (NULL);
+	}
+
+
+	scope_op->named.name = ACPI_ROOT_NAME;
+	return (scope_op);
+}
 
 
 /*******************************************************************************
diff -Nru a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
--- a/drivers/acpi/parser/psxface.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/parser/psxface.c	Tue Jul 16 16:49:43 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: psxface - Parser external interfaces
- *              $Revision: 64 $
+ *              $Revision: 65 $
  *
  *****************************************************************************/
 
@@ -108,7 +108,7 @@
 
 	/* Create and init a Root Node */
 
-	op = acpi_ps_alloc_op (AML_SCOPE_OP);
+	op = acpi_ps_create_scope_op ();
 	if (!op) {
 		return_ACPI_STATUS (AE_NO_MEMORY);
 	}
@@ -149,7 +149,7 @@
 
 	/* Create and init a Root Node */
 
-	op = acpi_ps_alloc_op (AML_SCOPE_OP);
+	op = acpi_ps_create_scope_op ();
 	if (!op) {
 		return_ACPI_STATUS (AE_NO_MEMORY);
 	}
diff -Nru a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
--- a/drivers/acpi/pci_irq.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/pci_irq.c	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- *  pci_irq.c - ACPI PCI Interrupt Routing ($Revision: 7 $)
+ *  pci_irq.c - ACPI PCI Interrupt Routing ($Revision: 10 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -250,8 +250,13 @@
 		return_VALUE(0);
 	}
 
-	if (!entry->irq && entry->link.handle)
+	if (!entry->irq && entry->link.handle) {
 		entry->irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index);
+		if (!entry->irq) {
+			ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n"));
+			return_VALUE(0);
+		}
+	}
 	else if (!entry->irq) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid static routing entry (IRQ 0)\n"));
 		return_VALUE(0);
@@ -323,7 +328,7 @@
 
 	/* 
 	 * First we check the PCI IRQ routing table (PRT) for an IRQ.  PRT
-	 * values override any BIOS-assinged IRQs set during boot.
+	 * values override any BIOS-assigned IRQs set during boot.
 	 */
  	irq = acpi_pci_irq_lookup(0, dev->bus->number, PCI_SLOT(dev->devfn), pin);
  
@@ -334,13 +339,18 @@
 	if (!irq)
  		irq = acpi_pci_irq_derive(dev, pin);
  
-	if (irq)
-		dev->irq = irq;
-		
-	if (!dev->irq) {
-		printk(KERN_WARNING PREFIX "No IRQ known for interrupt pin %c of device %s\n", ('A' + pin), dev->slot_name);
-		return_VALUE(0);
-	}
+	/*
+	 * No IRQ known to the ACPI subsystem - maybe the BIOS / 
+	 * driver reported one, then use it. Exit in any case.
+	 */
+	if (!irq) {
+		printk(KERN_WARNING PREFIX "No IRQ known for interrupt pin %c of device %s", ('A' + pin), dev->slot_name);
+		if (dev->irq) 
+			printk(" - using IRQ %d\n", dev->irq);
+		return_VALUE(dev->irq);
+ 	}
+
+	dev->irq = irq;
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s using IRQ %d\n", dev->slot_name, dev->irq));
 
diff -Nru a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
--- a/drivers/acpi/pci_link.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/pci_link.c	Tue Jul 16 16:49:41 2002
@@ -1,5 +1,5 @@
 /*
- *  pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 31 $)
+ *  pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 33 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -110,6 +110,10 @@
 
 	resource = (acpi_resource *) buffer.pointer;
 
+	/* skip past dependent function resource (if present) */
+	if (resource->id == ACPI_RSTYPE_START_DPF)
+		resource = ACPI_NEXT_RESOURCE(resource);
+
 	switch (resource->id) {
 	case ACPI_RSTYPE_IRQ:
 	{
@@ -160,7 +164,7 @@
 		"Found %d possible IRQs\n", link->irq.possible_count));
 
 end:
-	kfree(buffer.pointer);
+	acpi_os_free(buffer.pointer);
 
 	return_VALUE(result);
 }
@@ -255,7 +259,7 @@
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active));
 
 end:
-	kfree(buffer.pointer);
+	acpi_os_free(buffer.pointer);
 
 	return_VALUE(result);
 }
@@ -393,7 +397,7 @@
 
 		if (link->irq.active)
 			acpi_irq_penalty[link->irq.active] += 100;
-		else {
+		else if (link->irq.possible_count) {
 			int penalty = 100 / link->irq.possible_count;
 			for (i=0; i<link->irq.possible_count; i++) {
 				if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ)
@@ -410,7 +414,7 @@
 		int		i = 0;
 
 		link = list_entry(node, struct acpi_pci_link, node);
-		if (!link) {
+		if (!link || !link->irq.possible_count) {
 			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
 			continue;
 		}
@@ -435,8 +439,8 @@
 		acpi_irq_penalty[link->irq.active] += 100;
 
 		printk(PREFIX "%s [%s] enabled at IRQ %d\n", 
-			acpi_device_name(link->device), 
-			acpi_device_bid(link->device), irq);
+			acpi_device_name(link->device),
+			acpi_device_bid(link->device), link->irq.active);
 	}
 
 	return_VALUE(0);
diff -Nru a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
--- a/drivers/acpi/pci_root.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/pci_root.c	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- *  pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 38 $)
+ *  pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 39 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -154,7 +154,7 @@
 	root->mem_tra = acpi_pci_root_bus_tra ((acpi_resource *)
 			buffer.pointer, ACPI_MEMORY_RANGE);
 
-	kfree(buffer.pointer);
+	acpi_os_free(buffer.pointer);
 	return_VALUE(0);
 }
 
diff -Nru a/drivers/acpi/power.c b/drivers/acpi/power.c
--- a/drivers/acpi/power.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/power.c	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_power.c - ACPI Bus Power Management ($Revision: 37 $)
+ *  acpi_power.c - ACPI Bus Power Management ($Revision: 38 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -186,7 +186,7 @@
 		return_VALUE(0);
 	}
 
-	status = acpi_evaluate(resource->handle, "_ON", NULL, NULL);
+	status = acpi_evaluate_object(resource->handle, "_ON", NULL, NULL);
 	if (ACPI_FAILURE(status))
 		return_VALUE(-ENODEV);
 
@@ -240,7 +240,7 @@
 		return_VALUE(0);
 	}
 
-	status = acpi_evaluate(resource->handle, "_OFF", NULL, NULL);
+	status = acpi_evaluate_object(resource->handle, "_OFF", NULL, NULL);
 	if (ACPI_FAILURE(status))
 		return_VALUE(-ENODEV);
 
diff -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c
--- a/drivers/acpi/processor.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/processor.c	Tue Jul 16 16:49:43 2002
@@ -1,5 +1,5 @@
 /*
- * acpi_processor.c - ACPI Processor Driver ($Revision: 66 $)
+ * acpi_processor.c - ACPI Processor Driver ($Revision: 69 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -616,8 +616,15 @@
 	 * Set the default C1 promotion and C2 demotion policies, where we
 	 * promote from C1 to C2 after several (10) successive C1 transitions,
 	 * as we cannot (currently) measure the time spent in C1. Demote from
-	 * C2 to C1 after experiencing several (4) 'shorts' (time spent in C2
-	 * is less than the C2 transtion latency).
+	 * C2 to C1 anytime we experience a 'short' (time spent in C2 is less
+	 * than the C2 transtion latency).  Note the simplifying assumption 
+	 * that the 'cost' of a transition is amortized when we sleep for at
+	 * least as long as the transition's latency (thus the total transition
+	 * time is two times the latency).
+	 *
+	 * TBD: Measure C1 sleep times by instrumenting the core IRQ handler.
+	 * TBD: Demote to default C-State after long periods of activity.
+	 * TBD: Investigate policy's use of CPU utilization -vs- sleep duration.
 	 */
 	if (pr->power.states[ACPI_STATE_C2].valid) {
 		pr->power.states[ACPI_STATE_C1].promotion.threshold.count = 10;
@@ -625,7 +632,7 @@
 			pr->power.states[ACPI_STATE_C2].latency_ticks;
 		pr->power.states[ACPI_STATE_C1].promotion.state = ACPI_STATE_C2;
 
-		pr->power.states[ACPI_STATE_C2].demotion.threshold.count = 4;
+		pr->power.states[ACPI_STATE_C2].demotion.threshold.count = 1;
 		pr->power.states[ACPI_STATE_C2].demotion.threshold.ticks =
 			pr->power.states[ACPI_STATE_C2].latency_ticks;
 		pr->power.states[ACPI_STATE_C2].demotion.state = ACPI_STATE_C1;
@@ -929,7 +936,7 @@
 		pr->performance.status_register));
 
 end:
-	kfree(buffer.pointer);
+	acpi_os_free(buffer.pointer);
 
 	return_VALUE(result);
 }
@@ -1006,7 +1013,7 @@
 	}
 
 end:
-	kfree(buffer.pointer);
+	acpi_os_free(buffer.pointer);
 
 	return_VALUE(result);
 }
@@ -2059,11 +2066,8 @@
 	if (!pr)
 		return_VALUE(-EINVAL);
 
-#ifdef CONFIG_SMP
-	/* FIXME: What should this be? -- RR */
 	if (num_online_cpus() > 1)
-		errata.smp = num_online_cpus();
-#endif
+		errata.smp = TRUE;
 
 	acpi_processor_errata(pr);
 
diff -Nru a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
--- a/drivers/acpi/resources/rscreate.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/resources/rscreate.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: rscreate - Create resource lists/tables
- *              $Revision: 57 $
+ *              $Revision: 58 $
  *
  ******************************************************************************/
 
@@ -39,7 +39,6 @@
  *
  * PARAMETERS:  Byte_stream_buffer      - Pointer to the resource byte stream
  *              Output_buffer           - Pointer to the user's buffer
- *              Output_buffer_length    - Pointer to the size of Output_buffer
  *
  * RETURN:      Status  - AE_OK if okay, else a valid acpi_status code
  *              If Output_buffer is not large enough, Output_buffer_length
@@ -116,7 +115,6 @@
  * PARAMETERS:  Package_object          - Pointer to an acpi_operand_object
  *                                        package
  *              Output_buffer           - Pointer to the user's buffer
- *              Output_buffer_length    - Size of Output_buffer
  *
  * RETURN:      Status  AE_OK if okay, else a valid acpi_status code.
  *              If the Output_buffer is too small, the error will be
@@ -244,7 +242,7 @@
 		case INTERNAL_TYPE_REFERENCE:
 
 			if ((*sub_object_list)->reference.opcode != AML_INT_NAMEPATH_OP) {
-			   ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Need name, found reference op %X\n",
+				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Need name, found reference op %X\n",
 					(*sub_object_list)->reference.opcode));
 				return_ACPI_STATUS (AE_BAD_DATA);
 			}
diff -Nru a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c
--- a/drivers/acpi/resources/rsio.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/resources/rsio.c	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: rsio - IO and DMA resource descriptors
- *              $Revision: 20 $
+ *              $Revision: 21 $
  *
  ******************************************************************************/
 
@@ -410,6 +410,7 @@
 	if (i == 0) {
 		/* Zero channels is invalid! */
 
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Found Zero DMA channels in resource list\n"));
 		return_ACPI_STATUS (AE_BAD_DATA);
 	}
 	output_struct->data.dma.number_of_channels = i;
@@ -432,6 +433,7 @@
 	output_struct->data.dma.transfer = temp8 & 0x03;
 
 	if (0x03 == output_struct->data.dma.transfer) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid DMA.Transfer preference (3)\n"));
 		return_ACPI_STATUS (AE_BAD_DATA);
 	}
 
diff -Nru a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c
--- a/drivers/acpi/resources/rsirq.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/resources/rsirq.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: rsirq - IRQ resource descriptors
- *              $Revision: 28 $
+ *              $Revision: 29 $
  *
  ******************************************************************************/
 
@@ -99,6 +99,7 @@
 	if (i == 0) {
 		/* Zero interrupts is invalid! */
 
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Found Zero interrupt levels in resource list\n"));
 		return_ACPI_STATUS (AE_BAD_DATA);
 	}
 	output_struct->data.irq.number_of_interrupts = i;
@@ -133,6 +134,7 @@
 				 * are allowed (ACPI spec v1.0b ection 6.4.2.1),
 				 * so an error will occur if we reach this point
 				 */
+				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid interrupt polarity/trigger in resource list\n"));
 				return_ACPI_STATUS (AE_BAD_DATA);
 			}
 		}
diff -Nru a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
--- a/drivers/acpi/resources/rslist.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/resources/rslist.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: rslist - Linked list utilities
- *              $Revision: 30 $
+ *              $Revision: 31 $
  *
  ******************************************************************************/
 
@@ -471,6 +471,8 @@
 			 * If we get here, everything is out of sync,
 			 *  so exit with an error
 			 */
+			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid descriptor type (%X) in resource list\n",
+				linked_list->id));
 			status = AE_BAD_DATA;
 			break;
 
diff -Nru a/drivers/acpi/system.c b/drivers/acpi/system.c
--- a/drivers/acpi/system.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/system.c	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_system.c - ACPI System Driver ($Revision: 57 $)
+ *  acpi_system.c - ACPI System Driver ($Revision: 60 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -24,7 +24,6 @@
  */
 
 #define ACPI_C
-#define HAVE_NEW_DEVICE_MODEL
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -126,7 +125,7 @@
 
 	/* wait for power to come back */
 	mdelay(10);
-#ifdef HAVE_NEW_DEVICE_MODEL
+
 	/* turn all the devices back on */
 	device_resume(RESUME_POWER_ON);
 
@@ -135,11 +134,8 @@
 
 	/* restore device context */
 	device_resume(RESUME_RESTORE_STATE);
-#else
-#error Resume cant work without driver model
-#endif
 
-	if ((state == ACPI_STATE_S1) && (dmi_broken & BROKEN_INIT_AFTER_S1)) {
+	if (dmi_broken & BROKEN_INIT_AFTER_S1) {
 		printk("Broken toshiba laptop -> kicking interrupts\n");
 		init_8259A(0);
 	}
@@ -166,7 +162,6 @@
 {
 	int			error = 0;
 
-#ifdef HAVE_NEW_DEVICE_MODEL
 	/* Send notification to devices that they will be suspended.
 	 * If any device or driver cannot make the transition, either up
 	 * or down, we'll get an error back.
@@ -174,10 +169,9 @@
 	error = device_suspend(state, SUSPEND_NOTIFY);
 	if (error)
 		return AE_ERROR;
-#endif
+
 	if (state < ACPI_STATE_S5) {
 
-#ifdef HAVE_NEW_DEVICE_MODEL
 		/* Tell devices to stop I/O and actually save their state.
 		 * It is theoretically possible that something could fail,
 		 * so handle that gracefully..
@@ -190,7 +184,6 @@
 			device_resume(RESUME_RESTORE_STATE);
 			return error;
 		}
-#endif
 
 		/* flush caches */
 		ACPI_FLUSH_CPU_CACHE();
@@ -202,15 +195,13 @@
 			if (!error && (state == ACPI_STATE_S4))
 				error = acpi_save_state_disk();
 
-#ifdef HAVE_NEW_DEVICE_MODEL
 			if (error) {
 				device_resume(RESUME_RESTORE_STATE);
 				return error;
 			}
-#endif
 		}
 	}
-#ifdef HAVE_NEW_DEVICE_MODEL
+
 	/* disable interrupts
 	 * Note that acpi_suspend -- our caller -- will do this once we return.
 	 * But, we want it done early, so we don't get any suprises during
@@ -233,7 +224,7 @@
 	 */
 	if (error && state != ACPI_STATE_S5)
 		acpi_system_restore_state(state);
-#endif
+
 	return error ? AE_ERROR : AE_OK;
 }
 
@@ -515,12 +506,12 @@
 		if (size > count)
 			size = count;
 		if (copy_to_user(buffer, data, size)) {
-			kfree(dsdt.pointer);
+			acpi_os_free(dsdt.pointer);
 			return_VALUE(-EFAULT);
 		}
 	}
 
-	kfree(dsdt.pointer);
+	acpi_os_free(dsdt.pointer);
 
 	*ppos += size;
 
@@ -558,12 +549,12 @@
 		if (size > count)
 			size = count;
 		if (copy_to_user(buffer, data, size)) {
-			kfree(fadt.pointer);
+			acpi_os_free(fadt.pointer);
 			return_VALUE(-EFAULT);
 		}
 	}
 
-	kfree(fadt.pointer);
+	acpi_os_free(fadt.pointer);
 
 	*ppos += size;
 
@@ -1174,7 +1165,7 @@
 
 /* Simple wrapper calling power down function. */
 static void acpi_sysrq_power_off(int key, struct pt_regs *pt_regs,
-	struct kbd_struct *kbd, struct tty_struct *tty)
+				 struct tty_struct *tty)
 {
 	acpi_power_off();
 }
diff -Nru a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c
--- a/drivers/acpi/tables/tbconvrt.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/tables/tbconvrt.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbconvrt - ACPI Table conversion utilities
- *              $Revision: 41 $
+ *              $Revision: 42 $
  *
  *****************************************************************************/
 
@@ -90,8 +90,7 @@
 
 acpi_status
 acpi_tb_convert_to_xsdt (
-	acpi_table_desc         *table_info,
-	u32                     *number_of_tables)
+	acpi_table_desc         *table_info)
 {
 	ACPI_SIZE               table_size;
 	u32                     i;
@@ -101,13 +100,10 @@
 	ACPI_FUNCTION_ENTRY ();
 
 
-	/* Get the number of tables defined in the RSDT or XSDT */
-
-	*number_of_tables = acpi_tb_get_table_count (acpi_gbl_RSDP, table_info->pointer);
-
 	/* Compute size of the converted XSDT */
 
-	table_size = ((ACPI_SIZE) *number_of_tables * sizeof (u64)) + sizeof (acpi_table_header);
+	table_size = ((ACPI_SIZE) acpi_gbl_rsdt_table_count * sizeof (u64)) +
+			  sizeof (acpi_table_header);
 
 	/* Allocate an XSDT */
 
@@ -123,7 +119,7 @@
 
 	/* Copy the table pointers */
 
-	for (i = 0; i < *number_of_tables; i++) {
+	for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
 		if (acpi_gbl_RSDP->revision < 2) {
 			ACPI_STORE_ADDRESS (new_table->table_offset_entry[i],
 				((RSDT_DESCRIPTOR_REV1 *) table_info->pointer)->table_offset_entry[i]);
diff -Nru a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
--- a/drivers/acpi/tables/tbget.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/tables/tbget.c	Tue Jul 16 16:49:43 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbget - ACPI Table get* routines
- *              $Revision: 77 $
+ *              $Revision: 78 $
  *
  *****************************************************************************/
 
@@ -34,777 +34,438 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    Acpi_tb_table_override
+ * FUNCTION:    Acpi_tb_get_table
  *
- * PARAMETERS:  *Table_info         - Info for current table
+ * PARAMETERS:  Address             - Address of table to retrieve.  Can be
+ *                                    Logical or Physical
+ *              Table_info          - Where table info is returned
  *
  * RETURN:      None
  *
- * DESCRIPTION: Attempts override of current table with a new one if provided
- *              by the host OS.
+ * DESCRIPTION: Get entire table of unknown size.
  *
  ******************************************************************************/
 
-void
-acpi_tb_table_override (
+acpi_status
+acpi_tb_get_table (
+	ACPI_POINTER            *address,
 	acpi_table_desc         *table_info)
 {
-	acpi_table_header       *new_table;
 	acpi_status             status;
-	ACPI_POINTER            address;
-	acpi_table_desc         new_table_info;
-
-
-	ACPI_FUNCTION_TRACE ("Acpi_tb_table_override");
-
-
-	status = acpi_os_table_override (table_info->pointer, &new_table);
-	if (ACPI_FAILURE (status)) {
-		/* Some severe error from the OSL, but we basically ignore it */
+	acpi_table_header       header;
 
-		ACPI_REPORT_ERROR (("Could not override ACPI table, %s\n",
-			acpi_format_exception (status)));
-		return_VOID;
-	}
 
-	if (!new_table) {
-		/* No table override */
+	ACPI_FUNCTION_TRACE ("Tb_get_table");
 
-		return_VOID;
-	}
 
 	/*
-	 * We have a new table to override the old one.  Get a copy of
-	 * the new one.  We know that the new table has a logical pointer.
+	 * Get the header in order to get signature and table size
 	 */
-	address.pointer_type    = ACPI_LOGICAL_POINTER;
-	address.pointer.logical = new_table;
-
-	status = acpi_tb_get_table (&address, &new_table_info);
+	status = acpi_tb_get_table_header (address, &header);
 	if (ACPI_FAILURE (status)) {
-		ACPI_REPORT_ERROR (("Could not copy ACPI table override\n"));
-		return_VOID;
+		return_ACPI_STATUS (status);
 	}
 
-	/*
-	 * Delete the original table
-	 */
-	acpi_tb_delete_single_table (table_info);
-
-	/* Copy the table info */
+	/* Get the entire table */
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Successful table override [%4.4s]\n",
-		((acpi_table_header *) new_table_info.pointer)->signature));
+	status = acpi_tb_get_table_body (address, &header, table_info);
+	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_ERROR (("Could not get ACPI table (size %X), %s\n",
+			header.length, acpi_format_exception (status)));
+		return_ACPI_STATUS (status);
+	}
 
-	ACPI_MEMCPY (table_info, &new_table_info, sizeof (acpi_table_desc));
-	return_VOID;
+	return_ACPI_STATUS (AE_OK);
 }
 
 
 /*******************************************************************************
  *
- * FUNCTION:    Acpi_tb_get_table_with_override
+ * FUNCTION:    Acpi_tb_get_table_header
  *
- * PARAMETERS:  Address             - Physical or logical address of table
- *              *Table_info         - Where the table info is returned
+ * PARAMETERS:  Address             - Address of table to retrieve.  Can be
+ *                                    Logical or Physical
+ *              Return_header       - Where the table header is returned
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Gets and installs the table with possible table override by OS.
+ * DESCRIPTION: Get an ACPI table header.  Works in both physical or virtual
+ *              addressing mode.  Works with both physical or logical pointers.
+ *              Table is either copied or mapped, depending on the pointer
+ *              type and mode of the processor.
  *
  ******************************************************************************/
 
 acpi_status
-acpi_tb_get_table_with_override (
+acpi_tb_get_table_header (
 	ACPI_POINTER            *address,
-	acpi_table_desc         *table_info)
+	acpi_table_header       *return_header)
 {
-	acpi_status             status;
+	acpi_status             status = AE_OK;
+	acpi_table_header       *header = NULL;
 
 
-	ACPI_FUNCTION_TRACE ("Acpi_tb_get_table_with_override");
+	ACPI_FUNCTION_TRACE ("Tb_get_table_header");
 
 
-	status = acpi_tb_get_table (address, table_info);
-	if (ACPI_FAILURE (status)) {
-		ACPI_REPORT_ERROR (("Could not get ACPI table, %s\n",
-			acpi_format_exception (status)));
-		return_ACPI_STATUS (status);
-	}
-
 	/*
-	 * Attempt override.  It either happens or it doesn't, no status
+	 * Flags contains the current processor mode (Virtual or Physical addressing)
+	 * The Pointer_type is either Logical or Physical
 	 */
-	acpi_tb_table_override (table_info);
+	switch (address->pointer_type) {
+	case ACPI_PHYSMODE_PHYSPTR:
+	case ACPI_LOGMODE_LOGPTR:
 
-	/* Install the table */
+		/* Pointer matches processor mode, copy the header */
 
-	status = acpi_tb_install_table (table_info);
-	if (ACPI_FAILURE (status)) {
-		ACPI_REPORT_ERROR (("Could not install ACPI table, %s\n",
-			acpi_format_exception (status)));
-	}
+		ACPI_MEMCPY (return_header, address->pointer.logical, sizeof (acpi_table_header));
+		break;
 
-	return_ACPI_STATUS (status);
-}
 
+	case ACPI_LOGMODE_PHYSPTR:
 
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_tb_get_table_ptr
- *
- * PARAMETERS:  Table_type      - one of the defined table types
- *              Instance        - Which table of this type
- *              Table_ptr_loc   - pointer to location to place the pointer for
- *                                return
- *
- * RETURN:      Status
- *
- * DESCRIPTION: This function is called to get the pointer to an ACPI table.
- *
- ******************************************************************************/
+		/* Create a logical address for the physical pointer*/
 
-acpi_status
-acpi_tb_get_table_ptr (
-	acpi_table_type         table_type,
-	u32                     instance,
-	acpi_table_header       **table_ptr_loc)
-{
-	acpi_table_desc         *table_desc;
-	u32                     i;
+		status = acpi_os_map_memory (address->pointer.physical, sizeof (acpi_table_header),
+				  (void **) &header);
+		if (ACPI_FAILURE (status)) {
+			ACPI_REPORT_ERROR (("Could not map memory at %p for length %X\n",
+				address->pointer.physical, sizeof (acpi_table_header)));
+			return_ACPI_STATUS (status);
+		}
 
+		/* Copy header and delete mapping */
 
-	ACPI_FUNCTION_TRACE ("Tb_get_table_ptr");
+		ACPI_MEMCPY (return_header, header, sizeof (acpi_table_header));
+		acpi_os_unmap_memory (header, sizeof (acpi_table_header));
+		break;
 
 
-	if (!acpi_gbl_DSDT) {
-		return_ACPI_STATUS (AE_NO_ACPI_TABLES);
-	}
+	default:
 
-	if (table_type > ACPI_TABLE_MAX) {
+		ACPI_REPORT_ERROR (("Invalid address flags %X\n",
+			address->pointer_type));
 		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
 
-	/*
-	 * For all table types (Single/Multiple), the first
-	 * instance is always in the list head.
-	 */
-	if (instance == 1) {
-		/*
-		 * Just pluck the pointer out of the global table!
-		 * Will be null if no table is present
-		 */
-		*table_ptr_loc = acpi_gbl_acpi_tables[table_type].pointer;
-		return_ACPI_STATUS (AE_OK);
-	}
-
-	/*
-	 * Check for instance out of range
-	 */
-	if (instance > acpi_gbl_acpi_tables[table_type].count) {
-		return_ACPI_STATUS (AE_NOT_EXIST);
-	}
-
-	/* Walk the list to get the desired table
-	 * Since the if (Instance == 1) check above checked for the
-	 * first table, setting Table_desc equal to the .Next member
-	 * is actually pointing to the second table.  Therefore, we
-	 * need to walk from the 2nd table until we reach the Instance
-	 * that the user is looking for and return its table pointer.
-	 */
-	table_desc = acpi_gbl_acpi_tables[table_type].next;
-	for (i = 2; i < instance; i++) {
-		table_desc = table_desc->next;
-	}
-
-	/* We are now pointing to the requested table's descriptor */
-
-	*table_ptr_loc = table_desc->pointer;
-
 	return_ACPI_STATUS (AE_OK);
 }
 
 
 /*******************************************************************************
  *
- * FUNCTION:    Acpi_tb_get_table
+ * FUNCTION:    Acpi_tb_get_table_body
  *
- * PARAMETERS:  Address             - Physical address of table to retrieve
- *              *Table_info         - Where the table info is returned
+ * PARAMETERS:  Address             - Address of table to retrieve.  Can be
+ *                                    Logical or Physical
+ *              Header              - Header of the table to retrieve
+ *              Table_info          - Where the table info is returned
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Maps the physical address of table into a logical address
+ * DESCRIPTION: Get an entire ACPI table with support to allow the host OS to
+ *              replace the table with a newer version (table override.)
+ *              Works in both physical or virtual
+ *              addressing mode.  Works with both physical or logical pointers.
+ *              Table is either copied or mapped, depending on the pointer
+ *              type and mode of the processor.
  *
  ******************************************************************************/
 
 acpi_status
-acpi_tb_get_table (
+acpi_tb_get_table_body (
 	ACPI_POINTER            *address,
+	acpi_table_header       *header,
 	acpi_table_desc         *table_info)
 {
-	acpi_table_header       *table_header = NULL;
-	acpi_table_header       *full_table = NULL;
-	ACPI_SIZE               size;
-	u8                      allocation;
-	acpi_status             status = AE_OK;
+	acpi_status             status;
 
 
-	ACPI_FUNCTION_TRACE ("Tb_get_table");
+	ACPI_FUNCTION_TRACE ("Tb_get_table_body");
 
 
 	if (!table_info || !address) {
 		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
 
-	switch (address->pointer_type) {
-	case ACPI_LOGICAL_POINTER:
-
-		/*
-		 * Getting data from a buffer, not BIOS tables
-		 */
-		table_header = address->pointer.logical;
-
-		/* Allocate buffer for the entire table */
-
-		full_table = ACPI_MEM_ALLOCATE (table_header->length);
-		if (!full_table) {
-			return_ACPI_STATUS (AE_NO_MEMORY);
-		}
-
-		/* Copy the entire table (including header) to the local buffer */
-
-		size = (ACPI_SIZE) table_header->length;
-		ACPI_MEMCPY (full_table, table_header, size);
-
-		/* Save allocation type */
-
-		allocation = ACPI_MEM_ALLOCATED;
-		break;
-
-
-	case ACPI_PHYSICAL_POINTER:
-
-		/*
-		 * Not reading from a buffer, just map the table's physical memory
-		 * into our address space.
-		 */
-		size = SIZE_IN_HEADER;
-
-		status = acpi_tb_map_acpi_table (address->pointer.physical, &size, &full_table);
-		if (ACPI_FAILURE (status)) {
-			return_ACPI_STATUS (status);
-		}
-
-		/* Save allocation type */
-
-		allocation = ACPI_MEM_MAPPED;
-		break;
-
+	/*
+	 * Attempt table override.
+	 */
+	status = acpi_tb_table_override (header, table_info);
+	if (ACPI_SUCCESS (status)) {
+		/* Table was overridden by the host OS */
 
-	default:
-		return_ACPI_STATUS (AE_BAD_PARAMETER);
+		return_ACPI_STATUS (status);
 	}
 
-	/* Return values */
-
-	table_info->pointer     = full_table;
-	table_info->length      = size;
-	table_info->allocation  = allocation;
-	table_info->base_pointer = full_table;
-
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
-		"Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n",
-		full_table->signature,
-		ACPI_HIDWORD (address->pointer.physical),
-		ACPI_LODWORD (address->pointer.physical), full_table));
+	/* No override, get the original table */
 
+	status = acpi_tb_get_this_table (address, header, table_info);
 	return_ACPI_STATUS (status);
 }
 
 
 /*******************************************************************************
  *
- * FUNCTION:    Acpi_tb_get_all_tables
- *
- * PARAMETERS:  Number_of_tables    - Number of tables to get
- *
- * RETURN:      Status
+ * FUNCTION:    Acpi_tb_table_override
  *
- * DESCRIPTION: Load and validate tables other than the RSDT.  The RSDT must
- *              already be loaded and validated.
+ * PARAMETERS:  Header              - Pointer to table header
+ *              Table_info          - Return info if table is overridden
  *
- *              Get the minimum set of ACPI tables, namely:
+ * RETURN:      None
  *
- *              1) FADT (via RSDT in loop below)
- *              2) FACS (via FADT)
- *              3) DSDT (via FADT)
+ * DESCRIPTION: Attempts override of current table with a new one if provided
+ *              by the host OS.
  *
  ******************************************************************************/
 
 acpi_status
-acpi_tb_get_all_tables (
-	u32                     number_of_tables)
+acpi_tb_table_override (
+	acpi_table_header       *header,
+	acpi_table_desc         *table_info)
 {
-	acpi_status             status = AE_OK;
-	u32                     index;
-	acpi_table_desc         table_info;
+	acpi_table_header       *new_table;
+	acpi_status             status;
 	ACPI_POINTER            address;
 
 
-	ACPI_FUNCTION_TRACE ("Tb_get_all_tables");
-
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Number of tables: %d\n", number_of_tables));
-
-
-	/*
-	 * Loop through all table pointers found in RSDT.
-	 * This will NOT include the FACS and DSDT - we must get
-	 * them after the loop.
-	 *
-	 * The ONLY table we are interested in getting here is the FADT.
-	 */
-	for (index = 0; index < number_of_tables; index++) {
-		/* Clear the Table_info each time */
-
-		ACPI_MEMSET (&table_info, 0, sizeof (acpi_table_desc));
-
-		/* Get the table via the XSDT */
-
-		address.pointer_type  = acpi_gbl_table_flags;
-		address.pointer.value = ACPI_GET_ADDRESS (acpi_gbl_XSDT->table_offset_entry[index]);
-
-		status = acpi_tb_get_table (&address, &table_info);
-		if (ACPI_FAILURE (status)) {
-			return_ACPI_STATUS (status);
-		}
+	ACPI_FUNCTION_TRACE ("Tb_table_override");
 
-		/* Recognize and install the table */
-
-		status = acpi_tb_install_table (&table_info);
-		if (ACPI_FAILURE (status)) {
-			/*
-			 * Unrecognized or unsupported table, delete it and ignore the
-			 * error.  Just get as many tables as we can, later we will
-			 * determine if there are enough tables to continue.
-			 */
-			(void) acpi_tb_uninstall_table (&table_info);
-			status = AE_OK;
-		}
-	}
-
-	if (!acpi_gbl_FADT) {
-		ACPI_REPORT_ERROR (("No FADT present in R/XSDT\n"));
-		return_ACPI_STATUS (AE_NO_ACPI_TABLES);
-	}
 
 	/*
-	 * Convert the FADT to a common format.  This allows earlier revisions of the
-	 * table to coexist with newer versions, using common access code.
+	 * The OSL will examine the header and decide whether to override this
+	 * table.  If it decides to override, a table will be returned in New_table,
+	 * which we will then copy.
 	 */
-	status = acpi_tb_convert_table_fadt ();
+	status = acpi_os_table_override (header, &new_table);
 	if (ACPI_FAILURE (status)) {
-		ACPI_REPORT_ERROR (("Could not convert FADT to internal common format\n"));
-		return_ACPI_STATUS (status);
-	}
-
-	/*
-	 * Get the FACS (must have the FADT first, from loop above)
-	 * Acpi_tb_get_table_facs will fail if FADT pointer is not valid
-	 */
-	address.pointer_type  = acpi_gbl_table_flags;
-	address.pointer.value = ACPI_GET_ADDRESS (acpi_gbl_FADT->Xfirmware_ctrl);
+		/* Some severe error from the OSL, but we basically ignore it */
 
-	status = acpi_tb_get_table (&address, &table_info);
-	if (ACPI_FAILURE (status)) {
-		ACPI_REPORT_ERROR (("Could not get the FACS, %s\n",
+		ACPI_REPORT_ERROR (("Could not override ACPI table, %s\n",
 			acpi_format_exception (status)));
 		return_ACPI_STATUS (status);
 	}
 
-	/* Install the FACS */
-
-	status = acpi_tb_install_table (&table_info);
-	if (ACPI_FAILURE (status)) {
-		ACPI_REPORT_ERROR (("Could not install the FACS, %s\n",
-			acpi_format_exception (status)));
-		return_ACPI_STATUS (status);
-	}
+	if (!new_table) {
+		/* No table override */
 
-	/*
-	 * Create the common FACS pointer table
-	 * (Contains pointers to the original table)
-	 */
-	status = acpi_tb_build_common_facs (&table_info);
-	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
+		return_ACPI_STATUS (AE_NO_ACPI_TABLES);
 	}
 
 	/*
-	 * Get/install the DSDT (We know that the FADT is valid now)
+	 * We have a new table to override the old one.  Get a copy of
+	 * the new one.  We know that the new table has a logical pointer.
 	 */
-	address.pointer_type  = acpi_gbl_table_flags;
-	address.pointer.value = ACPI_GET_ADDRESS (acpi_gbl_FADT->Xdsdt);
+	address.pointer_type    = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
+	address.pointer.logical = new_table;
 
-	status = acpi_tb_get_table_with_override (&address, &table_info);
+	status = acpi_tb_get_this_table (&address, new_table, table_info);
 	if (ACPI_FAILURE (status)) {
-		ACPI_REPORT_ERROR (("Could not get the DSDT\n"));
+		ACPI_REPORT_ERROR (("Could not copy override ACPI table, %s\n",
+			acpi_format_exception (status)));
 		return_ACPI_STATUS (status);
 	}
 
-	/* Set Integer Width (32/64) based upon DSDT revision */
-
-	acpi_ut_set_integer_width (acpi_gbl_DSDT->revision);
-
-	/* Dump the entire DSDT */
-
-	ACPI_DEBUG_PRINT ((ACPI_DB_TABLES,
-		"Hex dump of entire DSDT, size %d (0x%X), Integer width = %d\n",
-		acpi_gbl_DSDT->length, acpi_gbl_DSDT->length, acpi_gbl_integer_bit_width));
-	ACPI_DUMP_BUFFER ((u8 *) acpi_gbl_DSDT, acpi_gbl_DSDT->length);
+	/* Copy the table info */
 
-	/* Always delete the RSDP mapping, we are done with it */
+	ACPI_REPORT_INFO (("Table [%4.4s] replaced by host OS\n",
+		table_info->pointer->signature));
 
-	acpi_tb_delete_acpi_table (ACPI_TABLE_RSDP);
-	return_ACPI_STATUS (status);
+	return_ACPI_STATUS (AE_OK);
 }
 
 
 /*******************************************************************************
  *
- * FUNCTION:    Acpi_tb_verify_rsdp
+ * FUNCTION:    Acpi_tb_get_this_table
  *
- * PARAMETERS:  Number_of_tables    - Where the table count is placed
+ * PARAMETERS:  Address             - Address of table to retrieve.  Can be
+ *                                    Logical or Physical
+ *              Header              - Header of the table to retrieve
+ *              Table_info          - Where the table info is returned
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
+ * DESCRIPTION: Get an entire ACPI table.  Works in both physical or virtual
+ *              addressing mode.  Works with both physical or logical pointers.
+ *              Table is either copied or mapped, depending on the pointer
+ *              type and mode of the processor.
  *
  ******************************************************************************/
 
 acpi_status
-acpi_tb_verify_rsdp (
-	ACPI_POINTER            *address)
+acpi_tb_get_this_table (
+	ACPI_POINTER            *address,
+	acpi_table_header       *header,
+	acpi_table_desc         *table_info)
 {
-	acpi_table_desc         table_info;
-	acpi_status             status;
-	RSDP_DESCRIPTOR         *rsdp;
-
-
-	ACPI_FUNCTION_TRACE ("Tb_verify_rsdp");
-
-
-	switch (address->pointer_type) {
-	case ACPI_LOGICAL_POINTER:
+	acpi_table_header       *full_table = NULL;
+	u8                      allocation;
+	acpi_status             status = AE_OK;
 
-		rsdp = address->pointer.logical;
-		break;
 
-	case ACPI_PHYSICAL_POINTER:
-		/*
-		 * Obtain access to the RSDP structure
-		 */
-		status = acpi_os_map_memory (address->pointer.physical, sizeof (RSDP_DESCRIPTOR),
-				  (void **) &rsdp);
-		if (ACPI_FAILURE (status)) {
-			return_ACPI_STATUS (status);
-		}
-		break;
+	ACPI_FUNCTION_TRACE ("Tb_get_this_table");
 
-	default:
-		return_ACPI_STATUS (AE_BAD_PARAMETER);
-	}
 
 	/*
-	 *  The signature and checksum must both be correct
+	 * Flags contains the current processor mode (Virtual or Physical addressing)
+	 * The Pointer_type is either Logical or Physical
 	 */
-	if (ACPI_STRNCMP ((NATIVE_CHAR *) rsdp, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) {
-		/* Nope, BAD Signature */
-
-		status = AE_BAD_SIGNATURE;
-		goto cleanup;
-	}
-
-	/* Check the standard checksum */
-
-	if (acpi_tb_checksum (rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
-		status = AE_BAD_CHECKSUM;
-		goto cleanup;
-	}
+	switch (address->pointer_type) {
+	case ACPI_PHYSMODE_PHYSPTR:
+	case ACPI_LOGMODE_LOGPTR:
 
-	/* Check extended checksum if table version >= 2 */
+		/* Pointer matches processor mode, copy the table to a new buffer */
 
-	if (rsdp->revision >= 2) {
-		if (acpi_tb_checksum (rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0) {
-			status = AE_BAD_CHECKSUM;
-			goto cleanup;
+		full_table = ACPI_MEM_ALLOCATE (header->length);
+		if (!full_table) {
+			ACPI_REPORT_ERROR (("Could not allocate table memory for [%4.4s] length %X\n",
+				header->signature, header->length));
+			return_ACPI_STATUS (AE_NO_MEMORY);
 		}
-	}
-
-	/* The RSDP supplied is OK */
-
-	table_info.pointer     = ACPI_CAST_PTR (acpi_table_header, rsdp);
-	table_info.length      = sizeof (RSDP_DESCRIPTOR);
-	table_info.allocation  = ACPI_MEM_MAPPED;
-	table_info.base_pointer = rsdp;
-
-	/* Save the table pointers and allocation info */
-
-	status = acpi_tb_init_table_descriptor (ACPI_TABLE_RSDP, &table_info);
-	if (ACPI_FAILURE (status)) {
-		goto cleanup;
-	}
-
-	/* Save the RSDP in a global for easy access */
-
-	acpi_gbl_RSDP = ACPI_CAST_PTR (RSDP_DESCRIPTOR, table_info.pointer);
-	return_ACPI_STATUS (status);
-
-
-	/* Error exit */
-cleanup:
-
-	if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) {
-		acpi_os_unmap_memory (rsdp, sizeof (RSDP_DESCRIPTOR));
-	}
-	return_ACPI_STATUS (status);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_tb_get_rsdt_address
- *
- * PARAMETERS:  None
- *
- * RETURN:      RSDT physical address
- *
- * DESCRIPTION: Extract the address of the RSDT or XSDT, depending on the
- *              version of the RSDP
- *
- ******************************************************************************/
-
-void
-acpi_tb_get_rsdt_address (
-	ACPI_POINTER            *out_address)
-{
-
-	ACPI_FUNCTION_ENTRY ();
-
-
-	out_address->pointer_type = acpi_gbl_table_flags;
-
-	/*
-	 * For RSDP revision 0 or 1, we use the RSDT.
-	 * For RSDP revision 2 (and above), we use the XSDT
-	 */
-	if (acpi_gbl_RSDP->revision < 2) {
-		out_address->pointer.value = acpi_gbl_RSDP->rsdt_physical_address;
-	}
-	else {
-		out_address->pointer.value = ACPI_GET_ADDRESS (acpi_gbl_RSDP->xsdt_physical_address);
-	}
-}
 
+		/* Copy the entire table (including header) to the local buffer */
 
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_tb_validate_rsdt
- *
- * PARAMETERS:  Table_ptr       - Addressable pointer to the RSDT.
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Validate signature for the RSDT or XSDT
- *
- ******************************************************************************/
+		ACPI_MEMCPY (full_table, address->pointer.logical, header->length);
 
-acpi_status
-acpi_tb_validate_rsdt (
-	acpi_table_header       *table_ptr)
-{
-	int                     no_match;
+		/* Save allocation type */
 
+		allocation = ACPI_MEM_ALLOCATED;
+		break;
 
-	ACPI_FUNCTION_NAME ("Tb_validate_rsdt");
 
+	case ACPI_LOGMODE_PHYSPTR:
 
-	/*
-	 * For RSDP revision 0 or 1, we use the RSDT.
-	 * For RSDP revision 2 and above, we use the XSDT
-	 */
-	if (acpi_gbl_RSDP->revision < 2) {
-		no_match = ACPI_STRNCMP ((char *) table_ptr, RSDT_SIG,
-				  sizeof (RSDT_SIG) -1);
-	}
-	else {
-		no_match = ACPI_STRNCMP ((char *) table_ptr, XSDT_SIG,
-				  sizeof (XSDT_SIG) -1);
-	}
+		/*
+		 * Just map the table's physical memory
+		 * into our address space.
+		 */
+		status = acpi_os_map_memory (address->pointer.physical, (ACPI_SIZE) header->length,
+				  (void **) &full_table);
+		if (ACPI_FAILURE (status)) {
+			ACPI_REPORT_ERROR (("Could not map memory for table [%4.4s] at %p for length %X\n",
+				header->signature, address->pointer.physical, header->length));
+			return (status);
+		}
 
-	if (no_match) {
-		/* Invalid RSDT or XSDT signature */
+		/* Save allocation type */
 
-		ACPI_REPORT_ERROR (("Invalid signature where RSDP indicates RSDT/XSDT should be located\n"));
+		allocation = ACPI_MEM_MAPPED;
+		break;
 
-		ACPI_DUMP_BUFFER (acpi_gbl_RSDP, 20);
 
-		ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR,
-			"RSDT/XSDT signature at %X (%p) is invalid\n",
-			acpi_gbl_RSDP->rsdt_physical_address,
-			(void *) (NATIVE_UINT) acpi_gbl_RSDP->rsdt_physical_address));
+	default:
 
-		return (AE_BAD_SIGNATURE);
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid address flags %X\n",
+			address->pointer_type));
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
 
-	return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_tb_get_table_pointer
- *
- * PARAMETERS:  Physical_address    - Address from RSDT
- *              Flags               - virtual or physical addressing
- *              Table_ptr           - Addressable address (output)
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Create an addressable pointer to an ACPI table
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_pointer (
-	ACPI_POINTER            *address,
-	u32                     flags,
-	ACPI_SIZE               *size,
-	acpi_table_header       **table_ptr)
-{
-	acpi_status             status = AE_OK;
-
-
-	ACPI_FUNCTION_ENTRY ();
-
-
 	/*
-	 * What mode is the processor in? (Virtual or Physical addressing)
+	 * Validate checksum for _most_ tables,
+	 * even the ones whose signature we don't recognize
 	 */
-	if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
-		/* Incoming pointer can be either logical or physical */
-
-		switch (address->pointer_type) {
-		case ACPI_PHYSICAL_POINTER:
-
-			*size = SIZE_IN_HEADER;
-			status = acpi_tb_map_acpi_table (address->pointer.physical, size, table_ptr);
-			break;
+	if (table_info->type != ACPI_TABLE_FACS) {
+		status = acpi_tb_verify_table_checksum (full_table);
 
-		case ACPI_LOGICAL_POINTER:
-
-			*table_ptr = address->pointer.logical;
-			*size = 0;
-			break;
+#if (!ACPI_CHECKSUM_ABORT)
+		if (ACPI_FAILURE (status)) {
+			/* Ignore the error if configuration says so */
 
-		default:
-			return (AE_BAD_PARAMETER);
+			status = AE_OK;
 		}
+#endif
 	}
-	else {
-		/* In Physical addressing mode, all pointers must be physical */
-
-		switch (address->pointer_type) {
-		case ACPI_PHYSICAL_POINTER:
-			*size = 0;
-			*table_ptr = address->pointer.logical;
-			break;
 
-		case ACPI_LOGICAL_POINTER:
+	/* Return values */
 
-			status = AE_BAD_PARAMETER;
-			break;
+	table_info->pointer     = full_table;
+	table_info->length      = (ACPI_SIZE) header->length;
+	table_info->allocation  = allocation;
+	table_info->base_pointer = full_table;
 
-		default:
-			return (AE_BAD_PARAMETER);
-		}
-	}
+	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+		"Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n",
+		full_table->signature,
+		ACPI_HIDWORD (address->pointer.physical),
+		ACPI_LODWORD (address->pointer.physical), full_table));
 
-	return (status);
+	return_ACPI_STATUS (status);
 }
 
 
 /*******************************************************************************
  *
- * FUNCTION:    Acpi_tb_get_table_rsdt
+ * FUNCTION:    Acpi_tb_get_table_ptr
  *
- * PARAMETERS:  Number_of_tables    - Where the table count is placed
+ * PARAMETERS:  Table_type      - one of the defined table types
+ *              Instance        - Which table of this type
+ *              Table_ptr_loc   - pointer to location to place the pointer for
+ *                                return
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
+ * DESCRIPTION: This function is called to get the pointer to an ACPI table.
  *
  ******************************************************************************/
 
 acpi_status
-acpi_tb_get_table_rsdt (
-	u32                     *number_of_tables)
+acpi_tb_get_table_ptr (
+	acpi_table_type         table_type,
+	u32                     instance,
+	acpi_table_header       **table_ptr_loc)
 {
-	acpi_table_desc         table_info;
-	acpi_status             status;
-	ACPI_POINTER            address;
-
+	acpi_table_desc         *table_desc;
+	u32                     i;
 
-	ACPI_FUNCTION_TRACE ("Tb_get_table_rsdt");
 
+	ACPI_FUNCTION_TRACE ("Tb_get_table_ptr");
 
-	/* Get the RSDT/XSDT from the RSDP */
 
-	acpi_tb_get_rsdt_address (&address);
-	status = acpi_tb_get_table (&address, &table_info);
-	if (ACPI_FAILURE (status)) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not get the R/XSDT, %s\n",
-			acpi_format_exception (status)));
-		return_ACPI_STATUS (status);
+	if (!acpi_gbl_DSDT) {
+		return_ACPI_STATUS (AE_NO_ACPI_TABLES);
 	}
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
-		"RSDP located at %p, RSDT physical=%8.8X%8.8X \n",
-		acpi_gbl_RSDP,
-		ACPI_HIDWORD (address.pointer.value),
-		ACPI_LODWORD (address.pointer.value)));
-
-	/* Check the RSDT or XSDT signature */
-
-	status = acpi_tb_validate_rsdt (table_info.pointer);
-	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
+	if (table_type > ACPI_TABLE_MAX) {
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
 
 	/*
-	 * Valid RSDT signature, verify the checksum.  If it fails, just
-	 * print a warning and ignore it.
+	 * For all table types (Single/Multiple), the first
+	 * instance is always in the list head.
 	 */
-	status = acpi_tb_verify_table_checksum (table_info.pointer);
-
-	/* Convert and/or copy to an XSDT structure */
-
-	status = acpi_tb_convert_to_xsdt (&table_info, number_of_tables);
-	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
+	if (instance == 1) {
+		/*
+		 * Just pluck the pointer out of the global table!
+		 * Will be null if no table is present
+		 */
+		*table_ptr_loc = acpi_gbl_acpi_tables[table_type].pointer;
+		return_ACPI_STATUS (AE_OK);
 	}
 
-	/* Save the table pointers and allocation info */
+	/*
+	 * Check for instance out of range
+	 */
+	if (instance > acpi_gbl_acpi_tables[table_type].count) {
+		return_ACPI_STATUS (AE_NOT_EXIST);
+	}
 
-	status = acpi_tb_init_table_descriptor (ACPI_TABLE_XSDT, &table_info);
-	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
+	/* Walk the list to get the desired table
+	 * Since the if (Instance == 1) check above checked for the
+	 * first table, setting Table_desc equal to the .Next member
+	 * is actually pointing to the second table.  Therefore, we
+	 * need to walk from the 2nd table until we reach the Instance
+	 * that the user is looking for and return its table pointer.
+	 */
+	table_desc = acpi_gbl_acpi_tables[table_type].next;
+	for (i = 2; i < instance; i++) {
+		table_desc = table_desc->next;
 	}
 
-	acpi_gbl_XSDT = (xsdt_descriptor *) table_info.pointer;
+	/* We are now pointing to the requested table's descriptor */
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT));
-	return_ACPI_STATUS (status);
-}
+	*table_ptr_loc = table_desc->pointer;
 
+	return_ACPI_STATUS (AE_OK);
+}
 
diff -Nru a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/acpi/tables/tbgetall.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,290 @@
+/******************************************************************************
+ *
+ * Module Name: tbgetall - Get all required ACPI tables
+ *              $Revision: 1 $
+ *
+ *****************************************************************************/
+
+/*
+ *  Copyright (C) 2000 - 2002, R. Byron Moore
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "acpi.h"
+#include "actables.h"
+
+
+#define _COMPONENT          ACPI_TABLES
+	 ACPI_MODULE_NAME    ("tbgetall")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_tb_get_primary_table
+ *
+ * PARAMETERS:  Address             - Physical address of table to retrieve
+ *              *Table_info         - Where the table info is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Maps the physical address of table into a logical address
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_primary_table (
+	ACPI_POINTER            *address,
+	acpi_table_desc         *table_info)
+{
+	acpi_status             status;
+	acpi_table_header       header;
+
+
+	ACPI_FUNCTION_TRACE ("Tb_get_primary_table");
+
+
+	/* Ignore a NULL address in the RSDT */
+
+	if (!address->pointer.value) {
+		return_ACPI_STATUS (AE_OK);
+	}
+
+	/*
+	 * Get the header in order to get signature and table size
+	 */
+	status = acpi_tb_get_table_header (address, &header);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	/* Clear the Table_info */
+
+	ACPI_MEMSET (table_info, 0, sizeof (acpi_table_desc));
+
+	/*
+	 * Check the table signature and make sure it is recognized.
+	 * Also checks the header checksum
+	 */
+	table_info->pointer = &header;
+	status = acpi_tb_recognize_table (table_info, ACPI_TABLE_PRIMARY);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	/* Get the entire table */
+
+	status = acpi_tb_get_table_body (address, &header, table_info);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	/* Install the table */
+
+	status = acpi_tb_install_table (table_info);
+	return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_tb_get_secondary_table
+ *
+ * PARAMETERS:  Address             - Physical address of table to retrieve
+ *              *Table_info         - Where the table info is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Maps the physical address of table into a logical address
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_secondary_table (
+	ACPI_POINTER            *address,
+	acpi_string             signature,
+	acpi_table_desc         *table_info)
+{
+	acpi_status             status;
+	acpi_table_header       header;
+
+
+	ACPI_FUNCTION_TRACE_STR ("Tb_get_secondary_table", signature);
+
+
+	/* Get the header in order to match the signature */
+
+	status = acpi_tb_get_table_header (address, &header);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	/* Signature must match request */
+
+	if (ACPI_STRNCMP (header.signature, signature, ACPI_NAME_SIZE)) {
+		ACPI_REPORT_ERROR (("Incorrect table signature - wanted [%s] found [%4.4s]\n",
+			signature, header.signature));
+		return_ACPI_STATUS (AE_BAD_SIGNATURE);
+	}
+
+	/*
+	 * Check the table signature and make sure it is recognized.
+	 * Also checks the header checksum
+	 */
+	table_info->pointer = &header;
+	status = acpi_tb_recognize_table (table_info, ACPI_TABLE_SECONDARY);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	/* Get the entire table */
+
+	status = acpi_tb_get_table_body (address, &header, table_info);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	/* Install the table */
+
+	status = acpi_tb_install_table (table_info);
+	return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_tb_get_required_tables
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Load and validate tables other than the RSDT.  The RSDT must
+ *              already be loaded and validated.
+ *
+ *              Get the minimum set of ACPI tables, namely:
+ *
+ *              1) FADT (via RSDT in loop below)
+ *              2) FACS (via FADT)
+ *              3) DSDT (via FADT)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_required_tables (
+	void)
+{
+	acpi_status             status = AE_OK;
+	u32                     i;
+	acpi_table_desc         table_info;
+	ACPI_POINTER            address;
+
+
+	ACPI_FUNCTION_TRACE ("Tb_get_required_tables");
+
+	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%d ACPI tables in RSDT\n",
+		acpi_gbl_rsdt_table_count));
+
+
+	address.pointer_type  = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
+
+	/*
+	 * Loop through all table pointers found in RSDT.
+	 * This will NOT include the FACS and DSDT - we must get
+	 * them after the loop.
+	 *
+	 * The only tables we are interested in getting here is the FADT and
+	 * any SSDTs.
+	 */
+	for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
+		/* Get the table addresss from the common internal XSDT */
+
+		address.pointer.value = ACPI_GET_ADDRESS (acpi_gbl_XSDT->table_offset_entry[i]);
+
+		/*
+		 * Get the tables needed by this subsystem (FADT and any SSDTs).
+		 * NOTE: All other tables are completely ignored at this time.
+		 */
+		acpi_tb_get_primary_table (&address, &table_info);
+	}
+
+	/* We must have a FADT to continue */
+
+	if (!acpi_gbl_FADT) {
+		ACPI_REPORT_ERROR (("No FADT present in RSDT/XSDT\n"));
+		return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+	}
+
+	/*
+	 * Convert the FADT to a common format.  This allows earlier revisions of the
+	 * table to coexist with newer versions, using common access code.
+	 */
+	status = acpi_tb_convert_table_fadt ();
+	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_ERROR (("Could not convert FADT to internal common format\n"));
+		return_ACPI_STATUS (status);
+	}
+
+	/*
+	 * Get the FACS (Pointed to by the FADT)
+	 */
+	address.pointer.value = ACPI_GET_ADDRESS (acpi_gbl_FADT->Xfirmware_ctrl);
+
+	status = acpi_tb_get_secondary_table (&address, FACS_SIG, &table_info);
+	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_ERROR (("Could not get/install the FACS, %s\n",
+			acpi_format_exception (status)));
+		return_ACPI_STATUS (status);
+	}
+
+	/*
+	 * Create the common FACS pointer table
+	 * (Contains pointers to the original table)
+	 */
+	status = acpi_tb_build_common_facs (&table_info);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	/*
+	 * Get/install the DSDT (Pointed to by the FADT)
+	 */
+	address.pointer.value = ACPI_GET_ADDRESS (acpi_gbl_FADT->Xdsdt);
+
+	status = acpi_tb_get_secondary_table (&address, DSDT_SIG, &table_info);
+	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_ERROR (("Could not get/install the DSDT\n"));
+		return_ACPI_STATUS (status);
+	}
+
+	/* Set Integer Width (32/64) based upon DSDT revision */
+
+	acpi_ut_set_integer_width (acpi_gbl_DSDT->revision);
+
+	/* Dump the entire DSDT */
+
+	ACPI_DEBUG_PRINT ((ACPI_DB_TABLES,
+		"Hex dump of entire DSDT, size %d (0x%X), Integer width = %d\n",
+		acpi_gbl_DSDT->length, acpi_gbl_DSDT->length, acpi_gbl_integer_bit_width));
+	ACPI_DUMP_BUFFER ((u8 *) acpi_gbl_DSDT, acpi_gbl_DSDT->length);
+
+	/* Always delete the RSDP mapping, we are done with it */
+
+	acpi_tb_delete_acpi_table (ACPI_TABLE_RSDP);
+	return_ACPI_STATUS (status);
+}
+
+
diff -Nru a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
--- a/drivers/acpi/tables/tbinstal.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/tables/tbinstal.c	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbinstal - ACPI table installation and removal
- *              $Revision: 61 $
+ *              $Revision: 62 $
  *
  *****************************************************************************/
 
@@ -49,7 +49,8 @@
 acpi_status
 acpi_tb_match_signature (
 	NATIVE_CHAR             *signature,
-	acpi_table_desc         *table_info)
+	acpi_table_desc         *table_info,
+	u8                      search_type)
 {
 	NATIVE_UINT             i;
 
@@ -61,6 +62,10 @@
 	 * Search for a signature match among the known table types
 	 */
 	for (i = 0; i < NUM_ACPI_TABLES; i++) {
+		if ((acpi_gbl_acpi_table_data[i].flags & ACPI_TABLE_TYPE_MASK) != search_type) {
+			continue;
+		}
+
 		if (!ACPI_STRNCMP (signature, acpi_gbl_acpi_table_data[i].signature,
 				   acpi_gbl_acpi_table_data[i].sig_length)) {
 			/* Found a signature match, return index if requested */
@@ -69,13 +74,18 @@
 				table_info->type = (u8) i;
 			}
 
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "ACPI Signature match %4.4s\n",
+			ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+				"Table [%4.4s] matched and is a required ACPI table\n",
 				(char *) acpi_gbl_acpi_table_data[i].signature));
 
 			return_ACPI_STATUS (AE_OK);
 		}
 	}
 
+	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+		"Table [%4.4s] is not a required ACPI table - ignored\n",
+		(char *) signature));
+
 	return_ACPI_STATUS (AE_TABLE_NOT_SUPPORTED);
 }
 
@@ -84,7 +94,7 @@
  *
  * FUNCTION:    Acpi_tb_install_table
  *
- * PARAMETERS:  Table_info          - Return value from Acpi_tb_get_table
+ * PARAMETERS:  Table_info          - Return value from Acpi_tb_get_table_body
  *
  * RETURN:      Status
  *
@@ -103,25 +113,22 @@
 	ACPI_FUNCTION_TRACE ("Tb_install_table");
 
 
-	/*
-	 * Check the table signature and make sure it is recognized
-	 * Also checks the header checksum
-	 */
-	status = acpi_tb_recognize_table (table_info);
-	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
-	}
-
 	/* Lock tables while installing */
 
 	status = acpi_ut_acquire_mutex (ACPI_MTX_TABLES);
 	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_ERROR (("Could not acquire table mutex for [%4.4s], %s\n",
+			table_info->pointer->signature, acpi_format_exception (status)));
 		return_ACPI_STATUS (status);
 	}
 
 	/* Install the table into the global data structure */
 
 	status = acpi_tb_init_table_descriptor (table_info->type, table_info);
+	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_ERROR (("Could not install ACPI table [%s], %s\n",
+			table_info->pointer->signature, acpi_format_exception (status)));
+	}
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s located at %p\n",
 		acpi_gbl_acpi_table_data[table_info->type].name, table_info->pointer));
@@ -135,7 +142,7 @@
  *
  * FUNCTION:    Acpi_tb_recognize_table
  *
- * PARAMETERS:  Table_info          - Return value from Acpi_tb_get_table
+ * PARAMETERS:  Table_info          - Return value from Acpi_tb_get_table_body
  *
  * RETURN:      Status
  *
@@ -153,7 +160,8 @@
 
 acpi_status
 acpi_tb_recognize_table (
-	acpi_table_desc         *table_info)
+	acpi_table_desc         *table_info,
+	u8                      search_type)
 {
 	acpi_table_header       *table_header;
 	acpi_status             status;
@@ -177,7 +185,7 @@
 	 * This can be any one of many valid ACPI tables, it just isn't one of
 	 * the tables that is consumed by the core subsystem
 	 */
-	status = acpi_tb_match_signature (table_header->signature, table_info);
+	status = acpi_tb_match_signature (table_header->signature, table_info, search_type);
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
@@ -190,22 +198,6 @@
 	/* Return the table type and length via the info struct */
 
 	table_info->length = (ACPI_SIZE) table_header->length;
-
-	/*
-	 * Validate checksum for _most_ tables,
-	 * even the ones whose signature we don't recognize
-	 */
-	if (table_info->type != ACPI_TABLE_FACS) {
-		status = acpi_tb_verify_table_checksum (table_header);
-
-#if (!ACPI_CHECKSUM_ABORT)
-		if (ACPI_FAILURE (status)) {
-			/* Ignore the error if configuration says so */
-
-			status = AE_OK;
-		}
-#endif
-	}
 
 	return_ACPI_STATUS (status);
 }
diff -Nru a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/acpi/tables/tbrsdt.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,304 @@
+/******************************************************************************
+ *
+ * Module Name: tbrsdt - ACPI RSDT table utilities
+ *              $Revision: 1 $
+ *
+ *****************************************************************************/
+
+/*
+ *  Copyright (C) 2000 - 2002, R. Byron Moore
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "acpi.h"
+#include "actables.h"
+
+
+#define _COMPONENT          ACPI_TABLES
+	 ACPI_MODULE_NAME    ("tbrsdt")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_tb_verify_rsdp
+ *
+ * PARAMETERS:  Address         - RSDP (Pointer to RSDT)
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_verify_rsdp (
+	ACPI_POINTER            *address)
+{
+	acpi_table_desc         table_info;
+	acpi_status             status;
+	RSDP_DESCRIPTOR         *rsdp;
+
+
+	ACPI_FUNCTION_TRACE ("Tb_verify_rsdp");
+
+
+	switch (address->pointer_type) {
+	case ACPI_LOGICAL_POINTER:
+
+		rsdp = address->pointer.logical;
+		break;
+
+	case ACPI_PHYSICAL_POINTER:
+		/*
+		 * Obtain access to the RSDP structure
+		 */
+		status = acpi_os_map_memory (address->pointer.physical, sizeof (RSDP_DESCRIPTOR),
+				  (void **) &rsdp);
+		if (ACPI_FAILURE (status)) {
+			return_ACPI_STATUS (status);
+		}
+		break;
+
+	default:
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
+	}
+
+	/*
+	 *  The signature and checksum must both be correct
+	 */
+	if (ACPI_STRNCMP ((NATIVE_CHAR *) rsdp, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) {
+		/* Nope, BAD Signature */
+
+		status = AE_BAD_SIGNATURE;
+		goto cleanup;
+	}
+
+	/* Check the standard checksum */
+
+	if (acpi_tb_checksum (rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
+		status = AE_BAD_CHECKSUM;
+		goto cleanup;
+	}
+
+	/* Check extended checksum if table version >= 2 */
+
+	if (rsdp->revision >= 2) {
+		if (acpi_tb_checksum (rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0) {
+			status = AE_BAD_CHECKSUM;
+			goto cleanup;
+		}
+	}
+
+	/* The RSDP supplied is OK */
+
+	table_info.pointer     = ACPI_CAST_PTR (acpi_table_header, rsdp);
+	table_info.length      = sizeof (RSDP_DESCRIPTOR);
+	table_info.allocation  = ACPI_MEM_MAPPED;
+	table_info.base_pointer = rsdp;
+
+	/* Save the table pointers and allocation info */
+
+	status = acpi_tb_init_table_descriptor (ACPI_TABLE_RSDP, &table_info);
+	if (ACPI_FAILURE (status)) {
+		goto cleanup;
+	}
+
+	/* Save the RSDP in a global for easy access */
+
+	acpi_gbl_RSDP = ACPI_CAST_PTR (RSDP_DESCRIPTOR, table_info.pointer);
+	return_ACPI_STATUS (status);
+
+
+	/* Error exit */
+cleanup:
+
+	if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) {
+		acpi_os_unmap_memory (rsdp, sizeof (RSDP_DESCRIPTOR));
+	}
+	return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_tb_get_rsdt_address
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      RSDT physical address
+ *
+ * DESCRIPTION: Extract the address of the RSDT or XSDT, depending on the
+ *              version of the RSDP
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_get_rsdt_address (
+	ACPI_POINTER            *out_address)
+{
+
+	ACPI_FUNCTION_ENTRY ();
+
+
+	out_address->pointer_type = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
+
+	/*
+	 * For RSDP revision 0 or 1, we use the RSDT.
+	 * For RSDP revision 2 (and above), we use the XSDT
+	 */
+	if (acpi_gbl_RSDP->revision < 2) {
+		out_address->pointer.value = acpi_gbl_RSDP->rsdt_physical_address;
+	}
+	else {
+		out_address->pointer.value = ACPI_GET_ADDRESS (acpi_gbl_RSDP->xsdt_physical_address);
+	}
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_tb_validate_rsdt
+ *
+ * PARAMETERS:  Table_ptr       - Addressable pointer to the RSDT.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Validate signature for the RSDT or XSDT
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_validate_rsdt (
+	acpi_table_header       *table_ptr)
+{
+	int                     no_match;
+
+
+	ACPI_FUNCTION_NAME ("Tb_validate_rsdt");
+
+
+	/*
+	 * For RSDP revision 0 or 1, we use the RSDT.
+	 * For RSDP revision 2 and above, we use the XSDT
+	 */
+	if (acpi_gbl_RSDP->revision < 2) {
+		no_match = ACPI_STRNCMP ((char *) table_ptr, RSDT_SIG,
+				  sizeof (RSDT_SIG) -1);
+	}
+	else {
+		no_match = ACPI_STRNCMP ((char *) table_ptr, XSDT_SIG,
+				  sizeof (XSDT_SIG) -1);
+	}
+
+	if (no_match) {
+		/* Invalid RSDT or XSDT signature */
+
+		ACPI_REPORT_ERROR (("Invalid signature where RSDP indicates RSDT/XSDT should be located\n"));
+
+		ACPI_DUMP_BUFFER (acpi_gbl_RSDP, 20);
+
+		ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR,
+			"RSDT/XSDT signature at %X (%p) is invalid\n",
+			acpi_gbl_RSDP->rsdt_physical_address,
+			(void *) (NATIVE_UINT) acpi_gbl_RSDP->rsdt_physical_address));
+
+		return (AE_BAD_SIGNATURE);
+	}
+
+	return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_tb_get_table_rsdt
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_table_rsdt (
+	void)
+{
+	acpi_table_desc         table_info;
+	acpi_status             status;
+	ACPI_POINTER            address;
+
+
+	ACPI_FUNCTION_TRACE ("Tb_get_table_rsdt");
+
+
+	/* Get the RSDT/XSDT via the RSDP */
+
+	acpi_tb_get_rsdt_address (&address);
+
+	status = acpi_tb_get_table (&address, &table_info);
+	if (ACPI_FAILURE (status)) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not get the RSDT/XSDT, %s\n",
+			acpi_format_exception (status)));
+		return_ACPI_STATUS (status);
+	}
+
+	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+		"RSDP located at %p, points to RSDT physical=%8.8X%8.8X \n",
+		acpi_gbl_RSDP,
+		ACPI_HIDWORD (address.pointer.value),
+		ACPI_LODWORD (address.pointer.value)));
+
+	/* Check the RSDT or XSDT signature */
+
+	status = acpi_tb_validate_rsdt (table_info.pointer);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	/*
+	 * Valid RSDT signature, verify the checksum.  If it fails, just
+	 * print a warning and ignore it.
+	 */
+	status = acpi_tb_verify_table_checksum (table_info.pointer);
+
+	/* Get the number of tables defined in the RSDT or XSDT */
+
+	acpi_gbl_rsdt_table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, table_info.pointer);
+
+	/* Convert and/or copy to an XSDT structure */
+
+	status = acpi_tb_convert_to_xsdt (&table_info);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	/* Save the table pointers and allocation info */
+
+	status = acpi_tb_init_table_descriptor (ACPI_TABLE_XSDT, &table_info);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	acpi_gbl_XSDT = (xsdt_descriptor *) table_info.pointer;
+
+	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT));
+	return_ACPI_STATUS (status);
+}
+
+
diff -Nru a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
--- a/drivers/acpi/tables/tbutils.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/tables/tbutils.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbutils - Table manipulation utilities
- *              $Revision: 54 $
+ *              $Revision: 55 $
  *
  *****************************************************************************/
 
@@ -121,7 +121,8 @@
 			"Table signature at %p [%p] has invalid characters\n",
 			table_header, &signature));
 
-		ACPI_REPORT_WARNING (("Invalid table signature found: [%4.4s]\n", (char *) &signature));
+		ACPI_REPORT_WARNING (("Invalid table signature found: [%4.4s]\n",
+			(char *) &signature));
 		ACPI_DUMP_BUFFER (table_header, sizeof (acpi_table_header));
 		return (AE_BAD_SIGNATURE);
 	}
@@ -133,97 +134,13 @@
 			"Invalid length in table header %p name %4.4s\n",
 			table_header, (char *) &signature));
 
-		ACPI_REPORT_WARNING (("Invalid table header length (0x%X) found\n", table_header->length));
+		ACPI_REPORT_WARNING (("Invalid table header length (0x%X) found\n",
+			table_header->length));
 		ACPI_DUMP_BUFFER (table_header, sizeof (acpi_table_header));
 		return (AE_BAD_HEADER);
 	}
 
 	return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_tb_map_acpi_table
- *
- * PARAMETERS:  Physical_address        - Physical address of table to map
- *              *Size                   - Size of the table.  If zero, the size
- *                                        from the table header is used.
- *                                        Actual size is returned here.
- *              **Logical_address       - Logical address of mapped table
- *
- * RETURN:      Logical address of the mapped table.
- *
- * DESCRIPTION: Maps the physical address of table into a logical address
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_map_acpi_table (
-	ACPI_PHYSICAL_ADDRESS   physical_address,
-	ACPI_SIZE               *size,
-	acpi_table_header       **logical_address)
-{
-	acpi_table_header       *table;
-	ACPI_SIZE               table_size = *size;
-	acpi_status             status = AE_OK;
-
-
-	ACPI_FUNCTION_NAME ("Tb_map_acpi_table");
-
-
-	/* If size is zero, look at the table header to get the actual size */
-
-	if ((*size) == 0) {
-		/* Get the table header so we can extract the table length */
-
-		status = acpi_os_map_memory (physical_address, sizeof (acpi_table_header),
-				  (void **) &table);
-		if (ACPI_FAILURE (status)) {
-			return (status);
-		}
-
-		/* Extract the full table length before we delete the mapping */
-
-		table_size = (ACPI_SIZE) table->length;
-
-#if 0
-/* We don't want to validate the header here.  */
-		/*
-		 * Validate the header and delete the mapping.
-		 * We will create a mapping for the full table below.
-		 */
-		status = acpi_tb_validate_table_header (table);
-#endif
-
-		/* Always unmap the memory for the header */
-
-		acpi_os_unmap_memory (table, sizeof (acpi_table_header));
-
-#if 0
-		/* Exit if header invalid */
-
-		if (ACPI_FAILURE (status)) {
-			return (status);
-		}
-#endif
-	}
-
-	/* Map the physical memory for the correct length */
-
-	status = acpi_os_map_memory (physical_address, table_size,
-			  (void **) &table);
-	if (ACPI_FAILURE (status)) {
-		return (status);
-	}
-
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
-		"Mapped memory for ACPI table, length=%d(%X) at %p\n",
-		table_size, table_size, table));
-
-	*size = table_size;
-	*logical_address = table;
-	return (status);
 }
 
 
diff -Nru a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
--- a/drivers/acpi/tables/tbxface.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/tables/tbxface.c	Tue Jul 16 16:49:43 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: tbxface - Public interfaces to the ACPI subsystem
  *                         ACPI table oriented interfaces
- *              $Revision: 57 $
+ *              $Revision: 58 $
  *
  *****************************************************************************/
 
@@ -52,7 +52,6 @@
 {
 	ACPI_POINTER            rsdp_address;
 	acpi_status             status;
-	u32                     number_of_tables = 0;
 
 
 	ACPI_FUNCTION_TRACE ("Acpi_load_tables");
@@ -81,16 +80,16 @@
 
 	/* Get the RSDT via the RSDP */
 
-	status = acpi_tb_get_table_rsdt (&number_of_tables);
+	status = acpi_tb_get_table_rsdt ();
 	if (ACPI_FAILURE (status)) {
 		ACPI_REPORT_ERROR (("Acpi_load_tables: Could not load RSDT: %s\n",
 				  acpi_format_exception (status)));
 		goto error_exit;
 	}
 
-	/* Now get the rest of the tables */
+	/* Now get the tables needed by this subsystem (FADT, DSDT, etc.) */
 
-	status = acpi_tb_get_all_tables (number_of_tables);
+	status = acpi_tb_get_required_tables ();
 	if (ACPI_FAILURE (status)) {
 		ACPI_REPORT_ERROR (("Acpi_load_tables: Error getting required tables (DSDT/FADT/FACS): %s\n",
 				  acpi_format_exception (status)));
@@ -154,10 +153,10 @@
 
 	/* Copy the table to a local buffer */
 
-	address.pointer_type    = ACPI_LOGICAL_POINTER;
+	address.pointer_type    = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
 	address.pointer.logical = table_ptr;
 
-	status = acpi_tb_get_table (&address, &table_info);
+	status = acpi_tb_get_table_body (&address, table_ptr, &table_info);
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
@@ -166,7 +165,7 @@
 
 	status = acpi_tb_install_table (&table_info);
 	if (ACPI_FAILURE (status)) {
-		/* Free table allocated by Acpi_tb_get_table */
+		/* Free table allocated by Acpi_tb_get_table_body */
 
 		acpi_tb_delete_single_table (&table_info);
 		return_ACPI_STATUS (status);
diff -Nru a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
--- a/drivers/acpi/tables/tbxfroot.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/acpi/tables/tbxfroot.c	Tue Jul 16 16:49:43 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbxfroot - Find the root ACPI table (RSDT)
- *              $Revision: 63 $
+ *              $Revision: 64 $
  *
  *****************************************************************************/
 
@@ -63,9 +63,9 @@
 
 	/* Validate string lengths */
 
-	if ((ACPI_STRLEN (signature)  > 4) ||
-		(ACPI_STRLEN (oem_id)     > 6) ||
-		(ACPI_STRLEN (oem_table_id) > 8)) {
+	if ((ACPI_STRLEN (signature)  > ACPI_NAME_SIZE) ||
+		(ACPI_STRLEN (oem_id)     > sizeof (table->oem_id)) ||
+		(ACPI_STRLEN (oem_table_id) > sizeof (table->oem_table_id))) {
 		return_ACPI_STATUS (AE_AML_STRING_LIMIT);
 	}
 
@@ -96,7 +96,7 @@
  * PARAMETERS:  Signature       - Any ACPI table signature
  *              Instance        - the non zero instance of the table, allows
  *                                support for multiple tables of the same type
- *              Flags           - 0: Physical/Virtual support
+ *              Flags           - Physical/Virtual support
  *              Ret_buffer      - pointer to a structure containing a buffer to
  *                                receive the table
  *
@@ -120,11 +120,10 @@
 {
 	ACPI_POINTER            rsdp_address;
 	ACPI_POINTER            address;
-	acpi_table_header       *rsdt_ptr = NULL;
-	acpi_table_header       *table_ptr;
 	acpi_status             status;
-	ACPI_SIZE               rsdt_size = 0;
-	ACPI_SIZE               table_size;
+	acpi_table_header       header;
+	acpi_table_desc         table_info;
+	acpi_table_desc         rsdt_info;
 	u32                     table_count;
 	u32                     i;
 	u32                     j;
@@ -147,6 +146,8 @@
 		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
 
+	rsdt_info.pointer = NULL;
+
 	if (!acpi_gbl_RSDP) {
 		/* Get the RSDP */
 
@@ -175,15 +176,13 @@
 		if (ACPI_STRNCMP ((NATIVE_CHAR *) acpi_gbl_RSDP, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) {
 			/* Nope, BAD Signature */
 
-			status = AE_BAD_SIGNATURE;
-			goto cleanup;
+			return_ACPI_STATUS (AE_BAD_SIGNATURE);
 		}
 
 		if (acpi_tb_checksum (acpi_gbl_RSDP, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
 			/* Nope, BAD Checksum */
 
-			status = AE_BAD_CHECKSUM;
-			goto cleanup;
+			return_ACPI_STATUS (AE_BAD_CHECKSUM);
 		}
 	}
 
@@ -197,64 +196,66 @@
 		ACPI_HIDWORD (address.pointer.value),
 		ACPI_LODWORD (address.pointer.value)));
 
-	status = acpi_tb_get_table_pointer (&address, flags, &rsdt_size, &rsdt_ptr);
+	/* Insert Processor_mode flags */
+
+	address.pointer_type |= flags;
+
+	status = acpi_tb_get_table (&address, &rsdt_info);
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
 
-	status = acpi_tb_validate_rsdt (rsdt_ptr);
+	status = acpi_tb_validate_rsdt (rsdt_info.pointer);
 	if (ACPI_FAILURE (status)) {
 		goto cleanup;
 	}
 
 	/* Get the number of table pointers within the RSDT */
 
-	table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, rsdt_ptr);
+	table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, rsdt_info.pointer);
 
+	address.pointer_type = acpi_gbl_table_flags | flags;
 
 	/*
 	 * Search the RSDT/XSDT for the correct instance of the
 	 * requested table
 	 */
 	for (i = 0, j = 0; i < table_count; i++) {
-		/* Get the next table pointer */
+		/* Get the next table pointer, handle RSDT vs. XSDT */
 
-		address.pointer_type = acpi_gbl_table_flags;
 		if (acpi_gbl_RSDP->revision < 2) {
-			address.pointer.value = ((RSDT_DESCRIPTOR *) rsdt_ptr)->table_offset_entry[i];
+			address.pointer.value = ((RSDT_DESCRIPTOR *) rsdt_info.pointer)->table_offset_entry[i];
 		}
 		else {
 			address.pointer.value = ACPI_GET_ADDRESS (
-				((xsdt_descriptor *) rsdt_ptr)->table_offset_entry[i]);
+				((xsdt_descriptor *) rsdt_info.pointer)->table_offset_entry[i]);
 		}
 
-		/* Get addressibility if necessary */
+		/* Get the table header */
 
-		status = acpi_tb_get_table_pointer (&address, flags, &table_size, &table_ptr);
+		status = acpi_tb_get_table_header (&address, &header);
 		if (ACPI_FAILURE (status)) {
 			goto cleanup;
 		}
 
 		/* Compare table signatures and table instance */
 
-		if (!ACPI_STRNCMP ((char *) table_ptr, signature, ACPI_STRLEN (signature))) {
+		if (!ACPI_STRNCMP (header.signature, signature, ACPI_NAME_SIZE)) {
 			/* An instance of the table was found */
 
 			j++;
 			if (j >= instance) {
-				/* Found the correct instance */
+				/* Found the correct instance, get the entire table */
 
-				*table_pointer = table_ptr;
+				status = acpi_tb_get_table_body (&address, &header, &table_info);
+				if (ACPI_FAILURE (status)) {
+					goto cleanup;
+				}
+
+				*table_pointer = table_info.pointer;
 				goto cleanup;
 			}
 		}
-
-		/* Delete table mapping if using virtual addressing */
-
-		if ((table_size) &&
-			((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING)) {
-			acpi_os_unmap_memory (table_ptr, table_size);
-		}
 	}
 
 	/* Did not find the table */
@@ -263,9 +264,7 @@
 
 
 cleanup:
-	if (rsdt_size) {
-		acpi_os_unmap_memory (rsdt_ptr, rsdt_size);
-	}
+	acpi_os_unmap_memory (rsdt_info.pointer, (ACPI_SIZE) rsdt_info.pointer->length);
 	return_ACPI_STATUS (status);
 }
 
diff -Nru a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
--- a/drivers/acpi/thermal.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/thermal.c	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 39 $)
+ *  acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 40 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -231,7 +231,7 @@
 
 	arg0.integer.value = mode;
 
-	status = acpi_evaluate(handle, NULL, &arg_list, NULL);
+	status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
 	if (ACPI_FAILURE(status))
 		return_VALUE(-ENODEV);
 
diff -Nru a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/acpi/toshiba_acpi.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,465 @@
+/*
+ *  toshiba_acpi.c - Toshiba Laptop ACPI Extras
+ *
+ *
+ *  Copyright (C) 2002 John Belmonte
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ *  The devolpment page for this driver is located at
+ *  http://memebeam.org/toys/ToshibaAcpiDriver.
+ *
+ *  Credits:
+ *	Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
+ *		engineering the Windows drivers
+ *	Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
+ *
+ *
+ *  TODO
+ *	provide version info in proc
+ *	add Fn key status
+ *
+ */
+
+#define TOSHIBA_ACPI_VERSION "0.12"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/version.h>
+
+#define KERNEL24 (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
+
+#if KERNEL24
+#include <acpi.h>
+extern struct proc_dir_entry* bm_proc_root;
+#define acpi_root_dir bm_proc_root
+#else
+#include "acpi_drivers.h"
+#endif
+
+MODULE_AUTHOR("John Belmonte");
+MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
+MODULE_LICENSE("GPL");
+
+/* Toshiba ACPI method paths */
+#define METHOD_LCD_BRIGHTNESS	"\\_SB_.PCI0.VGA_.LCD_._BCM"
+#define METHOD_HCI		"\\_SB_.VALD.GHCI"
+#define METHOD_VIDEO_OUT	"\\_SB_.VALX.DSSX"
+
+/* Toshiba HCI interface definitions
+ *
+ * HCI is Toshiba's "Hardware Control Interface" which is supposed to
+ * be uniform across all their models.  Ideally we would just call
+ * dedicated ACPI methods instead of using this primitive interface.
+ * However the ACPI methods seem to be incomplete in some areas (for
+ * example they allow setting, but not reading, the LCD brightness value),
+ * so this is still useful.
+ */
+
+#define HCI_WORDS			6
+
+/* operations */
+#define HCI_SET				0xff00
+#define HCI_GET				0xfe00
+
+/* return codes */
+#define HCI_SUCCESS			0x0000
+#define HCI_FAILURE			0x1000
+#define HCI_NOT_SUPPORTED		0x8000
+
+/* registers */
+#define HCI_FAN				0x0004
+#define HCI_VIDEO_OUT			0x001c
+#define HCI_LCD_BRIGHTNESS		0x002a
+
+/* field definitions */
+#define HCI_LCD_BRIGHTNESS_BITS		3
+#define HCI_LCD_BRIGHTNESS_SHIFT	(16-HCI_LCD_BRIGHTNESS_BITS)
+#define HCI_LCD_BRIGHTNESS_LEVELS	(1 << HCI_LCD_BRIGHTNESS_BITS)
+#define HCI_VIDEO_OUT_LCD		0x1
+#define HCI_VIDEO_OUT_CRT		0x2
+
+/* utility
+ */
+
+static __inline__ void
+_set_bit(u32* word, u32 mask, int value)
+{
+	*word = (*word & ~mask) | (mask * value);
+}
+
+/* This is the common code at the end of every proc read handler.  I don't
+ * understand it yet.
+ */
+static int
+end_proc_read(const char* p, char* page, off_t off, int count,
+	char** start, int* eof)
+{
+	int len = (p - page);
+	if (len <= off+count) *eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+
+/* acpi interface wrappers
+ */
+
+static int
+write_acpi_int(const char* methodName, int val)
+{
+	acpi_object_list params;
+	acpi_object in_objs[1];
+	acpi_status status;
+
+	params.count = sizeof(in_objs)/sizeof(in_objs[0]);
+	params.pointer = in_objs;
+	in_objs[0].type = ACPI_TYPE_INTEGER;
+	in_objs[0].integer.value = val;
+
+	status = acpi_evaluate_object(0, (char*)methodName, &params, 0);
+	return (status == AE_OK);
+}
+
+#if 0
+static int
+read_acpi_int(const char* methodName, int* pVal)
+{
+	acpi_buffer results;
+	acpi_object out_objs[1];
+	acpi_status status;
+
+	results.length = sizeof(out_objs);
+	results.pointer = out_objs;
+
+	status = acpi_evaluate_object(0, (char*)methodName, 0, &results);
+	*pVal = out_objs[0].integer.value;
+
+	return (status == AE_OK) && (out_objs[0].type == ACPI_TYPE_INTEGER);
+}
+#endif
+
+/* Perform a raw HCI call.  Here we don't care about input or output buffer
+ * format.
+ */
+static acpi_status
+hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
+{
+	acpi_object_list params;
+	acpi_object in_objs[HCI_WORDS];
+	acpi_buffer results;
+	acpi_object out_objs[HCI_WORDS+1];
+	acpi_status status;
+	int i;
+
+	params.count = HCI_WORDS;
+	params.pointer = in_objs;
+	for (i = 0; i < HCI_WORDS; ++i) {
+		in_objs[i].type = ACPI_TYPE_INTEGER;
+		in_objs[i].integer.value = in[i];
+		/*printk("%04x ", in[i]);*/
+	}
+	/*printk("\n");*/
+
+	results.length = sizeof(out_objs);
+	results.pointer = out_objs;
+
+	status = acpi_evaluate_object(0, METHOD_HCI, &params,
+		&results);
+	if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) {
+		for (i = 0; i < out_objs->package.count; ++i) {
+			out[i] = out_objs->package.elements[i].integer.value;
+			/*printk("%04x ", out[i]);*/
+		}
+		/*printk("\n");*/
+	}
+
+	return status;
+}
+
+/* common hci tasks (get or set one value)
+ *
+ * In addition to the ACPI status, the HCI system returns a result which
+ * may be useful (such as "not supported").
+ */
+
+static acpi_status
+hci_write1(u32 reg, u32 in1, u32* result)
+{
+	u32 in[HCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
+	u32 out[HCI_WORDS];
+	acpi_status status = hci_raw(in, out);
+	*result = (status == AE_OK) ? out[0] : HCI_FAILURE;
+	return status;
+}
+
+static acpi_status
+hci_read1(u32 reg, u32* out1, u32* result)
+{
+	u32 in[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
+	u32 out[HCI_WORDS];
+	acpi_status status = hci_raw(in, out);
+	*out1 = out[2];
+	*result = (status == AE_OK) ? out[0] : HCI_FAILURE;
+	return status;
+}
+
+#define PROC_TOSHIBA		"toshiba"
+#define PROC_LCD		"lcd"
+#define PROC_VIDEO		"video"
+#define PROC_FAN		"fan"
+
+static struct proc_dir_entry*	toshiba_proc_dir = NULL;
+static int			force_fan;
+
+/* proc file handlers
+ *
+ * WARNING: The write handlers are using sscanf on non-zero-terminated
+ * buffers.  This may result in memory reads past the buffer bounds.
+ */
+
+static int
+proc_read_lcd(char* page, char** start, off_t off, int count, int* eof,
+	void* context)
+{
+	char* p = page;
+	u32 hci_result;
+	u32 value;
+
+	if (off != 0) goto end;
+
+	hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result);
+	if (hci_result == HCI_SUCCESS) {
+		value = value >> HCI_LCD_BRIGHTNESS_SHIFT;
+		p += sprintf(p, "brightness:              %d\n", value);
+		p += sprintf(p, "brightness_levels:       %d\n",
+			HCI_LCD_BRIGHTNESS_LEVELS);
+	} else {
+		p += sprintf(p, "ERROR\n");
+		goto end;
+	}
+
+end:
+	return end_proc_read(p, page, off, count, start, eof);
+}
+
+static int
+proc_write_lcd(struct file* file, const char* buffer, unsigned long count,
+	void* data)
+{
+	int value;
+	/*int byte_count;*/
+	u32 hci_result;
+
+	/* ISSUE: %i doesn't work with hex values as advertised */
+	if (sscanf(buffer, " brightness : %i", &value) == 1 &&
+			value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
+		value = value << HCI_LCD_BRIGHTNESS_SHIFT;
+		hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
+		if (hci_result != HCI_SUCCESS)
+			return -EFAULT;
+	} else {
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static int
+proc_read_video(char* page, char** start, off_t off, int count, int* eof,
+	void* context)
+{
+	char* p = page;
+	u32 hci_result;
+	u32 value;
+
+	if (off != 0) goto end;
+
+	hci_read1(HCI_VIDEO_OUT, &value, &hci_result);
+	if (hci_result == HCI_SUCCESS) {
+		int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
+		int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
+		p += sprintf(p, "lcd_out:                 %d\n", is_lcd);
+		p += sprintf(p, "crt_out:                 %d\n", is_crt);
+	} else {
+		p += sprintf(p, "ERROR\n");
+		goto end;
+	}
+
+end:
+	return end_proc_read(p, page, off, count, start, eof);
+}
+
+static int
+proc_write_video(struct file* file, const char* buffer, unsigned long count,
+	void* data)
+{
+	int value;
+	const char* buffer_end = buffer + count;
+	int lcd_out = -1;
+	int crt_out = -1;
+	u32 hci_result;
+	int video_out;
+
+	/* scan expression.  Multiple expressions may be delimited with ; */
+	do {
+		if (sscanf(buffer, " lcd_out : %i", &value) == 1)
+			lcd_out = value & 1;
+		else if (sscanf(buffer, " crt_out : %i", &value) == 1)
+			crt_out = value & 1;
+		/* advance to one character past the next ; */
+		do ++buffer;
+		while ((buffer < buffer_end) && (*(buffer-1) != ';'));
+	} while (buffer < buffer_end);
+
+	hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result);
+	if (hci_result == HCI_SUCCESS) {
+		int new_video_out = video_out;
+		if (lcd_out != -1)
+			_set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
+		if (crt_out != -1)
+			_set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
+		/* To avoid unnecessary video disruption, only write the new
+		 * video setting if something changed. */
+		if (new_video_out != video_out)
+			write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
+	}
+
+	return count;
+}
+
+static int
+proc_read_fan(char* page, char** start, off_t off, int count, int* eof,
+	void* context)
+{
+	char* p = page;
+	u32 hci_result;
+	u32 value;
+
+	if (off != 0) goto end;
+
+	hci_read1(HCI_FAN, &value, &hci_result);
+	if (hci_result == HCI_SUCCESS) {
+		p += sprintf(p, "running:                 %d\n", (value > 0));
+		p += sprintf(p, "force_on:                %d\n", force_fan);
+	} else {
+		p += sprintf(p, "ERROR\n");
+		goto end;
+	}
+
+end:
+	return end_proc_read(p, page, off, count, start, eof);
+}
+
+static int
+proc_write_fan(struct file* file, const char* buffer, unsigned long count,
+	void* data)
+{
+	int value;
+	u32 hci_result;
+
+	if (sscanf(buffer, " force_on : %i", &value) == 1 &&
+			value >= 0 && value <= 1) {
+		hci_write1(HCI_FAN, value, &hci_result);
+		if (hci_result != HCI_SUCCESS)
+			return -EFAULT;
+		else
+			force_fan = value;
+	} else {
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+/* proc and module init
+ */
+
+static acpi_status
+add_device(void)
+{
+	struct proc_dir_entry* proc;
+
+	proc = create_proc_read_entry(PROC_LCD, S_IFREG | S_IRUGO | S_IWUSR,
+		toshiba_proc_dir, proc_read_lcd, 0);
+	if (proc) proc->write_proc = proc_write_lcd;
+
+	proc = create_proc_read_entry(PROC_VIDEO, S_IFREG | S_IRUGO | S_IWUSR,
+		toshiba_proc_dir, proc_read_video, 0);
+	if (proc) proc->write_proc = proc_write_video;
+
+	proc = create_proc_read_entry(PROC_FAN, S_IFREG | S_IRUGO | S_IWUSR,
+		toshiba_proc_dir, proc_read_fan, 0);
+	if (proc) proc->write_proc = proc_write_fan;
+
+	return(AE_OK);
+}
+
+static acpi_status
+remove_device(void)
+{
+	remove_proc_entry(PROC_LCD, toshiba_proc_dir);
+	remove_proc_entry(PROC_VIDEO, toshiba_proc_dir);
+	remove_proc_entry(PROC_FAN, toshiba_proc_dir);
+	return(AE_OK);
+}
+
+static int __init
+toshiba_acpi_init(void)
+{
+	acpi_status status = AE_OK;
+	int value;
+	u32 hci_result;
+
+	/* simple device detection: try reading an HCI register */
+	hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result);
+	if (hci_result != HCI_SUCCESS)
+		return -ENODEV;
+
+	printk("Toshiba Laptop ACPI Extras version %s\n", TOSHIBA_ACPI_VERSION);
+
+	force_fan = 0;
+
+	toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
+	if (!toshiba_proc_dir) {
+		status = AE_ERROR;
+	} else {
+		status = add_device();
+		if (ACPI_FAILURE(status))
+			remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+	}
+
+	return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
+}
+
+static void __exit
+toshiba_acpi_exit(void)
+{
+	remove_device();
+
+	if (toshiba_proc_dir)
+		remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+
+	return;
+}
+
+module_init(toshiba_acpi_init);
+module_exit(toshiba_acpi_exit);
diff -Nru a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
--- a/drivers/acpi/utilities/utcopy.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/utilities/utcopy.c	Tue Jul 16 16:49:42 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utcopy - Internal to external object translation utilities
- *              $Revision: 101 $
+ *              $Revision: 103 $
  *
  *****************************************************************************/
 
@@ -286,21 +286,23 @@
 	/*
 	 * Free space begins right after the first package
 	 */
-	info.length      = 0;
+	info.length      = ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object));
+	info.free_space  = buffer + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object));
 	info.object_space = 0;
 	info.num_packages = 1;
-	info.free_space  = buffer + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object));
 
-	external_object->type              = ACPI_GET_OBJECT_TYPE (internal_object);
-	external_object->package.count     = internal_object->package.count;
-	external_object->package.elements  = ACPI_CAST_PTR (acpi_object, info.free_space);
+	external_object->type            = ACPI_GET_OBJECT_TYPE (internal_object);
+	external_object->package.count   = internal_object->package.count;
+	external_object->package.elements = ACPI_CAST_PTR (acpi_object, info.free_space);
 
 	/*
-	 * Build an array of ACPI_OBJECTS in the buffer
+	 * Leave room for an array of ACPI_OBJECTS in the buffer
 	 * and move the free space past it
 	 */
+	info.length    += (ACPI_SIZE) external_object->package.count *
+			 ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object));
 	info.free_space += external_object->package.count *
-			  ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object));
+			 ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (acpi_object));
 
 	status = acpi_ut_walk_package_tree (internal_object, external_object,
 			 acpi_ut_copy_ielement_to_eelement, &info);
@@ -516,7 +518,6 @@
 	external_object->type              = ACPI_GET_OBJECT_TYPE (internal_object);
 	external_object->package.count     = internal_object->package.count;
 	external_object->package.elements  = (acpi_object *)free_space;
-
 
 	/*
 	 * Build an array of ACPI_OBJECTS in the buffer
diff -Nru a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
--- a/drivers/acpi/utilities/utglobal.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/utilities/utglobal.c	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utglobal - Global variables for the ACPI subsystem
- *              $Revision: 163 $
+ *              $Revision: 164 $
  *
  *****************************************************************************/
 
@@ -286,15 +286,15 @@
 
 ACPI_TABLE_SUPPORT          acpi_gbl_acpi_table_data[NUM_ACPI_TABLES] =
 {
-	/***********    Name,   Signature, Global typed pointer     Signature size,      How many allowed?,    Contains valid AML? */
+	/***********    Name,   Signature, Global typed pointer     Signature size,      Type                  How many allowed?,    Contains valid AML? */
 
-	/* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL,                    sizeof (RSDP_SIG)-1, ACPI_TABLE_SINGLE},
-	/* DSDT 1 */ {DSDT_SIG,  DSDT_SIG, (void **) &acpi_gbl_DSDT, sizeof (DSDT_SIG)-1, ACPI_TABLE_SINGLE  | ACPI_TABLE_EXECUTABLE},
-	/* FADT 2 */ {FADT_SIG,  FADT_SIG, (void **) &acpi_gbl_FADT, sizeof (FADT_SIG)-1, ACPI_TABLE_SINGLE},
-	/* FACS 3 */ {FACS_SIG,  FACS_SIG, (void **) &acpi_gbl_FACS, sizeof (FACS_SIG)-1, ACPI_TABLE_SINGLE},
-	/* PSDT 4 */ {PSDT_SIG,  PSDT_SIG, NULL,                    sizeof (PSDT_SIG)-1, ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE},
-	/* SSDT 5 */ {SSDT_SIG,  SSDT_SIG, NULL,                    sizeof (SSDT_SIG)-1, ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE},
-	/* XSDT 6 */ {XSDT_SIG,  XSDT_SIG, NULL,                    sizeof (RSDT_SIG)-1, ACPI_TABLE_SINGLE},
+	/* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL,                    sizeof (RSDP_SIG)-1, ACPI_TABLE_ROOT     | ACPI_TABLE_SINGLE},
+	/* DSDT 1 */ {DSDT_SIG,  DSDT_SIG, (void **) &acpi_gbl_DSDT, sizeof (DSDT_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE  | ACPI_TABLE_EXECUTABLE},
+	/* FADT 2 */ {FADT_SIG,  FADT_SIG, (void **) &acpi_gbl_FADT, sizeof (FADT_SIG)-1, ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE},
+	/* FACS 3 */ {FACS_SIG,  FACS_SIG, (void **) &acpi_gbl_FACS, sizeof (FACS_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE},
+	/* PSDT 4 */ {PSDT_SIG,  PSDT_SIG, NULL,                    sizeof (PSDT_SIG)-1, ACPI_TABLE_PRIMARY  | ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE},
+	/* SSDT 5 */ {SSDT_SIG,  SSDT_SIG, NULL,                    sizeof (SSDT_SIG)-1, ACPI_TABLE_PRIMARY  | ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE},
+	/* XSDT 6 */ {XSDT_SIG,  XSDT_SIG, NULL,                    sizeof (RSDT_SIG)-1, ACPI_TABLE_ROOT     | ACPI_TABLE_SINGLE},
 };
 
 
diff -Nru a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
--- a/drivers/acpi/utilities/utxface.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/acpi/utilities/utxface.c	Tue Jul 16 16:49:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utxface - External interfaces for "global" ACPI functions
- *              $Revision: 96 $
+ *              $Revision: 97 $
  *
  *****************************************************************************/
 
@@ -191,6 +191,31 @@
 			return_ACPI_STATUS (status);
 		}
 	}
+
+	return_ACPI_STATUS (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_initialize_objects
+ *
+ * PARAMETERS:  Flags           - Init/enable Options
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Completes namespace initialization by initializing device
+ *              objects and executing AML code for Regions, buffers, etc.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_initialize_objects (
+	u32                     flags)
+{
+	acpi_status             status = AE_OK;
+
+
+	ACPI_FUNCTION_TRACE ("Acpi_initialize_objects");
 
 	/*
 	 * Initialize all device objects in the namespace
diff -Nru a/drivers/acpi/utils.c b/drivers/acpi/utils.c
--- a/drivers/acpi/utils.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/acpi/utils.c	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_utils.c - ACPI Utility Functions ($Revision: 7 $)
+ *  acpi_utils.c - ACPI Utility Functions ($Revision: 10 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -236,59 +236,6 @@
 
 
 acpi_status
-acpi_evaluate (
-	acpi_handle		handle,
-	acpi_string		pathname,
-	acpi_object_list	*arguments,
-	acpi_buffer		*buffer)
-{
-	acpi_status		status = AE_OK;
-
-	ACPI_FUNCTION_TRACE("acpi_evaluate");
-
-	/* If caller provided a buffer it must be unallocated/zero'd. */
-	if (buffer && (buffer->length != 0 || buffer->pointer))
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-
-	/*
-	 * Evalute object. The first attempt is just to get the size of the
-	 * object data (that is unless there's no return data); the second
-	 * gets the data.
-	 */
-	status = acpi_evaluate_object(handle, pathname, arguments, buffer);
-
-	if (ACPI_SUCCESS(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	else if (buffer && (status == AE_BUFFER_OVERFLOW)) {
-
-		/* Gotta allocate - CALLER MUST FREE! */
-		buffer->pointer = kmalloc(buffer->length, GFP_KERNEL);
-		if (!buffer->pointer) {
-			return_ACPI_STATUS(AE_NO_MEMORY);
-		}
-		memset(buffer->pointer, 0, buffer->length);
-
-		/* Re-evaluate - this time it should work. */
-		status = acpi_evaluate_object(handle, pathname, arguments,
-			buffer);
-	}
-
-	if (ACPI_FAILURE(status)) {
-		if (status != AE_NOT_FOUND)
-			acpi_util_eval_error(handle, pathname, status);
-		if (buffer && buffer->pointer) {
-			kfree(buffer->pointer);
-			buffer->length = 0;
-		}
-	}
-
-	return_ACPI_STATUS(status);
-}
-
-
-acpi_status
 acpi_evaluate_integer (
 	acpi_handle		handle,
 	acpi_string		pathname,
@@ -366,6 +313,8 @@
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%s]\n", *data));
 
+	acpi_os_free(buffer.pointer);
+
 	return_ACPI_STATUS(AE_OK);
 }
 #endif
@@ -381,7 +330,7 @@
 	acpi_status		status = AE_OK;
 	acpi_object		*package = NULL;
 	acpi_object		*element = NULL;
-	acpi_buffer		buffer = {0, NULL};
+	acpi_buffer		buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 	u32			i = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_evaluate_reference");
@@ -392,42 +341,53 @@
 
 	/* Evaluate object. */
 
-	status = acpi_evaluate(handle, pathname, arguments, &buffer);
+	status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
 	if (ACPI_FAILURE(status))
 		goto end;
 
 	package = (acpi_object *) buffer.pointer;
 
-	if (!package || (package->type != ACPI_TYPE_PACKAGE)
-		|| (package->package.count == 0)) {
+	if ((buffer.length == 0) || !package) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"No return object (len %X ptr %p)\n", 
+			buffer.length, package));
+		status = AE_BAD_DATA;
+		acpi_util_eval_error(handle, pathname, status);
+		goto end;
+	}
+	if (package->type != ACPI_TYPE_PACKAGE) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Expecting a [Package], found type %X\n", 
+			package->type));
+		status = AE_BAD_DATA;
+		acpi_util_eval_error(handle, pathname, status);
+		goto end;
+	}
+	if (!package->package.count) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"[Package] has zero elements (%p)\n", 
+			package));
 		status = AE_BAD_DATA;
 		acpi_util_eval_error(handle, pathname, status);
 		goto end;
 	}
 
-	/* Allocate list - CALLER MUST FREE! */
-	list->count = package->package.count;
-	if (list->count > 10) {
+	if (package->package.count > ACPI_MAX_HANDLES) {
 		return AE_NO_MEMORY;
 	}
-	/* TBD: dynamically allocate */
-	/*
-	list->handles = kmalloc(sizeof(acpi_handle)*(list->count), GFP_KERNEL);
-	if (!list->handles) {
-		return_ACPI_STATUS(AE_NO_MEMORY);
-	}
-	memset(list->handles, 0, sizeof(acpi_handle)*(list->count));
-	*/
+	list->count = package->package.count;
 
-	/* Parse package data. */
+	/* Extract package data. */
 
 	for (i = 0; i < list->count; i++) {
 
 		element = &(package->package.elements[i]);
 
-		if (!element || (element->type != ACPI_TYPE_ANY)) {
+		if (element->type != ACPI_TYPE_ANY) {
 			status = AE_BAD_DATA;
-			ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid element in package (not a device reference)\n"));
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+				"Expecting a [Reference] package element, found type %X\n",
+				element->type));
 			acpi_util_eval_error(handle, pathname, status);
 			break;
 		}
@@ -435,7 +395,8 @@
 		/* Get the  acpi_handle. */
 
 		list->handles[i] = element->reference.handle;
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resolved reference [%s]->[%p]\n", element->string.pointer, list->handles[i]));
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found reference [%p]\n",
+			list->handles[i]));
 	}
 
 end:
@@ -444,7 +405,7 @@
 		//kfree(list->handles);
 	}
 
-	kfree(buffer.pointer);
+	acpi_os_free(buffer.pointer);
 
 	return_ACPI_STATUS(status);
 }
diff -Nru a/drivers/block/Config.in b/drivers/block/Config.in
--- a/drivers/block/Config.in	Tue Jul 16 16:49:42 2002
+++ b/drivers/block/Config.in	Tue Jul 16 16:49:42 2002
@@ -4,7 +4,7 @@
 mainmenu_option next_comment
 comment 'Block devices'
 
-tristate 'Normal PC floppy disk support' CONFIG_BLK_DEV_FD
+tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
 if [ "$CONFIG_AMIGA" = "y" ]; then
    tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
 fi
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/block/ll_rw_blk.c	Tue Jul 16 16:49:41 2002
@@ -1202,6 +1202,26 @@
 	return rq;
 }
 
+/*
+ * Non-locking blk_get_request variant, for special requests from drivers.
+ */
+struct request *__blk_get_request(request_queue_t *q, int rw)
+{
+	struct request *rq;
+
+	BUG_ON(rw != READ && rw != WRITE);
+
+	rq = get_request(q, rw);
+
+	if (rq) {
+		rq->flags = 0;
+		rq->buffer = NULL;
+		rq->bio = rq->biotail = NULL;
+		rq->waiting = NULL;
+	}
+	return rq;
+}
+
 void blk_put_request(struct request *rq)
 {
 	blkdev_release_request(rq);
@@ -1381,6 +1401,14 @@
 	spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
+/*
+ * Non-locking blk_attempt_remerge variant.
+ */
+void __blk_attempt_remerge(request_queue_t *q, struct request *rq)
+{
+	attempt_back_merge(q, rq);
+}
+
 static int __make_request(request_queue_t *q, struct bio *bio)
 {
 	struct request *req, *freereq = NULL;
@@ -2039,6 +2067,7 @@
 EXPORT_SYMBOL(blk_plug_device);
 EXPORT_SYMBOL(blk_remove_plug);
 EXPORT_SYMBOL(blk_attempt_remerge);
+EXPORT_SYMBOL(__blk_attempt_remerge);
 EXPORT_SYMBOL(blk_max_low_pfn);
 EXPORT_SYMBOL(blk_max_pfn);
 EXPORT_SYMBOL(blk_queue_max_sectors);
@@ -2055,6 +2084,7 @@
 EXPORT_SYMBOL(blk_phys_contig_segment);
 EXPORT_SYMBOL(blk_hw_contig_segment);
 EXPORT_SYMBOL(blk_get_request);
+EXPORT_SYMBOL(__blk_get_request);
 EXPORT_SYMBOL(blk_put_request);
 
 EXPORT_SYMBOL(blk_queue_prep_rq);
diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
--- a/drivers/bluetooth/hci_usb.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/bluetooth/hci_usb.c	Tue Jul 16 16:49:43 2002
@@ -176,7 +176,6 @@
         pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep);
 
         FILL_BULK_URB(urb, husb->udev, pipe, skb->data, size, hci_usb_rx_complete, skb);
-        urb->transfer_flags = USB_QUEUE_BULK;
 
 	skb_queue_tail(&husb->pending_q, skb);
 	err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -318,7 +317,7 @@
         
 	FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,
 	              hci_usb_tx_complete, skb);
-	urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET;
+	urb->transfer_flags = USB_ZERO_PACKET;
 
 	BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len);
 
diff -Nru a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
--- a/drivers/cdrom/aztcd.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/cdrom/aztcd.c	Tue Jul 16 16:49:43 2002
@@ -2083,12 +2083,12 @@
 				}
 				azt_state = AZT_S_IDLE;
 				while (current_valid())
-					end_request(0);
+					end_request(CURRENT, 0);
 				return;
 			}
 
 /*	  if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3");
-	  outb(0x01, DATA_PORT);          
+	  outb(0x01, DATA_PORT);
 	  PA_OK;
 	  STEN_LOW;
 */
@@ -2138,7 +2138,7 @@
 				}
 				azt_state = AZT_S_IDLE;
 				while (current_valid())
-					end_request(0);
+					end_request(CURRENT, 0);
 				return;
 			}
 
@@ -2236,7 +2236,7 @@
 						break;
 					}
 					if (current_valid())
-						end_request(0);
+						end_request(CURRENT, 0);
 					AztTries = 5;
 				}
 				azt_state = AZT_S_START;
diff -Nru a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
--- a/drivers/cdrom/sonycd535.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/cdrom/sonycd535.c	Tue Jul 16 16:49:42 2002
@@ -805,14 +805,8 @@
 	Byte cmd[2];
 
 	while (1) {
-		/*
-		 * The beginning here is stolen from the hard disk driver.  I hope
-		 * it's right.
-		 */
-		if (blk_queue_empty(QUEUE)) {
-			CLEAR_INTR;
+		if (blk_queue_empty(QUEUE))
 			return;
-		}
 
 		dev = minor(CURRENT->rq_dev);
 		block = CURRENT->sector;
@@ -828,7 +822,6 @@
 				 * If the block address is invalid or the request goes beyond the end of
 				 * the media, return an error.
 				 */
-				
 				if (sony_toc->lead_out_start_lba <= (block / 4)) {
 					end_request(CURRENT, 0);
 					return;
diff -Nru a/drivers/char/Config.help b/drivers/char/Config.help
--- a/drivers/char/Config.help	Tue Jul 16 16:49:42 2002
+++ b/drivers/char/Config.help	Tue Jul 16 16:49:42 2002
@@ -633,37 +633,6 @@
   The module will be called busmouse.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-CONFIG_MOUSE
-  This is for machines with a mouse which is neither a serial nor a
-  bus mouse. Examples are PS/2 mice (such as the track balls on some
-  laptops) and some digitizer pads. Most people have a regular serial
-  MouseSystem or Microsoft mouse (made by Logitech) that plugs into a
-  COM port (rectangular with 9 or 25 pins). These people say N here.
-  If you have something else, read the Busmouse-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. This HOWTO contains
-  information about all non-serial mice, not just bus mice.
-
-  If you have a laptop, you either have to check the documentation or
-  experiment a bit to find out whether the trackball is a serial mouse
-  or not; it's best to say Y here for you.
-
-  Note that the answer to this question won't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about non-serial mice. If unsure, say Y.
-
-CONFIG_LOGIBUSMOUSE
-  Logitech mouse connected to a proprietary interface card.  It's
-  generally a round connector with 9 pins. Note that the newer mice
-  made by Logitech don't use the Logitech protocol anymore; for those,
-  you don't need this option.  You want to read the Busmouse-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called busmouse.o.  If you are unsure, say N and read the
-  HOWTO nevertheless: it will tell you what you have.
-
 CONFIG_PSMOUSE
   The PS/2 mouse connects to a special mouse port that looks much like
   the keyboard port (small circular connector with 6 pins). This way,
@@ -682,64 +651,6 @@
   of the Linux mouse managing program gpm (available from
   <ftp://gnu.systemy.it/pub/gpm/>) solves this problem, or you can get
   the "mconv2" utility from <ftp://ibiblio.org/pub/Linux/system/mouse/>.
-
-CONFIG_82C710_MOUSE
-  This is a certain kind of PS/2 mouse used on the TI Travelmate. If
-  you are unsure, try first to say N here and come back if the mouse
-  doesn't work. Read the Busmouse-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-CONFIG_PC110_PAD
-  This drives the digitizer pad on the IBM PC110 palmtop.  It can turn
-  the digitizer pad into a PS/2 mouse emulation with tap gestures or
-  into an absolute pad.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called pc110pad.o.
-
-CONFIG_MS_BUSMOUSE
-  These animals (also called Inport mice) are connected to an
-  expansion board using a round connector with 9 pins. If this is what
-  you have, say Y and read the Busmouse-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you are unsure, say N and read the HOWTO nevertheless: it will
-  tell you what you have. Also be aware that several vendors talk
-  about 'Microsoft busmouse' and actually mean PS/2 busmouse -- so
-  count the pins on the connector.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called msbusmouse.o.
-
-CONFIG_ADBMOUSE
-  Say Y here if you have this type of bus mouse (4 pin connector) as
-  is common on Macintoshes.  You may want to read the Busmouse-HOWTO,
-  available from <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called adbmouse.o.
-
-CONFIG_ATIXL_BUSMOUSE
-  This is a rare type of busmouse that is connected to the back of an
-  ATI video card.  Say Y if you have one of those. Note however that
-  most mice by ATI are actually Microsoft busmice; you should say Y to
-  "Microsoft busmouse support" above if you have one of those.  Read
-  the Busmouse-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called atixlmouse.o.
-
-  If you are unsure, say N and read the HOWTO nevertheless: it will
-  tell you what you have.
 
 CONFIG_QIC02_TAPE
   If you have a non-SCSI tape drive like that, say Y. Or, if you want
diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in
--- a/drivers/char/Config.in	Tue Jul 16 16:49:41 2002
+++ b/drivers/char/Config.in	Tue Jul 16 16:49:41 2002
@@ -113,22 +113,8 @@
 
 mainmenu_option next_comment
 comment 'Mice'
-tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
-if [ "$CONFIG_BUSMOUSE" != "n" ]; then
-   dep_tristate '  ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE
-   dep_tristate '  Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE
-   dep_tristate '  Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE
-   if [ "$CONFIG_ADB" = "y" -a "$CONFIG_ADB_KEYBOARD" = "y" ]; then
-      dep_tristate '  Apple Desktop Bus mouse support (old driver)' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
-   fi
-fi
-
-tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE
-if [ "$CONFIG_MOUSE" != "n" ]; then
-   bool '  PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
-   tristate '  C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
-   tristate '  PC110 digitizer pad support' CONFIG_PC110_PAD
-fi
+   tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
+   bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
 endmenu
 
 tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
@@ -185,7 +171,9 @@
    tristate 'NetWinder flash support' CONFIG_NWFLASH
 fi
 
-dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI
+if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then
+   dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI
+fi
 tristate '/dev/nvram support' CONFIG_NVRAM
 tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
 if [ "$CONFIG_IA64" = "y" ]; then
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	Tue Jul 16 16:49:42 2002
+++ b/drivers/char/Makefile	Tue Jul 16 16:49:42 2002
@@ -155,8 +155,6 @@
 obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
 obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o
 
-obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
-obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o
 obj-$(CONFIG_PRINTER) += lp.o
 
 obj-$(CONFIG_BUSMOUSE) += busmouse.o
@@ -164,12 +162,7 @@
 obj-$(CONFIG_R3964) += n_r3964.o
 obj-$(CONFIG_APPLICOM) += applicom.o
 obj-$(CONFIG_SONYPI) += sonypi.o
-obj-$(CONFIG_MS_BUSMOUSE) += msbusmouse.o
-obj-$(CONFIG_82C710_MOUSE) += qpmouse.o
-obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o
 obj-$(CONFIG_ATARIMOUSE) += atarimouse.o
-obj-$(CONFIG_ADBMOUSE) += adbmouse.o
-obj-$(CONFIG_PC110_PAD) += pc110pad.o
 obj-$(CONFIG_RTC) += rtc.o
 obj-$(CONFIG_EFI_RTC) += efirtc.o
 ifeq ($(CONFIG_PPC),)
@@ -235,4 +228,4 @@
 	sed -e 's/^static *//' $@.tmp > $@
 	rm $@.tmp
 
-endif
\ No newline at end of file
+endif
diff -Nru a/drivers/char/adbmouse.c b/drivers/char/adbmouse.c
--- a/drivers/char/adbmouse.c	Tue Jul 16 16:49:42 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,209 +0,0 @@
-/*
- * Macintosh ADB Mouse driver for Linux
- *
- * 27 Oct 1997 Michael Schmitz
- * logitech fixes by anthony tong
- * further hacking by Paul Mackerras
- *
- * Apple mouse protocol according to:
- *
- * Device code shamelessly stolen from:
- */
-/*
- * Atari Mouse Driver for Linux
- * by Robert de Vries (robert@and.nl) 19Jul93
- *
- * 16 Nov 1994 Andreas Schwab
- * Compatibility with busmouse
- * Support for three button mouse (shamelessly stolen from MiNT)
- * third button wired to one of the joystick directions on joystick 1
- *
- * 1996/02/11 Andreas Schwab
- * Module support
- * Allow multiple open's
- *
- * Converted to use new generic busmouse code.  11 July 1998
- *   Russell King <rmk@arm.uk.linux.org>
- */
-
-#include <linux/module.h>
-
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/adb_mouse.h>
-
-#ifdef __powerpc__
-#include <asm/processor.h>
-#endif
-#if defined(__mc68000__) || defined(MODULE)
-#include <asm/setup.h>
-#endif
-
-#include "busmouse.h"
-
-static int msedev;
-static unsigned char adb_mouse_buttons[16];
-
-extern void (*adb_mouse_interrupt_hook)(unsigned char *, int);
-extern int adb_emulate_buttons;
-extern int adb_button2_keycode;
-extern int adb_button3_keycode;
-
-/*
- *    XXX: need to figure out what ADB mouse packets mean ... 
- *      This is the stuff stolen from the Atari driver ...
- */
-static void adb_mouse_interrupt(unsigned char *buf, int nb)
-{
-	int buttons, id;
-	char dx, dy;
-
-	/*
-	   Handler 1 -- 100cpi original Apple mouse protocol.
-	   Handler 2 -- 200cpi original Apple mouse protocol.
-
-	   For Apple's standard one-button mouse protocol the data array will
-	   contain the following values:
-
-		       BITS    COMMENTS
-	   data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
-	   data[1] = bxxx xxxx First button and x-axis motion.
-	   data[2] = byyy yyyy Second button and y-axis motion.
-
-	   Handler 4 -- Apple Extended mouse protocol.
-
-	   For Apple's 3-button mouse protocol the data array will contain the
-	   following values:
-
-		       BITS    COMMENTS
-	   data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
-	   data[1] = bxxx xxxx Left button and x-axis motion.
-	   data[2] = byyy yyyy Second button and y-axis motion.
-	   data[3] = byyy bxxx Third button and fourth button.  
-		   Y is additiona. high bits of y-axis motion.  
-		   X is additional high bits of x-axis motion.
-
-	   'buttons' here means 'button down' states!
-	   Button 1 (left)  : bit 2, busmouse button 3
-	   Button 2 (right) : bit 0, busmouse button 1
-	   Button 3 (middle): bit 1, busmouse button 2
-	 */
-
-	/* x/y and buttons swapped */
-
-	id = (buf[0] >> 4) & 0xf;
-
-	buttons = adb_mouse_buttons[id];
-
-	/* button 1 (left, bit 2) */
-	buttons = (buttons & 3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */
-
-	/* button 2 (middle) */
-	buttons = (buttons & 5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */
-
-	/* button 3 (right) present?
-	 *  on a logitech mouseman, the right and mid buttons sometimes behave
-	 *  strangely until they both have been pressed after booting. */
-	/* data valid only if extended mouse format ! */
-	if (nb >= 4)
-		buttons = (buttons & 6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
-
-	adb_mouse_buttons[id] = buttons;
-
-	/* a button is down if it is down on any mouse */
-	for (id = 0; id < 16; ++id)
-		buttons &= adb_mouse_buttons[id];
-
-	dx = ((buf[2] & 0x7f) < 64 ? (buf[2] & 0x7f) : (buf[2] & 0x7f) - 128);
-	dy = ((buf[1] & 0x7f) < 64 ? (buf[1] & 0x7f) : (buf[1] & 0x7f) - 128);
-	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
-
-	if (console_loglevel >= 8)
-		printk(" %X %X %X dx %d dy %d \n",
-		       buf[1], buf[2], buf[3], dx, dy);
-}
-
-static int release_mouse(struct inode *inode, struct file *file)
-{
-	adb_mouse_interrupt_hook = NULL;
-	/*
-	 *	FIXME?: adb_mouse_interrupt_hook may still be executing
-	 *	on another CPU.
-	 */
-	return 0;
-}
-
-static int open_mouse(struct inode *inode, struct file *file)
-{
-	adb_mouse_interrupt_hook = adb_mouse_interrupt;
-	return 0;
-}
-
-static struct busmouse adb_mouse =
-{
-	ADB_MOUSE_MINOR, "adbmouse", THIS_MODULE, open_mouse, release_mouse, 7
-};
-
-static int __init adb_mouse_init(void)
-{
-#ifdef __powerpc__
-	if ((_machine != _MACH_chrp) && (_machine != _MACH_Pmac))
-		return -ENODEV;
-#endif
-#ifdef __mc68000__
-	if (!MACH_IS_MAC)
-		return -ENODEV;
-#endif
-	/* all buttons up */
-	memset(adb_mouse_buttons, 7, sizeof(adb_mouse_buttons));
-
-	msedev = register_busmouse(&adb_mouse);
-	if (msedev < 0)
-		printk(KERN_WARNING "Unable to register ADB mouse driver.\n");
-	else
-		printk(KERN_INFO "Macintosh ADB mouse driver installed.\n");
-
-	return msedev < 0 ? msedev : 0;
-}
-
-#ifndef MODULE
-
-/*
- * XXX this function is misnamed.
- * It is called if the kernel is booted with the adb_buttons=xxx
- * option, which is about using ADB keyboard buttons to emulate
- * mouse buttons. -- paulus
- */
-static int __init adb_mouse_setup(char *str)
-{
-	int ints[4];
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-	if (ints[0] >= 1) {
-		adb_emulate_buttons = ints[1];
-		if (ints[0] >= 2)
-			adb_button2_keycode = ints[2];
-		if (ints[0] >= 3)
-			adb_button3_keycode = ints[3];
-	}
-	return 1;
-}
-
-__setup("adb_buttons=", adb_mouse_setup);
-
-#endif /* !MODULE */
-
-static void __exit adb_mouse_cleanup(void)
-{
-	unregister_busmouse(msedev);
-}
-
-module_init(adb_mouse_init);
-module_exit(adb_mouse_cleanup);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/amigamouse.c b/drivers/char/amigamouse.c
--- a/drivers/char/amigamouse.c	Tue Jul 16 16:49:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,213 +0,0 @@
-/*
- * Amiga Mouse Driver for Linux 68k by Michael Rausch
- * based upon:
- *
- * Logitech Bus Mouse Driver for Linux
- * by James Banks
- *
- * Mods by Matthew Dillon
- *   calls verify_area()
- *   tracks better when X is busy or paging
- *
- * Heavily modified by David Giller
- *   changed from queue- to counter- driven
- *   hacked out a (probably incorrect) mouse_poll
- *
- * Modified again by Nathan Laredo to interface with
- *   0.96c-pl1 IRQ handling changes (13JUL92)
- *   didn't bother touching poll code.
- *
- * Modified the poll() code blindly to conform to the VFS
- *   requirements. 92.07.14 - Linus. Somebody should test it out.
- *
- * Modified by Johan Myreen to make room for other mice (9AUG92)
- *   removed assignment chr_fops[10] = &mouse_fops; see mouse.c
- *   renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
- *   renamed this file mouse.c => busmouse.c
- *
- * Modified for use in the 1.3 kernels by Jes Sorensen.
- *
- * Moved the isr-allocation to the mouse_{open,close} calls, as there
- *   is no reason to service the mouse in the vertical blank isr if
- *   the mouse is not in use.             Jes Sorensen
- *
- * Converted to use new generic busmouse code.  5 Apr 1998
- *   Russell King <rmk@arm.uk.linux.org>
- */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/logibusmouse.h>
-
-#include <asm/setup.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-
-#include "busmouse.h"
-
-#if AMIGA_OLD_INT
-#define AMI_MSE_INT_ON()	mouseint_allowed = 1
-#define AMI_MSE_INT_OFF()	mouseint_allowed = 0
-static int mouseint_allowed;
-#endif
-
-static int msedev;
-
-static void mouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
-	static int lastx=0, lasty=0;
-	int dx, dy;
-	int nx, ny;
-	unsigned char buttons;
-
-	unsigned short joy0dat, potgor;
-
-#if AMIGA_OLD_INT
-	if(!mouseint_allowed)
-		return;
-	AMI_MSE_INT_OFF();
-#endif
-
-	/*
-	 *  This routine assumes, just like Kickstart, that the mouse
-	 *  has not moved more than 127 ticks since last VBL.
-	 */
-
-	joy0dat = custom.joy0dat;
-
-	nx = joy0dat & 0xff;
-	ny = joy0dat >> 8;
-
-	dx = nx - lastx;
-	if (dx < - 127)
-		dx = (256 + nx) - lastx;
-
-	if (dx > 127)
-		dx = (nx - 256) - lastx;
-
-	dy = ny - lasty;
-	if (dy < - 127)
-		dy = (256 + ny) - lasty;
-
-	if (dy > 127)
-		dy = (ny - 256) - lasty;
-
-	lastx = nx;
-	lasty = ny;
-
-#if 0
-	dx = -lastdx;
-	dx += (lastdx = joy0dat & 0xff);
-	if (dx < -127)
-	    dx = -255-dx;		/* underrun */
-	else
-	if (dx > 127)
-	    dx = 255-dx;		/* overflow */
-
-	dy = -lastdy;
-	dy += (lastdy = joy0dat >> 8);
-	if (dy < -127)
-	    dy = -255-dy;
-	else
-	if (dy > 127)
-	    dy = 255-dy;
-#endif
-
-
-	potgor = custom.potgor;
-	buttons = (ciaa.pra & 0x40 ? 4 : 0) |	/* left button; note that the bits are low-active, as are the expected results -> double negation */
-#if 1
-		  (potgor & 0x0100 ? 2 : 0) |	/* middle button; emulation goes here */
-#endif
-		  (potgor & 0x0400 ? 1 : 0);	/* right button */
-
-
-	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
-#if AMIGA_OLD_INT
-	AMI_MSE_INT_ON();
-#endif
-}
-
-/*
- * close access to the mouse
- */
-
-static int release_mouse(struct inode * inode, struct file * file)
-{
-	free_irq(IRQ_AMIGA_VERTB, mouse_interrupt);
-#if AMIGA_OLD_INT
-	AMI_MSE_INT_OFF();
-#endif
-	return 0;
-}
-
-/*
- * open access to the mouse, currently only one open is
- * allowed.
- */
-
-static int open_mouse(struct inode * inode, struct file * file)
-{
-	/*
-	 *  use VBL to poll mouse deltas
-	 */
-
-	if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0,
-	               "Amiga mouse", mouse_interrupt)) {
-		printk(KERN_INFO "Installing Amiga mouse failed.\n");
-		return -EIO;
-	}
-
-#if AMIGA_OLD_INT
-	AMI_MSE_INT_ON();
-#endif
-	return 0;
-}
-
-static struct busmouse amigamouse = {
-	AMIGAMOUSE_MINOR, "amigamouse", THIS_MODULE, open_mouse, release_mouse, 7
-};
-
-static int __init amiga_mouse_init(void)
-{
-	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
-		return -ENODEV;
-	if (!request_mem_region(CUSTOM_PHYSADDR+10, 2, "amigamouse [Denise]"))
-		return -EBUSY;
-
-	custom.joytest = 0;	/* reset counters */
-#if AMIGA_OLD_INT
-	AMI_MSE_INT_OFF();
-#endif
-	msedev = register_busmouse(&amigamouse);
-	if (msedev < 0)
-		printk(KERN_WARNING "Unable to install Amiga mouse driver.\n");
-	else
-		printk(KERN_INFO "Amiga mouse installed.\n");
-	return msedev < 0 ? msedev : 0;
-}
-
-static void __exit amiga_mouse_exit(void)
-{
-	unregister_busmouse(msedev);
-	release_mem_region(CUSTOM_PHYSADDR+10, 2);
-}
-
-module_init(amiga_mouse_init);
-module_exit(amiga_mouse_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c
--- a/drivers/char/atixlmouse.c	Tue Jul 16 16:49:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,151 +0,0 @@
-/*
- * ATI XL Bus Mouse Driver for Linux
- * by Bob Harris (rth@sparta.com)
- *
- * Uses VFS interface for linux 0.98 (01OCT92)
- *
- * Modified by Chris Colohan (colohan@eecg.toronto.edu)
- * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
- *
- * Converted to use new generic busmouse code.  5 Apr 1998
- *   Russell King <rmk@arm.uk.linux.org>
- *
- * version 0.3a
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-
-#include "busmouse.h"
-
-#define ATIXL_MOUSE_IRQ		5 /* H/W interrupt # set up on ATIXL board */
-#define ATIXL_BUSMOUSE		3 /* Minor device # (mknod c 10 3 /dev/bm) */
-
-/* ATI XL Inport Busmouse Definitions */
-
-#define	ATIXL_MSE_DATA_PORT		0x23d
-#define	ATIXL_MSE_SIGNATURE_PORT	0x23e
-#define	ATIXL_MSE_CONTROL_PORT		0x23c
-
-#define	ATIXL_MSE_READ_BUTTONS		0x00
-#define	ATIXL_MSE_READ_X		0x01
-#define	ATIXL_MSE_READ_Y		0x02
-
-/* Some nice ATI XL macros */
-
-/* Select IR7, HOLD UPDATES (INT ENABLED), save X,Y */
-#define ATIXL_MSE_DISABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
-	outb( (0x20 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
-
-/* Select IR7, Enable updates (INT ENABLED) */
-#define ATIXL_MSE_ENABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
-	 outb( (0xdf & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
-
-/* Select IR7 - Mode Register, NO INTERRUPTS */
-#define ATIXL_MSE_INT_OFF() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
-	outb( (0xe7 & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
-
-/* Select IR7 - Mode Register, DATA INTERRUPTS ENABLED */
-#define ATIXL_MSE_INT_ON() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
-	outb( (0x08 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
-
-/* Same general mouse structure */
-
-static int msedev;
-
-static void mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	char dx, dy, buttons;
-
-	ATIXL_MSE_DISABLE_UPDATE(); /* Note that interrupts are still enabled */
-	outb(ATIXL_MSE_READ_X, ATIXL_MSE_CONTROL_PORT); /* Select IR1 - X movement */
-	dx = inb( ATIXL_MSE_DATA_PORT);
-	outb(ATIXL_MSE_READ_Y, ATIXL_MSE_CONTROL_PORT); /* Select IR2 - Y movement */
-	dy = inb( ATIXL_MSE_DATA_PORT);
-	outb(ATIXL_MSE_READ_BUTTONS, ATIXL_MSE_CONTROL_PORT); /* Select IR0 - Button Status */
-	buttons = inb( ATIXL_MSE_DATA_PORT);
-	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
-	ATIXL_MSE_ENABLE_UPDATE();
-}
-
-static int release_mouse(struct inode * inode, struct file * file)
-{
-	ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
-	free_irq(ATIXL_MOUSE_IRQ, NULL);
-	return 0;
-}
-
-static int open_mouse(struct inode * inode, struct file * file)
-{
-	if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL))
-		return -EBUSY;
-	ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */
-	return 0;
-}
-
-static struct busmouse atixlmouse = {
-	ATIXL_BUSMOUSE, "atixl", THIS_MODULE, open_mouse, release_mouse, 0
-};
-
-static int __init atixl_busmouse_init(void)
-{
-	unsigned char a,b,c;
-
-	/*
-	 *	We must request the resource and claim it atomically
-	 *	nowdays. We can throw it away on error. Otherwise we
-	 *	may race another module load of the same I/O
-	 */
-
-	if (!request_region(ATIXL_MSE_DATA_PORT, 3, "atixlmouse"))
-		return -EIO;
-
-	a = inb( ATIXL_MSE_SIGNATURE_PORT );	/* Get signature */
-	b = inb( ATIXL_MSE_SIGNATURE_PORT );
-	c = inb( ATIXL_MSE_SIGNATURE_PORT );
-	if (( a != b ) && ( a == c ))
-		printk(KERN_INFO "\nATI Inport ");
-	else
-	{
-		release_region(ATIXL_MSE_DATA_PORT,3);
-		return -EIO;
-	}
-	outb(0x80, ATIXL_MSE_CONTROL_PORT);	/* Reset the Inport device */
-	outb(0x07, ATIXL_MSE_CONTROL_PORT);	/* Select Internal Register 7 */
-	outb(0x0a, ATIXL_MSE_DATA_PORT);	/* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */
-
-	msedev = register_busmouse(&atixlmouse);
-	if (msedev < 0)
-	{
-		printk("Bus mouse initialisation error.\n");
-		release_region(ATIXL_MSE_DATA_PORT,3);	/* Was missing */
-	}
-	else
-		printk("Bus mouse detected and installed.\n");
-	return msedev < 0 ? msedev : 0;
-}
-
-static void __exit atixl_cleanup (void)
-{
-	release_region(ATIXL_MSE_DATA_PORT, 3);
-	unregister_busmouse(msedev);
-}
-
-module_init(atixl_busmouse_init);
-module_exit(atixl_cleanup);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/console.c b/drivers/char/console.c
--- a/drivers/char/console.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/char/console.c	Tue Jul 16 16:49:43 2002
@@ -126,6 +126,7 @@
 #define DEFAULT_BELL_DURATION	(HZ/8)
 
 extern void vcs_make_devfs (unsigned int index, int unregister);
+extern void console_map_init(void);
 
 #ifndef MIN
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
@@ -2381,6 +2382,7 @@
 
 	vt_cons[currcons]->vc_num = currcons;
 	tty->driver_data = vt_cons[currcons];
+	vc_cons[currcons].d->vc_tty = tty;
 
 	if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
 		tty->winsize.ws_row = video_num_lines;
@@ -2445,42 +2447,6 @@
 		return;
 	}
 
-	memset(&console_driver, 0, sizeof(struct tty_driver));
-	console_driver.magic = TTY_DRIVER_MAGIC;
-	console_driver.name = "vc/%d";
-	console_driver.name_base = 1;
-	console_driver.major = TTY_MAJOR;
-	console_driver.minor_start = 1;
-	console_driver.num = MAX_NR_CONSOLES;
-	console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
-	console_driver.init_termios = tty_std_termios;
-	console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
-	/* Tell tty_register_driver() to skip consoles because they are
-	 * registered before kmalloc() is ready. We'll patch them in later. 
-	 * See comments at console_init(); see also con_init_devfs(). 
-	 */
-	console_driver.flags |= TTY_DRIVER_NO_DEVFS;
-	console_driver.refcount = &console_refcount;
-	console_driver.table = console_table;
-	console_driver.termios = console_termios;
-	console_driver.termios_locked = console_termios_locked;
-
-	console_driver.open = con_open;
-	console_driver.close = con_close;
-	console_driver.write = con_write;
-	console_driver.write_room = con_write_room;
-	console_driver.put_char = con_put_char;
-	console_driver.flush_chars = con_flush_chars;
-	console_driver.chars_in_buffer = con_chars_in_buffer;
-	console_driver.ioctl = vt_ioctl;
-	console_driver.stop = con_stop;
-	console_driver.start = con_start;
-	console_driver.throttle = con_throttle;
-	console_driver.unthrottle = con_unthrottle;
-
-	if (tty_register_driver(&console_driver))
-		panic("Couldn't register console driver\n");
-
 	init_timer(&console_timer);
 	console_timer.function = blank_screen;
 	if (blankinterval) {
@@ -2517,6 +2483,50 @@
 #ifdef CONFIG_VT_CONSOLE
 	register_console(&vt_console_driver);
 #endif
+}
+
+int __init vty_init(void)
+{
+	memset(&console_driver, 0, sizeof(struct tty_driver));
+	console_driver.magic = TTY_DRIVER_MAGIC;
+	console_driver.name = "vc/%d";
+	console_driver.name_base = 1;
+	console_driver.major = TTY_MAJOR;
+	console_driver.minor_start = 1;
+	console_driver.num = MAX_NR_CONSOLES;
+	console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
+	console_driver.init_termios = tty_std_termios;
+	console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+	/* Tell tty_register_driver() to skip consoles because they are
+	 * registered before kmalloc() is ready. We'll patch them in later. 
+	 * See comments at console_init(); see also con_init_devfs(). 
+	 */
+	console_driver.flags |= TTY_DRIVER_NO_DEVFS;
+	console_driver.refcount = &console_refcount;
+	console_driver.table = console_table;
+	console_driver.termios = console_termios;
+	console_driver.termios_locked = console_termios_locked;
+
+	console_driver.open = con_open;
+	console_driver.close = con_close;
+	console_driver.write = con_write;
+	console_driver.write_room = con_write_room;
+	console_driver.put_char = con_put_char;
+	console_driver.flush_chars = con_flush_chars;
+	console_driver.chars_in_buffer = con_chars_in_buffer;
+	console_driver.ioctl = vt_ioctl;
+	console_driver.stop = con_stop;
+	console_driver.start = con_start;
+	console_driver.throttle = con_throttle;
+	console_driver.unthrottle = con_unthrottle;
+
+	if (tty_register_driver(&console_driver))
+		panic("Couldn't register console driver\n");
+
+	kbd_init();
+	console_map_init();
+	vcs_init();
+	return 0;
 }
 
 #ifndef VT_SINGLE_DRIVER
diff -Nru a/drivers/char/ftape/Config.in b/drivers/char/ftape/Config.in
--- a/drivers/char/ftape/Config.in	Tue Jul 16 16:49:41 2002
+++ b/drivers/char/ftape/Config.in	Tue Jul 16 16:49:41 2002
@@ -35,7 +35,7 @@
    int '  Maximal data rate to use (EXPERIMENTAL)' CONFIG_FT_FDC_MAX_RATE 2000
 fi
 
-if [ "$ARCH" = "alpha" ]; then
+if [ "$CONFIG_ALPHA" = "y" ]; then
    int '  CPU clock frequency of your DEC Alpha' CONFIG_FT_ALPHA_CLOCK 0
 else
    define_int CONFIG_FT_ALPHA_CLOCK 0
diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c
--- a/drivers/char/keyboard.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/char/keyboard.c	Tue Jul 16 16:49:42 2002
@@ -36,6 +36,7 @@
 #include <asm/keyboard.h>
 #include <asm/bitops.h>
 
+#include <linux/console_struct.h>
 #include <linux/kbd_kern.h>
 #include <linux/kbd_diacr.h>
 #include <linux/vt_kern.h>
@@ -43,8 +44,14 @@
 #include <linux/sysrq.h>
 #include <linux/pm.h>
 
+extern void ctrl_alt_del(void);
+
 #define SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
+/*
+ * Exported functions/variables
+ */
+
 #ifndef KBD_DEFMODE
 #define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
 #endif
@@ -64,277 +71,121 @@
 void (*kbd_ledfunc)(unsigned int led);
 EXPORT_SYMBOL(handle_scancode);
 EXPORT_SYMBOL(kbd_ledfunc);
-
-extern void ctrl_alt_del(void);
-
-struct console;
+/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
+struct pt_regs * kbd_pt_regs;
+void compute_shiftstate(void);
 
 /*
- * global state includes the following, and various static variables
- * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next.
- * (last_console is now a global variable)
- */
-
-/* shift state counters.. */
-static unsigned char k_down[NR_SHIFT];
-/* keyboard key bitmap */
-static unsigned long key_down[256/BITS_PER_LONG];
-
-static int dead_key_next;
-/* 
- * In order to retrieve the shift_state (for the mouse server), either
- * the variable must be global, or a new procedure must be created to 
- * return the value. I chose the former way.
+ * Handler Tables.
  */
-int shift_state;
-static int npadch = -1;			/* -1 or number assembled on pad */
-static unsigned char diacr;
-static char rep;			/* flag telling character repeat */
-struct kbd_struct kbd_table[MAX_NR_CONSOLES];
-static struct tty_struct **ttytab;
-static struct kbd_struct * kbd = kbd_table;
-static struct tty_struct * tty;
-
-void compute_shiftstate(void);
-
-typedef void (*k_hand)(unsigned char value, char up_flag);
-typedef void (k_handfn)(unsigned char value, char up_flag);
-
-static k_handfn
-	do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
-	do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2,
-	do_ignore;
-
-static k_hand key_handler[16] = {
-	do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
-	do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2,
-	do_ignore, do_ignore
-};
 
 /* Key types processed even in raw modes */
 
 #define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT))
+#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK))
 
-typedef void (*void_fnp)(void);
-typedef void (void_fn)(void);
-
-static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
-	num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
-	SAK, decr_console, incr_console, spawn_console, bare_num;
-
-static void_fnp spec_fn_table[] = {
-	do_null,	enter,		show_ptregs,	show_mem,
-	show_state,	send_intr,	lastcons,	caps_toggle,
-	num,		hold,		scroll_forw,	scroll_back,
-	boot_it,	caps_on,	compose,	SAK,
-	decr_console,	incr_console,	spawn_console,	bare_num
-};
+#define K_HANDLERS\
+	k_self,		k_fn,		k_spec,		k_pad,\
+	k_dead,		k_cons,		k_cur,		k_shift,\
+	k_meta,		k_ascii,	k_lock,		k_lowercase,\
+	k_slock,	k_dead2,	k_ignore,	k_ignore	
+
+typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, 
+			    char up_flag);
+static k_handler_fn K_HANDLERS;
+static k_handler_fn *k_handler[16] = { K_HANDLERS };
+
+#define FN_HANDLERS\
+	fn_null, 	fn_enter,	fn_show_ptregs,	fn_show_mem,\
+	fn_show_state,	fn_send_intr, 	fn_lastcons, 	fn_caps_toggle,\
+	fn_num,		fn_hold, 	fn_scroll_forw,	fn_scroll_back,\
+	fn_boot_it, 	fn_caps_on, 	fn_compose,	fn_SAK,\
+	fn_dec_console, fn_inc_console, fn_spawn_con, 	fn_bare_num
+
+typedef void (fn_handler_fn)(struct vc_data *vc);
+static fn_handler_fn FN_HANDLERS;
+static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
 
-#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK))
+/*
+ * Variables/functions exported for vt.c
+ */
 
 /* maximum values each key_handler can handle */
 const int max_vals[] = {
-	255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
-	NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
-	255, NR_ASCII - 1, NR_LOCK - 1, 255,
-	NR_LOCK - 1, 255
+	255, SIZE(func_table) - 1, SIZE(fn_handler) - 1, NR_PAD - 1,
+	NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
+	255, NR_LOCK - 1, 255
 };
 
 const int NR_TYPES = SIZE(max_vals);
 
-/* N.B. drivers/macintosh/mac_keyb.c needs to call put_queue */
-void put_queue(int);
-static unsigned char handle_diacr(unsigned char);
-
-/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
-struct pt_regs * kbd_pt_regs;
-
-#ifdef CONFIG_MAGIC_SYSRQ
-static int sysrq_pressed;
-#endif
-
-static struct pm_dev *pm_kbd;
-
-/*
- * Many other routines do put_queue, but I think either
- * they produce ASCII, or they produce some user-assigned
- * string, and in both cases we might assume that it is
- * in utf-8 already.
- */
-void to_utf8(ushort c) {
-    if (c < 0x80)
-	put_queue(c);			/*  0*******  */
-    else if (c < 0x800) {
-	put_queue(0xc0 | (c >> 6)); 	/*  110***** 10******  */
-	put_queue(0x80 | (c & 0x3f));
-    } else {
-	put_queue(0xe0 | (c >> 12)); 	/*  1110**** 10****** 10******  */
-	put_queue(0x80 | ((c >> 6) & 0x3f));
-	put_queue(0x80 | (c & 0x3f));
-    }
-    /* UTF-8 is defined for words of up to 31 bits,
-       but we need only 16 bits here */
-}
+int spawnpid, spawnsig;
 
 /*
  * Translation of escaped scancodes to keycodes.
  * This is now user-settable (for machines were it makes sense).
  */
-
-int setkeycode(unsigned int scancode, unsigned int keycode)
-{
-    return kbd_setkeycode(scancode, keycode);
-}
-
 int getkeycode(unsigned int scancode)
 {
     return kbd_getkeycode(scancode);
 }
 
-void handle_scancode(unsigned char scancode, int down)
+int setkeycode(unsigned int scancode, unsigned int keycode)
 {
-	unsigned char keycode;
-	char up_flag = down ? 0 : 0200;
-	char raw_mode;
-
-	pm_access(pm_kbd);
-	add_keyboard_randomness(scancode | up_flag);
-
-	tty = ttytab? ttytab[fg_console]: NULL;
-	if (tty && (!tty->driver_data)) {
-		/*
-		 * We touch the tty structure via the ttytab array
-		 * without knowing whether or not tty is open, which
-		 * is inherently dangerous.  We currently rely on that
-		 * fact that console_open sets tty->driver_data when
-		 * it opens it, and clears it when it closes it.
-		 */
-		tty = NULL;
-	}
-	kbd = kbd_table + fg_console;
-	if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
-		put_queue(scancode | up_flag);
-		/* we do not return yet, because we want to maintain
-		   the key_down array, so that we have the correct
-		   values when finishing RAW mode or when changing VT's */
-	}
-
-	/*
-	 *  Convert scancode to keycode
-	 */
-	if (!kbd_translate(scancode, &keycode, raw_mode))
-		goto out;
-
-	/*
-	 * At this point the variable `keycode' contains the keycode.
-	 * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid).
-	 * We keep track of the up/down status of the key, and
-	 * return the keycode if in MEDIUMRAW mode.
-	 */
-
-	if (up_flag) {
-		rep = 0;
-		if(!test_and_clear_bit(keycode, key_down))
-		    up_flag = kbd_unexpected_up(keycode);
-	} else
-		rep = test_and_set_bit(keycode, key_down);
-
-#ifdef CONFIG_MAGIC_SYSRQ		/* Handle the SysRq Hack */
-	if (keycode == SYSRQ_KEY) {
-		sysrq_pressed = !up_flag;
-		goto out;
-	} else if (sysrq_pressed) {
-		if (!up_flag) {
-			handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty);
-			goto out;
-		}
-	}
-#endif
+    return kbd_setkeycode(scancode, keycode);
+}
 
-	if (kbd->kbdmode == VC_MEDIUMRAW) {
-		/* soon keycodes will require more than one byte */
-		put_queue(keycode + up_flag);
-		raw_mode = 1;	/* Most key classes will be ignored */
-	}
+/*
+ * Variables/function exported for console.c
+ */
+int shift_state = 0;
 
-	/*
-	 * Small change in philosophy: earlier we defined repetition by
-	 *	 rep = keycode == prev_keycode;
-	 *	 prev_keycode = keycode;
-	 * but now by the fact that the depressed key was down already.
-	 * Does this ever make a difference? Yes.
-	 */
+/*
+ * Internal Data.
+ */
 
-	/*
-	 *  Repeat a key only if the input buffers are empty or the
-	 *  characters get echoed locally. This makes key repeat usable
-	 *  with slow applications and under heavy loads.
-	 */
-	if (!rep ||
-	    (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
-	     (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) {
-		u_short keysym;
-		u_char type;
+static unsigned long key_down[256/BITS_PER_LONG]; /* keyboard key bitmap */
+static unsigned char shift_down[NR_SHIFT];	/* shift state counters.. */	
+static int dead_key_next;
+static int npadch = -1;			/* -1 or number assembled on pad */
+static unsigned char diacr;
+static char rep;			/* flag telling character repeat */
+pm_callback pm_kbd_request_override = NULL;
+typedef void (pm_kbd_func) (void);
+static struct pm_dev *pm_kbd;
 
-		/* the XOR below used to be an OR */
-		int shift_final = (shift_state | kbd->slockstate) ^
-		    kbd->lockstate;
-		ushort *key_map = key_maps[shift_final];
+static unsigned char ledstate = 0xff; /* undefined */
+static unsigned char ledioctl;
 
-		if (key_map != NULL) {
-			keysym = key_map[keycode];
-			type = KTYP(keysym);
+static struct ledptr {
+    unsigned int *addr;
+    unsigned int mask;
+    unsigned char valid:1;
+} ledptrs[3];
 
-			if (type >= 0xf0) {
-			    type -= 0xf0;
-			    if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type)))
-				goto out;
-			    if (type == KT_LETTER) {
-				type = KT_LATIN;
-				if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
-				    key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
-				    if (key_map)
-				      keysym = key_map[keycode];
-				}
-			    }
-			    (*key_handler[type])(keysym & 0xff, up_flag);
-			    if (type != KT_SLOCK)
-			      kbd->slockstate = 0;
-			} else {
-			    /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */
-			    if (!up_flag && !raw_mode)
-			      to_utf8(keysym);
-			}
-		} else {
-			/* maybe beep? */
-			/* we have at least to update shift_state */
-#if 1			/* how? two almost equivalent choices follow */
-			compute_shiftstate();
-			kbd->slockstate = 0; /* play it safe */
-#else
-			keysym =  U(plain_map[keycode]);
-			type = KTYP(keysym);
-			if (type == KT_SHIFT)
-			  (*key_handler[type])(keysym & 0xff, up_flag);
+struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+static struct kbd_struct *kbd = kbd_table;
+#ifdef CONFIG_MAGIC_SYSRQ
+static int sysrq_pressed;
 #endif
-		}
-	}
-out:
-	do_poke_blanked_console = 1;
-	schedule_console_callback();
-}
 
-
-void put_queue(int ch)
+/*
+ * Helper Functions.
+ */
+void put_queue(struct vc_data *vc, int ch)
 {
+	struct tty_struct *tty = vc->vc_tty;	
+
 	if (tty) {
 		tty_insert_flip_char(tty, ch, 0);
 		con_schedule_flip(tty);
 	}
 }
 
-static void puts_queue(char *cp)
+static void puts_queue(struct vc_data *vc, char *cp)
 {
+	struct tty_struct *tty = vc->vc_tty;
+
 	if (!tty)
 		return;
 
@@ -345,48 +196,139 @@
 	con_schedule_flip(tty);
 }
 
-static void applkey(int key, char mode)
+static void applkey(struct vc_data *vc, int key, char mode)
 {
 	static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
 
 	buf[1] = (mode ? 'O' : '[');
 	buf[2] = key;
-	puts_queue(buf);
+	puts_queue(vc, buf);
 }
 
-static void enter(void)
+/*
+ * Many other routines do put_queue, but I think either
+ * they produce ASCII, or they produce some user-assigned
+ * string, and in both cases we might assume that it is
+ * in utf-8 already. UTF-8 is defined for words of up to 31 bits,
+ * but we need only 16 bits here
+ */
+void to_utf8(struct vc_data *vc, ushort c) 
+{
+	if (c < 0x80)
+		/*  0*******  */
+		put_queue(vc, c);
+    	else if (c < 0x800) {
+		/*  110***** 10******  */
+		put_queue(vc, 0xc0 | (c >> 6)); 
+		put_queue(vc, 0x80 | (c & 0x3f));
+    	} else {
+		/*  1110**** 10****** 10*******/
+		put_queue(vc, 0xe0 | (c >> 12));
+		put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
+		put_queue(vc, 0x80 | (c & 0x3f));
+    	}
+}
+
+/* called after returning from RAW mode or when changing consoles -
+   recompute shift_down[] and shift_state from key_down[] */
+/* maybe called when keymap is undefined, so that shiftkey release is seen */
+void compute_shiftstate(void)
+{
+	int i, j, k, sym, val;
+
+	shift_state = 0;
+	memset(shift_down, 0, sizeof(shift_down));
+	
+	for (i = 0; i < SIZE(key_down); i++) {
+	  	
+		if (!key_down[i])
+			continue;	    
+
+		k = i*BITS_PER_LONG;
+	
+		for (j = 0; j < BITS_PER_LONG; j++, k++) {
+	      
+			if (!test_bit(k, key_down))
+				continue;
+	
+			sym = U(plain_map[k]);
+			if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
+				continue;
+
+	  		val = KVAL(sym);
+		  	if (val == KVAL(K_CAPSSHIFT))
+		    		val = KVAL(K_SHIFT);
+		  	
+			shift_down[val]++;
+		  	shift_state |= (1<<val);
+		}
+	}
+}
+
+/*
+ * We have a combining character DIACR here, followed by the character CH.
+ * If the combination occurs in the table, return the corresponding value.
+ * Otherwise, if CH is a space or equals DIACR, return DIACR.
+ * Otherwise, conclude that DIACR was not combining after all,
+ * queue it and return CH.
+ */
+unsigned char handle_diacr(struct vc_data *vc, unsigned char ch)
+{
+	int d = diacr;
+	int i;
+
+	diacr = 0;
+
+	for (i = 0; i < accent_table_size; i++) {
+		if (accent_table[i].diacr == d && accent_table[i].base == ch)
+			return accent_table[i].result;
+	}
+
+	if (ch == ' ' || ch == d)
+		return d;
+
+	put_queue(vc, d);
+	return ch;
+}
+
+/*
+ * Special function handlers
+ */
+static void fn_enter(struct vc_data *vc)
 {
 	if (diacr) {
-		put_queue(diacr);
+		put_queue(vc, diacr);
 		diacr = 0;
 	}
-	put_queue(13);
-	if (vc_kbd_mode(kbd,VC_CRLF))
-		put_queue(10);
+	put_queue(vc, 13);
+	if (vc_kbd_mode(kbd, VC_CRLF))
+		put_queue(vc, 10);
 }
 
-static void caps_toggle(void)
+static void fn_caps_toggle(struct vc_data *vc)
 {
 	if (rep)
 		return;
 	chg_vc_kbd_led(kbd, VC_CAPSLOCK);
 }
 
-static void caps_on(void)
+static void fn_caps_on(struct vc_data *vc)
 {
 	if (rep)
 		return;
 	set_vc_kbd_led(kbd, VC_CAPSLOCK);
 }
 
-static void show_ptregs(void)
+static void fn_show_ptregs(struct vc_data *vc)
 {
 	if (kbd_pt_regs)
 		show_regs(kbd_pt_regs);
 }
 
-static void hold(void)
+static void fn_hold(struct vc_data *vc)
 {
+	struct tty_struct *tty = vc->vc_tty;
+
 	if (rep || !tty)
 		return;
 
@@ -401,12 +343,12 @@
 		stop_tty(tty);
 }
 
-static void num(void)
+static void fn_num(struct vc_data *vc)
 {
 	if (vc_kbd_mode(kbd,VC_APPLIC))
-		applkey('P', 1);
+		applkey(vc, 'P', 1);
 	else
-		bare_num();
+		fn_bare_num(vc);
 }
 
 /*
@@ -415,19 +357,19 @@
  * Bind this to NumLock if you prefer that the NumLock key always
  * changes the NumLock flag.
  */
-static void bare_num(void)
+static void fn_bare_num(struct vc_data *vc)
 {
 	if (!rep)
 		chg_vc_kbd_led(kbd,VC_NUMLOCK);
 }
 
-static void lastcons(void)
+static void fn_lastcons(struct vc_data *vc)
 {
 	/* switch to the last used console, ChN */
 	set_console(last_console);
 }
 
-static void decr_console(void)
+static void fn_dec_console(struct vc_data *vc)
 {
 	int i;
  
@@ -440,7 +382,7 @@
 	set_console(i);
 }
 
-static void incr_console(void)
+static void fn_inc_console(struct vc_data *vc)
 {
 	int i;
 
@@ -453,98 +395,112 @@
 	set_console(i);
 }
 
-static void send_intr(void)
+static void fn_send_intr(struct vc_data *vc)
 {
+	struct tty_struct *tty = vc->vc_tty;
+
 	if (!tty)
 		return;
 	tty_insert_flip_char(tty, 0, TTY_BREAK);
 	con_schedule_flip(tty);
 }
 
-static void scroll_forw(void)
+static void fn_scroll_forw(struct vc_data *vc)
 {
 	scrollfront(0);
 }
 
-static void scroll_back(void)
+static void fn_scroll_back(struct vc_data *vc)
 {
 	scrollback(0);
 }
 
-static void boot_it(void)
+static void fn_show_mem(struct vc_data *vc)
+{
+	show_mem();
+}
+
+static void fn_show_state(struct vc_data *vc)
+{
+	show_state();
+}
+
+static void fn_boot_it(struct vc_data *vc)
 {
 	ctrl_alt_del();
 }
 
-static void compose(void)
+static void fn_compose(struct vc_data *vc)
 {
 	dead_key_next = 1;
 }
 
-int spawnpid, spawnsig;
-
-static void spawn_console(void)
+static void fn_spawn_con(struct vc_data *vc)
 {
         if (spawnpid)
 	   if(kill_proc(spawnpid, spawnsig, 1))
 	     spawnpid = 0;
 }
 
-static void SAK(void)
+static void fn_SAK(struct vc_data *vc)
 {
+	struct tty_struct *tty = vc->vc_tty;
+
 	/*
 	 * SAK should also work in all raw modes and reset
 	 * them properly.
 	 */
-
-	do_SAK(tty);
+	if (tty)
+		do_SAK(tty);
 	reset_vc(fg_console);
 #if 0
 	do_unblank_screen();	/* not in interrupt routine? */
 #endif
 }
 
-static void do_ignore(unsigned char value, char up_flag)
+static void fn_null(struct vc_data *vc)
 {
+	compute_shiftstate();
 }
 
-static void do_null()
+/*
+ * Special key handlers
+ */
+static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag)
 {
-	compute_shiftstate();
 }
 
-static void do_spec(unsigned char value, char up_flag)
+static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	if (up_flag)
 		return;
-	if (value >= SIZE(spec_fn_table))
+	if (value >= SIZE(fn_handler))
 		return;
 	if ((kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) &&
 	    !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value)))
 		return;
-	spec_fn_table[value]();
+	fn_handler[value](vc);
 }
 
-static void do_lowercase(unsigned char value, char up_flag)
+static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	printk(KERN_ERR "keyboard.c: do_lowercase was called - impossible\n");
 }
 
-static void do_self(unsigned char value, char up_flag)
+static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	if (up_flag)
 		return;		/* no action, if this is a key release */
 
 	if (diacr)
-		value = handle_diacr(value);
+		value = handle_diacr(vc, value);
 
 	if (dead_key_next) {
 		dead_key_next = 0;
 		diacr = value;
 		return;
 	}
-
-	put_queue(value);
+	put_queue(vc, value);
 }
 
 #define A_GRAVE  '`'
@@ -557,10 +513,10 @@
 	{A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL };
 
 /* Obsolete - for backwards compatibility only */
-static void do_dead(unsigned char value, char up_flag)
+static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	value = ret_diacr[value];
-	do_dead2(value,up_flag);
+	k_dead2(vc, value,up_flag);
 }
 
 /*
@@ -568,60 +524,33 @@
  * dead keys modifying the same character. Very useful
  * for Vietnamese.
  */
-static void do_dead2(unsigned char value, char up_flag)
+static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	if (up_flag)
 		return;
 
-	diacr = (diacr ? handle_diacr(value) : value);
-}
-
-
-/*
- * We have a combining character DIACR here, followed by the character CH.
- * If the combination occurs in the table, return the corresponding value.
- * Otherwise, if CH is a space or equals DIACR, return DIACR.
- * Otherwise, conclude that DIACR was not combining after all,
- * queue it and return CH.
- */
-unsigned char handle_diacr(unsigned char ch)
-{
-	int d = diacr;
-	int i;
-
-	diacr = 0;
-
-	for (i = 0; i < accent_table_size; i++) {
-		if (accent_table[i].diacr == d && accent_table[i].base == ch)
-			return accent_table[i].result;
-	}
-
-	if (ch == ' ' || ch == d)
-		return d;
-
-	put_queue(d);
-	return ch;
+	diacr = (diacr ? handle_diacr(vc, value) : value);
 }
 
-static void do_cons(unsigned char value, char up_flag)
+static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	if (up_flag)
 		return;
 	set_console(value);
 }
 
-static void do_fn(unsigned char value, char up_flag)
+static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	if (up_flag)
 		return;
 	if (value < SIZE(func_table)) {
 		if (func_table[value])
-			puts_queue(func_table[value]);
+			puts_queue(vc, func_table[value]);
 	} else
-		printk(KERN_ERR "do_fn called with value=%d\n", value);
+		printk(KERN_ERR "k_fn called with value=%d\n", value);
 }
 
-static void do_pad(unsigned char value, char up_flag)
+static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	static const char *pad_chars = "0123456789+-*/\015,.?()";
 	static const char *app_map = "pqrstuvwxylSRQMnnmPQ";
@@ -630,8 +559,8 @@
 		return;		/* no action, if this is a key release */
 
 	/* kludge... shift forces cursor/number keys */
-	if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
-		applkey(app_map[value], 1);
+	if (vc_kbd_mode(kbd,VC_APPLIC) && !shift_down[KG_SHIFT]) {
+		applkey(vc, app_map[value], 1);
 		return;
 	}
 
@@ -639,55 +568,55 @@
 		switch (value) {
 			case KVAL(K_PCOMMA):
 			case KVAL(K_PDOT):
-				do_fn(KVAL(K_REMOVE), 0);
+				k_fn(vc, KVAL(K_REMOVE), 0);
 				return;
 			case KVAL(K_P0):
-				do_fn(KVAL(K_INSERT), 0);
+				k_fn(vc, KVAL(K_INSERT), 0);
 				return;
 			case KVAL(K_P1):
-				do_fn(KVAL(K_SELECT), 0);
+				k_fn(vc, KVAL(K_SELECT), 0);
 				return;
 			case KVAL(K_P2):
-				do_cur(KVAL(K_DOWN), 0);
+				k_cur(vc, KVAL(K_DOWN), 0);
 				return;
 			case KVAL(K_P3):
-				do_fn(KVAL(K_PGDN), 0);
+				k_fn(vc, KVAL(K_PGDN), 0);
 				return;
 			case KVAL(K_P4):
-				do_cur(KVAL(K_LEFT), 0);
+				k_cur(vc, KVAL(K_LEFT), 0);
 				return;
 			case KVAL(K_P6):
-				do_cur(KVAL(K_RIGHT), 0);
+				k_cur(vc, KVAL(K_RIGHT), 0);
 				return;
 			case KVAL(K_P7):
-				do_fn(KVAL(K_FIND), 0);
+				k_fn(vc, KVAL(K_FIND), 0);
 				return;
 			case KVAL(K_P8):
-				do_cur(KVAL(K_UP), 0);
+				k_cur(vc, KVAL(K_UP), 0);
 				return;
 			case KVAL(K_P9):
-				do_fn(KVAL(K_PGUP), 0);
+				k_fn(vc, KVAL(K_PGUP), 0);
 				return;
 			case KVAL(K_P5):
-				applkey('G', vc_kbd_mode(kbd, VC_APPLIC));
+				applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC));
 				return;
 		}
 
-	put_queue(pad_chars[value]);
+	put_queue(vc, pad_chars[value]);
 	if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
-		put_queue(10);
+		put_queue(vc, 10);
 }
 
-static void do_cur(unsigned char value, char up_flag)
+static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	static const char *cur_chars = "BDCA";
+
 	if (up_flag)
 		return;
-
-	applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
+	applkey(vc, cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
 }
 
-static void do_shift(unsigned char value, char up_flag)
+static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	int old_state = shift_state;
 
@@ -705,12 +634,12 @@
 	if (up_flag) {
 		/* handle the case that two shift or control
 		   keys are depressed simultaneously */
-		if (k_down[value])
-			k_down[value]--;
+		if (shift_down[value])
+			shift_down[value]--;
 	} else
-		k_down[value]++;
+		shift_down[value]++;
 
-	if (k_down[value])
+	if (shift_down[value])
 		shift_state |= (1 << value);
 	else
 		shift_state &= ~ (1 << value);
@@ -718,54 +647,26 @@
 	/* kludge */
 	if (up_flag && shift_state != old_state && npadch != -1) {
 		if (kbd->kbdmode == VC_UNICODE)
-		  to_utf8(npadch & 0xffff);
+		  to_utf8(vc, npadch & 0xffff);
 		else
-		  put_queue(npadch & 0xff);
+		  put_queue(vc, npadch & 0xff);
 		npadch = -1;
 	}
 }
 
-/* called after returning from RAW mode or when changing consoles -
-   recompute k_down[] and shift_state from key_down[] */
-/* maybe called when keymap is undefined, so that shiftkey release is seen */
-void compute_shiftstate(void)
-{
-	int i, j, k, sym, val;
-
-	shift_state = 0;
-	for(i=0; i < SIZE(k_down); i++)
-	  k_down[i] = 0;
-
-	for(i=0; i < SIZE(key_down); i++)
-	  if(key_down[i]) {	/* skip this word if not a single bit on */
-	    k = i*BITS_PER_LONG;
-	    for(j=0; j<BITS_PER_LONG; j++,k++)
-	      if(test_bit(k, key_down)) {
-		sym = U(plain_map[k]);
-		if(KTYP(sym) == KT_SHIFT || KTYP(sym) == KT_SLOCK) {
-		  val = KVAL(sym);
-		  if (val == KVAL(K_CAPSSHIFT))
-		    val = KVAL(K_SHIFT);
-		  k_down[val]++;
-		  shift_state |= (1<<val);
-		}
-	      }
-	  }
-}
-
-static void do_meta(unsigned char value, char up_flag)
+static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	if (up_flag)
 		return;
 
 	if (vc_kbd_mode(kbd, VC_META)) {
-		put_queue('\033');
-		put_queue(value);
+		put_queue(vc, '\033');
+		put_queue(vc, value);
 	} else
-		put_queue(value | 0x80);
+		put_queue(vc, value | 0x80);
 }
 
-static void do_ascii(unsigned char value, char up_flag)
+static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	int base;
 
@@ -785,16 +686,16 @@
 	  npadch = npadch * base + value;
 }
 
-static void do_lock(unsigned char value, char up_flag)
+static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
 {
 	if (up_flag || rep)
 		return;
 	chg_vc_kbd_lock(kbd, value);
 }
 
-static void do_slock(unsigned char value, char up_flag)
+static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
 {
-	do_shift(value,up_flag);
+	k_shift(vc, value,up_flag);
 	if (up_flag || rep)
 		return;
 	chg_vc_kbd_slock(kbd, value);
@@ -810,10 +711,6 @@
  * or (ii) whatever pattern of lights people want to show using KDSETLED,
  * or (iii) specified bits of specified words in kernel memory.
  */
-
-static unsigned char ledstate = 0xff; /* undefined */
-static unsigned char ledioctl;
-
 unsigned char getledstate(void) {
     return ledstate;
 }
@@ -827,12 +724,6 @@
     set_leds();
 }
 
-static struct ledptr {
-    unsigned int *addr;
-    unsigned int mask;
-    unsigned char valid:1;
-} ledptrs[3];
-
 void register_leds(int console, unsigned int led,
 		   unsigned int *addr, unsigned int mask) {
     struct kbd_struct *kbd = kbd_table + console;
@@ -888,6 +779,7 @@
  * used, but this allows for easy and efficient race-condition
  * prevention later on.
  */
+
 static void kbd_bh(unsigned long dummy)
 {
 	unsigned char leds = getleds();
@@ -902,15 +794,146 @@
 EXPORT_SYMBOL(keyboard_tasklet);
 DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
 
-typedef void (pm_kbd_func) (void);
+void handle_scancode(unsigned char scancode, int down)
+{
+	struct vc_data *vc = vc_cons[fg_console].d;
+	char up_flag = down ? 0 : 0200;
+	struct tty_struct *tty;
+	unsigned char keycode;
+	char raw_mode;
 
-pm_callback pm_kbd_request_override = NULL;
+	pm_access(pm_kbd);
+	add_keyboard_randomness(scancode | up_flag);
+
+	tty = vc->vc_tty;
+
+	if (tty && (!tty->driver_data)) {
+		/*
+		 * We touch the tty structure via the ttytab array
+		 * without knowing whether or not tty is open, which
+		 * is inherently dangerous.  We currently rely on that
+		 * fact that console_open sets tty->driver_data when
+		 * it opens it, and clears it when it closes it.
+		 */
+		tty = NULL;
+	}
+	kbd = kbd_table + fg_console;
+	if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
+		put_queue(vc, scancode | up_flag);
+		/* we do not return yet, because we want to maintain
+		   the key_down array, so that we have the correct
+		   values when finishing RAW mode or when changing VT's */
+	}
+
+	/*
+	 *  Convert scancode to keycode
+	 */
+	if (!kbd_translate(scancode, &keycode, raw_mode))
+		goto out;
+
+	/*
+	 * At this point the variable `keycode' contains the keycode.
+	 * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid).
+	 * We keep track of the up/down status of the key, and
+	 * return the keycode if in MEDIUMRAW mode.
+	 */
+
+	if (up_flag) {
+		rep = 0;
+		if(!test_and_clear_bit(keycode, key_down))
+		    up_flag = kbd_unexpected_up(keycode);
+	} else
+		rep = test_and_set_bit(keycode, key_down);
+
+#ifdef CONFIG_MAGIC_SYSRQ		/* Handle the SysRq Hack */
+	if (keycode == SYSRQ_KEY) {
+		sysrq_pressed = !up_flag;
+		goto out;
+	} else if (sysrq_pressed) {
+		if (!up_flag) {
+			handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, tty);
+			goto out;
+		}
+	}
+#endif
+
+	if (kbd->kbdmode == VC_MEDIUMRAW) {
+		/* soon keycodes will require more than one byte */
+		put_queue(vc, keycode + up_flag);
+		raw_mode = 1;	/* Most key classes will be ignored */
+	}
+
+	/*
+	 * Small change in philosophy: earlier we defined repetition by
+	 *	 rep = keycode == prev_keycode;
+	 *	 prev_keycode = keycode;
+	 * but now by the fact that the depressed key was down already.
+	 * Does this ever make a difference? Yes.
+	 */
+
+	/*
+	 *  Repeat a key only if the input buffers are empty or the
+	 *  characters get echoed locally. This makes key repeat usable
+	 *  with slow applications and under heavy loads.
+	 */
+	if (!rep ||
+	    (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
+	     (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) {
+		u_short keysym;
+		u_char type;
+
+		/* the XOR below used to be an OR */
+		int shift_final = (shift_state | kbd->slockstate) ^
+		    kbd->lockstate;
+		ushort *key_map = key_maps[shift_final];
+
+		if (key_map != NULL) {
+			keysym = key_map[keycode];
+			type = KTYP(keysym);
+
+			if (type >= 0xf0) {
+			    type -= 0xf0;
+			    if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type)))
+				goto out;
+			    if (type == KT_LETTER) {
+				type = KT_LATIN;
+				if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
+				    key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
+				    if (key_map)
+				      keysym = key_map[keycode];
+				}
+			    }
+			    (*k_handler[type])(vc, keysym & 0xff, up_flag);
+			    if (type != KT_SLOCK)
+			      kbd->slockstate = 0;
+			} else {
+			    /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */
+			    if (!up_flag && !raw_mode)
+			      to_utf8(vc, keysym);
+			}
+		} else {
+			/* maybe beep? */
+			/* we have at least to update shift_state */
+#if 1			/* how? two almost equivalent choices follow */
+			compute_shiftstate();
+			kbd->slockstate = 0; /* play it safe */
+#else
+			keysym =  U(plain_map[keycode]);
+			type = KTYP(keysym);
+			if (type == KT_SHIFT)
+			  (*key_handler[type])(keysym & 0xff, up_flag);
+#endif
+		}
+	}
+out:
+	do_poke_blanked_console = 1;
+	schedule_console_callback();
+}
 
 int __init kbd_init(void)
 {
 	int i;
 	struct kbd_struct kbd0;
-	extern struct tty_driver console_driver;
 
 	kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
 	kbd0.ledmode = LED_SHOW_FLAGS;
@@ -921,8 +944,6 @@
  
 	for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
 		kbd_table[i] = kbd0;
-
-	ttytab = console_driver.table;
 
 	kbd_init_hw();
 
diff -Nru a/drivers/char/logibusmouse.c b/drivers/char/logibusmouse.c
--- a/drivers/char/logibusmouse.c	Tue Jul 16 16:49:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,165 +0,0 @@
-/*
- * Logitech Bus Mouse Driver for Linux
- * by James Banks
- *
- * Mods by Matthew Dillon
- *   calls verify_area()
- *   tracks better when X is busy or paging
- *
- * Heavily modified by David Giller
- *   changed from queue- to counter- driven
- *   hacked out a (probably incorrect) mouse_select
- *
- * Modified again by Nathan Laredo to interface with
- *   0.96c-pl1 IRQ handling changes (13JUL92)
- *   didn't bother touching select code.
- *
- * Modified the select() code blindly to conform to the VFS
- *   requirements. 92.07.14 - Linus. Somebody should test it out.
- *
- * Modified by Johan Myreen to make room for other mice (9AUG92)
- *   removed assignment chr_fops[10] = &mouse_fops; see mouse.c
- *   renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
- *   renamed this file mouse.c => busmouse.c
- *
- * Minor addition by Cliff Matthews
- *   added fasync support
- *
- * Modularised 6-Sep-95 Philip Blundell <pjb27@cam.ac.uk> 
- *
- * Replaced dumb busy loop with udelay()  16 Nov 95
- *   Nathan Laredo <laredo@gnu.ai.mit.edu>
- *
- * Track I/O ports with request_region().  12 Dec 95 Philip Blundell
- *
- * Converted to use new generic busmouse code.  5 Apr 1998
- *   Russell King <rmk@arm.uk.linux.org>
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/logibusmouse.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/poll.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-
-#include "busmouse.h"
-
-static int msedev;
-static int mouse_irq = MOUSE_IRQ;
-
-MODULE_PARM(mouse_irq, "i");
-
-#ifndef MODULE
-
-static int __init bmouse_setup(char *str)
-{
-	int ints[4];
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-
-	if (ints[0] > 0)
-		mouse_irq=ints[1];
-
-	return 1;
-}
-
-__setup("logi_busmouse=", bmouse_setup);
-
-#endif /* !MODULE */
-
-static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	char dx, dy;
-	unsigned char buttons;
-
-	outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
-	dx = (inb(MSE_DATA_PORT) & 0xf);
-	outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
-	dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
-	outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
-	dy = (inb(MSE_DATA_PORT) & 0xf);
-	outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
-	buttons = inb(MSE_DATA_PORT);
-	dy |= (buttons & 0xf) << 4;
-	buttons = ((buttons >> 5) & 0x07);
-	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
-	MSE_INT_ON();
-}
-
-/*
- * close access to the mouse
- */
-static int close_mouse(struct inode * inode, struct file * file)
-{
-	MSE_INT_OFF();
-	free_irq(mouse_irq, NULL);
-	return 0;
-}
-
-/*
- * open access to the mouse
- */
-
-static int open_mouse(struct inode * inode, struct file * file)
-{
-	if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL))
-		return -EBUSY;
-	MSE_INT_ON();
-	return 0;
-}
-
-static struct busmouse busmouse = {
-	LOGITECH_BUSMOUSE, "busmouse", THIS_MODULE, open_mouse, close_mouse, 7
-};
-
-static int __init logi_busmouse_init(void)
-{
-	if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "busmouse"))
-		return -EIO;
-
-	outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
-	outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
-	udelay(100L);	/* wait for reply from mouse */
-	if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
-		release_region(LOGIBM_BASE, LOGIBM_EXTENT);
-		return -EIO;
-	}
-
-	outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
-	MSE_INT_OFF();
-	
-	msedev = register_busmouse(&busmouse);
-	if (msedev < 0) {
-		release_region(LOGIBM_BASE, LOGIBM_EXTENT);
-		printk(KERN_WARNING "Unable to register busmouse driver.\n");
-	} 
-	else
-		printk(KERN_INFO "Logitech busmouse installed.\n");
-	
-	return msedev < 0 ? msedev : 0;
-}
-
-static void __exit logi_busmouse_cleanup (void)
-{
-	unregister_busmouse(msedev);
-	release_region(LOGIBM_BASE, LOGIBM_EXTENT);
-}
-
-module_init(logi_busmouse_init);
-module_exit(logi_busmouse_cleanup);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c
--- a/drivers/char/msbusmouse.c	Tue Jul 16 16:49:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,175 +0,0 @@
-/*
- * Microsoft busmouse driver based on Logitech driver (see busmouse.c)
- *
- * Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92)
- *
- * Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net)
- *    8/28/92
- *
- * Microsoft Bus Mouse support folded into 0.97pl4 code
- *    by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
- * Changes:  Logitech and Microsoft support in the same kernel.
- *           Defined new constants in busmouse.h for MS mice.
- *           Added int mse_busmouse_type to distinguish busmouse types
- *           Added a couple of new functions to handle differences in using
- *             MS vs. Logitech (where the int variable wasn't appropriate).
- *
- * Modified by Peter Cervasio (address above) (26SEP92)
- * Changes:  Included code to (properly?) detect when a Microsoft mouse is
- *           really attached to the machine.  Don't know what this does to
- *           Logitech bus mice, but all it does is read ports.
- *
- * Modified by Christoph Niemann (niemann@rubdv15.etdv.ruhr-uni-bochum.de)
- * Changes:  Better interrupt-handler (like in busmouse.c).
- *	     Some changes to reduce code-size.
- *	     Changed detection code to use inb_p() instead of doing empty
- *	     loops to delay i/o.
- *
- * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
- *
- * Converted to use new generic busmouse code.  5 Apr 1998
- *   Russell King <rmk@arm.uk.linux.org>
- *
- * version 0.3b
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/logibusmouse.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-
-#include "busmouse.h"
-
-static int msedev;
-static int mouse_irq = MOUSE_IRQ;
-
-MODULE_PARM(mouse_irq, "i");
-
-#ifndef MODULE
-
-static int __init msmouse_setup(char *str)
-{
-        int ints[4];
-
-        str = get_options(str, ARRAY_SIZE(ints), ints);
-
-	if (ints[0] > 0)
-		mouse_irq=ints[1];
-
-	return 1;
-}
-
-__setup("msmouse=",msmouse_setup);
-
-#endif /* !MODULE */
-
-static void ms_mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-        char dx, dy;
-	unsigned char buttons;
-
-	outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
-	outb((inb(MS_MSE_DATA_PORT) | 0x20), MS_MSE_DATA_PORT);
-
-	outb(MS_MSE_READ_X, MS_MSE_CONTROL_PORT);
-	dx = inb(MS_MSE_DATA_PORT);
-
-	outb(MS_MSE_READ_Y, MS_MSE_CONTROL_PORT);
-	dy = inb(MS_MSE_DATA_PORT);
-
-	outb(MS_MSE_READ_BUTTONS, MS_MSE_CONTROL_PORT);
-	buttons = ~(inb(MS_MSE_DATA_PORT)) & 0x07;
-
-	outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
-	outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT);
-
-	/* why did the original have:
-	 * if (dx != 0 || dy != 0 || buttons != mouse.buttons ||
-	 *    ((~buttons) & 0x07))
-	 *    ^^^^^^^^^^^^^^^^^^^ this?
-	 */
-	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
-}
-
-static int release_mouse(struct inode * inode, struct file * file)
-{
-	MS_MSE_INT_OFF();
-	free_irq(mouse_irq, NULL);
-	return 0;
-}
-
-static int open_mouse(struct inode * inode, struct file * file)
-{
-	if (request_irq(mouse_irq, ms_mouse_interrupt, 0, "MS Busmouse", NULL))
-		return -EBUSY;
-
-	outb(MS_MSE_START, MS_MSE_CONTROL_PORT);
-	MS_MSE_INT_ON();	
-	return 0;
-}
-
-static struct busmouse msbusmouse = {
-	MICROSOFT_BUSMOUSE, "msbusmouse", THIS_MODULE, open_mouse, release_mouse, 0
-};
-
-static int __init ms_bus_mouse_init(void)
-{
-	int present = 0;
-	int mse_byte, i;
-
-	if (check_region(MS_MSE_CONTROL_PORT, 0x04))
-		return -ENODEV;
-
-	if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
-
-		mse_byte = inb_p(MS_MSE_SIGNATURE_PORT);
-
-		for (i = 0; i < 4; i++) {
-			if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
-				if (inb_p(MS_MSE_SIGNATURE_PORT) == mse_byte)
-					present = 1;
-				else
-					present = 0;
-			} else
-				present = 0;
-		}
-	}
-	if (present == 0)
-		return -EIO;
-	if (!request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse"))
-		return -EIO;
-	
-	MS_MSE_INT_OFF();
-	msedev = register_busmouse(&msbusmouse);
-	if (msedev < 0) {
-		printk(KERN_WARNING "Unable to register msbusmouse driver.\n");
-		release_region(MS_MSE_CONTROL_PORT, 0x04);
-	}
-	else
-		printk(KERN_INFO "Microsoft BusMouse detected and installed.\n");
-	return msedev < 0 ? msedev : 0;
-}
-
-static void __exit ms_bus_mouse_exit(void)
-{
-	unregister_busmouse(msedev);
-	release_region(MS_MSE_CONTROL_PORT, 0x04);
-}
-
-module_init(ms_bus_mouse_init)
-module_exit(ms_bus_mouse_exit)
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/pc110pad.c b/drivers/char/pc110pad.c
--- a/drivers/char/pc110pad.c	Tue Jul 16 16:49:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,851 +0,0 @@
-/*
- *	Linux driver for the PC110 pad
- */
- 
-/**
- * 	DOC: PC110 Digitizer Hardware
- *
- *	The pad provides triples of data. The first byte has
- *	0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down
- *	The second byte is bits 0-6 X
- *	The third is bits 0-6 Y
- *
- *	This is read internally and used to synthesize a stream of
- *	triples in the form expected from a PS/2 device. Specialist
- *	applications can choose to obtain the pad data in other formats
- *	including a debugging mode.
- *
- *	It would be good to add a joystick driver mode to this pad so
- *	that doom and other game playing are better. One possible approach
- *	would be to deactive the mouse mode while the joystick port is opened.
- */
- 
-/*
- *	History
- *
- *	0.0 1997-05-16 Alan Cox <alan@redhat.com> - Pad reader
- *	0.1 1997-05-19 Robin O'Leary <robin@acm.org> - PS/2 emulation
- *	0.2 1997-06-03 Robin O'Leary <robin@acm.org> - tap gesture
- *	0.3 1997-06-27 Alan Cox <alan@redhat.com> - 2.1 commit
- *	0.4 1997-11-09 Alan Cox <alan@redhat.com> - Single Unix VFS API changes
- *	0.5 2000-02-10 Alan Cox <alan@redhat.com> - 2.3.x cleanup, documentation
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/miscdevice.h>
-#include <linux/ptrace.h>
-#include <linux/poll.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-
-#include <asm/signal.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/semaphore.h>
-#include <linux/spinlock.h>
-#include <asm/uaccess.h>
-
-#include "pc110pad.h"
-
-
-static struct pc110pad_params default_params = {
-	mode:			PC110PAD_PS2,
-	bounce_interval:	50 MS,
-	tap_interval:		200 MS,
-	irq:			10,
-	io:			0x15E0,
-};
-
-static struct pc110pad_params current_params;
-
-
-/* driver/filesystem interface management */
-static wait_queue_head_t queue;
-static struct fasync_struct *asyncptr;
-static int active_count = 0; 	/* number of concurrent open()s */
-static spinlock_t pc110_lock = SPIN_LOCK_UNLOCKED;
-/* this lock should be held when referencing active_count */
-static struct semaphore reader_lock;
-
-/**
- *	wake_readers:
- *
- *	Take care of letting any waiting processes know that
- *	now would be a good time to do a read().  Called
- *	whenever a state transition occurs, real or synthetic. Also
- *	issue any SIGIO's to programs that use SIGIO on mice (eg
- *	Executor)
- */
- 
-static void wake_readers(void)
-{
-	wake_up_interruptible(&queue);
-	kill_fasync(&asyncptr, SIGIO, POLL_IN);
-}
-
-
-/*****************************************************************************/
-/*
- * Deal with the messy business of synthesizing button tap and drag
- * events.
- *
- * Exports:
- *	notify_pad_up_down()
- *		Must be called whenever debounced pad up/down state changes.
- *	button_pending
- *		Flag is set whenever read_button() has new values
- *		to return.
- *	read_button()
- *		Obtains the current synthetic mouse button state.
- */
-
-/*
- * These keep track of up/down transitions needed to generate the
- * synthetic mouse button events.  While recent_transition is set,
- * up/down events cause transition_count to increment.  tap_timer
- * turns off the recent_transition flag and may cause some synthetic
- * up/down mouse events to be created by incrementing synthesize_tap.
- */
- 
-static int button_pending;
-static int recent_transition;
-static int transition_count;
-static int synthesize_tap;
-static void tap_timeout(unsigned long data);
-static struct timer_list tap_timer = { function: tap_timeout };
-
-
-/**
- * tap_timeout:
- * @data: Unused
- *
- * This callback goes off a short time after an up/down transition;
- * before it goes off, transitions will be considered part of a
- * single PS/2 event and counted in transition_count.  Once the
- * timeout occurs the recent_transition flag is cleared and
- * any synthetic mouse up/down events are generated.
- */
- 
-static void tap_timeout(unsigned long data)
-{
-	if(!recent_transition)
-	{
-		printk(KERN_ERR "pc110pad: tap_timeout but no recent transition!\n");
-	}
-	if( transition_count==2 || transition_count==4 || transition_count==6 )
-	{
-		synthesize_tap+=transition_count;
-		button_pending = 1;
-		wake_readers();
-	}
-	recent_transition=0;
-}
-
-
-/**
- * notify_pad_up_down:
- *
- * Called by the raw pad read routines when a (debounced) up/down
- * transition is detected.
- */
- 
-void notify_pad_up_down(void)
-{
-	if(recent_transition)
-	{
-		transition_count++;
-	}
-	else
-	{
-		transition_count=1;
-		recent_transition=1;
-	}
-	mod_timer(&tap_timer, jiffies + current_params.tap_interval);
-
-	/* changes to transition_count can cause reported button to change */
-	button_pending = 1;
-	wake_readers();
-}
-
-/**
- *	read_button:
- *	@b: pointer to the button status.
- *
- *	The actual button state depends on what we are seeing. We have to check
- *	for the tap gesture and also for dragging.
- */
-
-static void read_button(int *b)
-{
-	if(synthesize_tap)
-	{
-		*b=--synthesize_tap & 1;
-	}
-	else
-	{
-		*b=(!recent_transition && transition_count==3);	/* drag */
-	}
-	button_pending=(synthesize_tap>0);
-}
-
-
-/*****************************************************************************/
-/*
- * Read pad absolute co-ordinates and debounced up/down state.
- *
- * Exports:
- *	pad_irq()
- *		Function to be called whenever the pad signals
- *		that it has new data available.
- *	read_raw_pad()
- *		Returns the most current pad state.
- *	xy_pending
- *		Flag is set whenever read_raw_pad() has new values
- *		to return.
- * Imports:
- *	wake_readers()
- *		Called when movement occurs.
- *	notify_pad_up_down()
- *		Called when debounced up/down status changes.
- */
-
-/*
- * These are up/down state and absolute co-ords read directly from pad 
- */
-
-static int raw_data[3];
-static int raw_data_count;
-static int raw_x, raw_y;	/* most recent absolute co-ords read */
-static int raw_down;		/* raw up/down state */
-static int debounced_down;	/* up/down state after debounce processing */
-static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE;
-				/* set just after an up/down transition */
-static int xy_pending;	/* set if new data have not yet been read */
-
-/* 
- * Timer goes off a short while after an up/down transition and copies
- * the value of raw_down to debounced_down.
- */
- 
-static void bounce_timeout(unsigned long data);
-static struct timer_list bounce_timer = { function: bounce_timeout };
-
-
-
-/**
- * bounce_timeout:
- * @data: Unused
- *
- * No further up/down transitions happened within the
- * bounce period, so treat this as a genuine transition.
- */
-
-static void bounce_timeout(unsigned long data)
-{
-	switch(bounce)
-	{
-		case NO_BOUNCE:
-		{
-			/*
-			 * Strange; the timer callback should only go off if
-			 * we were expecting to do bounce processing!
-			 */
-			printk(KERN_WARNING "pc110pad, bounce_timeout: bounce flag not set!\n");
-			break;
-		}
-		case JUST_GONE_UP:
-		{
-			/*
-			 * The last up we spotted really was an up, so set
-			 * debounced state the same as raw state.
-			 */
-			bounce=NO_BOUNCE;
-			if(debounced_down==raw_down)
-			{
-				printk(KERN_WARNING "pc110pad, bounce_timeout: raw already debounced!\n");
-			}
-			debounced_down=raw_down;
-
-			notify_pad_up_down();
-			break;
-		}
-		case JUST_GONE_DOWN:
-		{
-			/*
-			 * We don't debounce down events, but we still time
-			 * out soon after one occurs so we can avoid the (x,y)
-			 * skittering that sometimes happens.
-			 */
-			bounce=NO_BOUNCE;
-			break;
-		}
-	}
-}
-
-
-/**
- * pad_irq:
- * @irq: Interrupt number
- * @ptr: Unused
- * @regs: Unused
- *
- * Callback when pad's irq goes off; copies values in to raw_* globals;
- * initiates debounce processing. This isn't SMP safe however there are
- * no SMP machines with a PC110 touchpad on them.
- */
- 
-static void pad_irq(int irq, void *ptr, struct pt_regs *regs)
-{
-
-	/* Obtain byte from pad and prime for next byte */
-	{
-		int value=inb_p(current_params.io);
-		int handshake=inb_p(current_params.io+2);
-		outb_p(handshake | 1, current_params.io+2);
-		outb_p(handshake &~1, current_params.io+2);
-		inb_p(0x64);
-
-		raw_data[raw_data_count++]=value;
-	}
-
-	if(raw_data_count==3)
-	{
-		int new_down=raw_data[0]&0x01;
-		int new_x=raw_data[1];
-		int new_y=raw_data[2];
-		if(raw_data[0]&0x10) new_x+=128;
-		if(raw_data[0]&0x80) new_x+=256;
-		if(raw_data[0]&0x08) new_y+=128;
-
-		if( (raw_x!=new_x) || (raw_y!=new_y) )
-		{
-			raw_x=new_x;
-			raw_y=new_y;
-			xy_pending=1;
-		}
-
-		if(new_down != raw_down)
-		{
-			/* Down state has changed.  raw_down always holds
-			 * the most recently observed state.
-			 */
-			raw_down=new_down;
-
-			/* Forget any earlier bounce processing */
-			if(bounce)
-			{
-				del_timer(&bounce_timer);
-				bounce=NO_BOUNCE;
-			}
-
-			if(new_down)
-			{
-				if(debounced_down)
-				{
-					/* pad gone down, but we were reporting
-					 * it down anyway because we suspected
-					 * (correctly) that the last up was just
-					 * a bounce
-					 */
-				}
-				else
-				{
-					bounce=JUST_GONE_DOWN;
-					mod_timer(&bounce_timer,
-						jiffies+current_params.bounce_interval);
-					/* start new stroke/tap */
-					debounced_down=new_down;
-					notify_pad_up_down();
-				}
-			}
-			else /* just gone up */
-			{
-				if(recent_transition)
-				{
-					/* early bounces are probably part of
-					 * a multi-tap gesture, so process
-					 * immediately
-					 */
-					debounced_down=new_down;
-					notify_pad_up_down();
-				}
-				else
-				{
-					/* don't trust it yet */
-					bounce=JUST_GONE_UP;
-					mod_timer(&bounce_timer,
-						jiffies+current_params.bounce_interval);
-				}
-			}
-		}
-		wake_readers();
-		raw_data_count=0;
-	}
-}
-
-/**
- *	read_raw_pad:
- *	@down: set if the pen is down
- *	@debounced: set if the debounced pen position is down
- *	@x: X position
- *	@y: Y position
- *
- *	Retrieve the data saved by the interrupt handler and indicate we
- *	have no more pending XY to do. 
- *
- *	FIXME: We should switch to a spinlock for this.
- */
-
-static void read_raw_pad(int *down, int *debounced, int *x, int *y)
-{
-	disable_irq(current_params.irq);
-	{
-		*down=raw_down;
-		*debounced=debounced_down;
-		*x=raw_x;
-		*y=raw_y;
-		xy_pending = 0;
-	}
-	enable_irq(current_params.irq);
-}
-
-/*****************************************************************************/
-/*
- * Filesystem interface
- */
-
-/* 
- * Read returns byte triples, so we need to keep track of
- * how much of a triple has been read.  This is shared across
- * all processes which have this device open---not that anything
- * will make much sense in that case.
- */
-static int read_bytes[3];
-static int read_byte_count;
-
-/**
- *	sample_raw:
- *	@d: sample buffer
- *
- *	Retrieve a triple of sample data. 
- */
-
-
-static void sample_raw(int d[3])
-{
-	d[0]=raw_data[0];
-	d[1]=raw_data[1];
-	d[2]=raw_data[2];
-}
-
-/**
- *	sample_rare:
- *	@d: sample buffer
- *
- *	Retrieve a triple of sample data and sanitize it. We do the needed
- *	scaling and masking to get the current status.
- */
-
-
-static void sample_rare(int d[3])
-{
-	int thisd, thisdd, thisx, thisy;
-
-	read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
-
-	d[0]=(thisd?0x80:0)
-	   | (thisx/256)<<4
-	   | (thisdd?0x08:0)
-	   | (thisy/256)
-	;
-	d[1]=thisx%256;
-	d[2]=thisy%256;
-}
-
-/**
- *	sample_debug:
- *	@d: sample buffer
- *
- *	Retrieve a triple of sample data and mix it up with the state 
- *	information in the gesture parser. Not useful for normal users but
- *	handy when debugging
- */
-
-static void sample_debug(int d[3])
-{
-	int thisd, thisdd, thisx, thisy;
-	int b;
-	unsigned long flags;
-
-	spin_lock_irqsave(&pc110_lock, flags);	
-	read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
-	d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce;
-	d[1]=(recent_transition?0x80:0)+transition_count;
-	read_button(&b);
-	d[2]=(synthesize_tap<<4) | (b?0x01:0);
-	spin_unlock_irqrestore(&pc110_lock, flags);
-}
-
-/**
- *	sample_ps2:
- *	@d: sample buffer
- *
- *	Retrieve a triple of sample data and turn the debounced tap and
- *	stroke information into what appears to be a PS/2 mouse. This means
- *	the PC110 pad needs no funny application side support.
- */
-
-
-static void sample_ps2(int d[3])
-{
-	static int lastx, lasty, lastd;
-
-	int thisd, thisdd, thisx, thisy;
-	int dx, dy, b;
-
-	/*
-	 * Obtain the current mouse parameters and limit as appropriate for
-	 * the return data format.  Interrupts are only disabled while 
-	 * obtaining the parameters, NOT during the puts_fs_byte() calls,
-	 * so paging in put_user() does not affect mouse tracking.
-	 */
-	read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
-	read_button(&b);
-
-	/* Now compare with previous readings.  Note that we use the
-	 * raw down flag rather than the debounced one.
-	 */
-	if( (thisd && !lastd) /* new stroke */
-	 || (bounce!=NO_BOUNCE) )
-	{
-		dx=0;
-		dy=0;
-	}
-	else
-	{
-		dx =  (thisx-lastx);
-		dy = -(thisy-lasty);
-	}
-	lastx=thisx;
-	lasty=thisy;
-	lastd=thisd;
-
-/*
-	d[0]= ((dy<0)?0x20:0)
-	    | ((dx<0)?0x10:0)
-	    | 0x08
-	    | (b? 0x01:0x00)
-	;
-*/
-	d[0]= ((dy<0)?0x20:0)
-	    | ((dx<0)?0x10:0)
-	    | (b? 0x00:0x08)
-	;
-	d[1]=dx;
-	d[2]=dy;
-}
-
-
-/**
- *	fasync_pad:
- *	@fd:	file number for the file 
- *	@filp:	file handle
- *	@on:	1 to add, 0 to remove a notifier
- *
- *	Update the queue of asynchronous event notifiers. We can use the
- *	same helper the mice do and that does almost everything we need.
- */
- 
-static int fasync_pad(int fd, struct file *filp, int on)
-{
-	int retval;
-
-	retval = fasync_helper(fd, filp, on, &asyncptr);
-	if (retval < 0)
-		return retval;
-	return 0;
-}
-
-
-/**
- *	close_pad:
- *	@inode: inode of pad
- *	@file: file handle to pad
- *
- *	Close access to the pad. We turn the pad power off if this is the
- *	last user of the pad. I've not actually measured the power draw but
- *	the DOS driver is careful to do this so we follow suit.
- */
- 
-static int close_pad(struct inode * inode, struct file * file)
-{
-	unsigned long flags;
-	fasync_pad(-1, file, 0);
-	spin_lock_irqsave(&pc110_lock, flags);
-	if (!--active_count)
-		outb(0x30, current_params.io+2);  /* switch off digitiser */
-	spin_unlock_irqrestore(&pc110_lock, flags);	
-	return 0;
-}
-
-
-/**
- *	open_pad:
- *	@inode: inode of pad
- *	@file: file handle to pad
- *
- *	Open access to the pad. We turn the pad off first (we turned it off
- *	on close but if this is the first open after a crash the state is
- *	indeterminate). The device has a small fifo so we empty that before
- *	we kick it back into action.
- */
- 
-static int open_pad(struct inode * inode, struct file * file)
-{
-	unsigned long flags;
-	
-       	spin_lock_irqsave(&pc110_lock, flags);
-	if (active_count++)
-        {
-        	spin_unlock_irqrestore(&pc110_lock, flags);
-		return 0;
-	}
-
-	outb(0x30, current_params.io+2);	/* switch off digitiser */
-	pad_irq(0,0,0);		/* read to flush any pending bytes */
-	pad_irq(0,0,0);		/* read to flush any pending bytes */
-	pad_irq(0,0,0);		/* read to flush any pending bytes */
-	outb(0x38, current_params.io+2);	/* switch on digitiser */
-	current_params = default_params;
-	raw_data_count=0;		/* re-sync input byte counter */
-	read_byte_count=0;		/* re-sync output byte counter */
-	button_pending=0;
-	recent_transition=0;
-	transition_count=0;
-	synthesize_tap=0;
-	del_timer(&bounce_timer);
-	del_timer(&tap_timer);
-       spin_unlock_irqrestore(&pc110_lock, flags);
-
-	return 0;
-}
-
-
-/**
- *	write_pad:
- *	@file: File handle to the pad
- *	@buffer: Unused
- *	@count: Unused
- *	@ppos: Unused
- *
- *	Writes are disallowed. A true PS/2 mouse lets you write stuff. Everyone
- *	seems happy with this and not faking the write modes.
- */
-
-static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos)
-{
-	return -EINVAL;
-}
-
-
-/*
- *	new_sample:
- *	@d: sample buffer
- *
- *	Fetch a new sample according the current mouse mode the pad is 
- *	using.
- */
- 
-void new_sample(int d[3])
-{
-	switch(current_params.mode)
-	{
-		case PC110PAD_RAW:	sample_raw(d);		break;
-		case PC110PAD_RARE:	sample_rare(d);		break;
-		case PC110PAD_DEBUG:	sample_debug(d);	break;
-		case PC110PAD_PS2:	sample_ps2(d);		break;
-	}
-}
-
-
-/**
- * read_pad:
- * @file: File handle to pad
- * @buffer: Target for the mouse data
- * @count: Buffer length
- * @ppos: Offset (unused)
- *
- * Read data from the pad. We use the reader_lock to avoid mess when there are
- * two readers. This shouldnt be happening anyway but we play safe.
- */
- 
-static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos)
-{
-	int r;
-
-	down(&reader_lock);
-	for(r=0; r<count; r++)
-	{
-		if(!read_byte_count)
-			new_sample(read_bytes);
-		if(put_user(read_bytes[read_byte_count], buffer+r))
-		{
-			r = -EFAULT;
-			break;
-		}
-		read_byte_count = (read_byte_count+1)%3;
-	}
-	up(&reader_lock);
-	return r;
-}
-
-
-/**
- * pad_poll:
- * @file: File of the pad device
- * @wait: Poll table
- *
- * The pad is ready to read if there is a button or any position change
- * pending in the queue. The reading and interrupt routines maintain the
- * required state for us and do needed wakeups.
- */
-
-static unsigned int pad_poll(struct file *file, poll_table * wait)
-{
-	poll_wait(file, &queue, wait);
-    	if(button_pending || xy_pending)
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-
-/**
- *	pad_ioctl;
- *	@inode: Inode of the pad
- *	@file: File handle to the pad
- *	@cmd: Ioctl command
- *	@arg: Argument pointer
- *
- *	The PC110 pad supports two ioctls both of which use the pc110pad_params
- *	structure. GETP queries the current pad status. SETP changes the pad
- *	configuration. Changing configuration during normal mouse operations
- *	may give momentarily odd results as things like tap gesture state
- *	may be lost.
- */
- 
-static int pad_ioctl(struct inode *inode, struct file * file,
-	unsigned int cmd, unsigned long arg)
-{
-	struct pc110pad_params new;
-
-	if (!inode)
-		return -EINVAL;
-		
-	switch (cmd) {
-	case PC110PADIOCGETP:
-		new = current_params;
-		if(copy_to_user((void *)arg, &new, sizeof(new)))
-			return -EFAULT;
-		return 0;
-
-	case PC110PADIOCSETP:
-		if(copy_from_user(&new, (void *)arg, sizeof(new)))
-			return -EFAULT;
-
-		if( (new.mode<PC110PAD_RAW)
-		 || (new.mode>PC110PAD_PS2)
-		 || (new.bounce_interval<0)
-		 || (new.tap_interval<0)
-		)
-			return -EINVAL;
-
-		current_params.mode	= new.mode;
-		current_params.bounce_interval	= new.bounce_interval;
-		current_params.tap_interval	= new.tap_interval;
-		return 0;
-	}
-	return -ENOTTY;
-}
-
-
-static struct file_operations pad_fops = {
-	owner:		THIS_MODULE,
-	read:		read_pad,
-	write:		write_pad,
-	poll:		pad_poll,
-	ioctl:		pad_ioctl,
-	open:		open_pad,
-	release:	close_pad,
-	fasync:		fasync_pad,
-};
-
-
-static struct miscdevice pc110_pad = {
-	minor:		PC110PAD_MINOR,
-	name:		"pc110 pad",
-	fops:		&pad_fops,
-};
-
-
-/**
- *	pc110pad_init_driver:
- *
- *	We configure the pad with the default parameters (that is PS/2 
- *	emulation mode. We then claim the needed I/O and interrupt resources.
- *	Finally as a matter of paranoia we turn the pad off until we are
- *	asked to open it by an application.
- */
-
-static char banner[] __initdata = KERN_INFO "PC110 digitizer pad at 0x%X, irq %d.\n";
-
-static int __init pc110pad_init_driver(void)
-{
-	init_MUTEX(&reader_lock);
-	current_params = default_params;
-
-	if (request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0)) {
-		printk(KERN_ERR "pc110pad: Unable to get IRQ.\n");
-		return -EBUSY;
-	}
-	if (!request_region(current_params.io, 4, "pc110pad"))	{
-		printk(KERN_ERR "pc110pad: I/O area in use.\n");
-		free_irq(current_params.irq,0);
-		return -EBUSY;
-	}
-	init_waitqueue_head(&queue);
-	printk(banner, current_params.io, current_params.irq);
-	misc_register(&pc110_pad);
-	outb(0x30, current_params.io+2);	/* switch off digitiser */
-	return 0;
-}
-
-/*
- *	pc110pad_exit_driver:
- *
- *	Free the resources we acquired when the module was loaded. We also
- *	turn the pad off to be sure we don't leave it using power.
- */
-
-static void __exit pc110pad_exit_driver(void)
-{
-	outb(0x30, current_params.io+2);	/* switch off digitiser */
-	if (current_params.irq)
-		free_irq(current_params.irq, 0);
-	current_params.irq = 0;
-	release_region(current_params.io, 4);
-	misc_deregister(&pc110_pad);
-}
-
-module_init(pc110pad_init_driver);
-module_exit(pc110pad_exit_driver);
-
-MODULE_AUTHOR("Alan Cox, Robin O'Leary");
-MODULE_DESCRIPTION("Driver for the touchpad on the IBM PC110 palmtop");
-MODULE_LICENSE("GPL");
-
diff -Nru a/drivers/char/pc110pad.h b/drivers/char/pc110pad.h
--- a/drivers/char/pc110pad.h	Tue Jul 16 16:49:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,31 +0,0 @@
-#ifndef _PC110PAD_H
-#define _PC110PAD_H
-
-#include <linux/ioctl.h>
-
-enum pc110pad_mode {
-	PC110PAD_RAW,		/* bytes as they come out of the hardware */
-	PC110PAD_RARE,		/* debounced up/down and absolute x,y */
-	PC110PAD_DEBUG,		/* up/down, debounced, transitions, button */
-	PC110PAD_PS2,		/* ps2 relative (default) */ 
-};
-
-
-struct pc110pad_params {
-	enum pc110pad_mode mode;
-	int	bounce_interval;
-	int	tap_interval;
-	int	irq;
-	int	io;
-};
-
-#define MS *HZ/1000
-
-/* Appears as device major=10 (MISC), minor=PC110_PAD */
-
-#define PC110PAD_IOCTL_TYPE		0x9a
-
-#define PC110PADIOCGETP _IOR(PC110PAD_IOCTL_TYPE, 0, struct pc110pad_params)
-#define PC110PADIOCSETP _IOW(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
- 
-#endif /* _PC110PAD_H */
diff -Nru a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
--- a/drivers/char/pc_keyb.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/char/pc_keyb.c	Tue Jul 16 16:49:42 2002
@@ -912,6 +912,8 @@
 
 void __init pckbd_init_hw(void)
 {
+#ifndef CONFIG_SERIO_I8042
+
 	kbd_request_region();
 
 	/* Flush any pending input. */
@@ -935,6 +937,7 @@
 
 	/* Ok, finally allocate the IRQ, and off we go.. */
 	kbd_request_irq(keyboard_interrupt);
+#endif
 }
 
 #if defined CONFIG_PSMOUSE
@@ -1213,6 +1216,7 @@
 
 static int __init psaux_init(void)
 {
+#ifndef CONFIG_SERIO_I8042
 	int retval;
 
 	if (!detect_auxiliary_port())
@@ -1241,6 +1245,7 @@
 #endif /* INITIALIZE_MOUSE */
 	kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */
 	kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */
+#endif
 
 	return 0;
 }
diff -Nru a/drivers/char/qpmouse.c b/drivers/char/qpmouse.c
--- a/drivers/char/qpmouse.c	Tue Jul 16 16:49:42 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,381 +0,0 @@
-/*
- * linux/drivers/char/qpmouse.c
- *
- * Driver for a 82C710 C&T mouse interface chip.
- *
- * Based on the PS/2 driver by Johan Myreen.
- *
- * Corrections in device setup for some laptop mice & trackballs.
- * 02Feb93  (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca)
- *
- * Modified by Johan Myreen (jem@iki.fi) 04Aug93
- *   to include support for QuickPort mouse.
- *
- * Changed references to "QuickPort" with "82C710" since "QuickPort"
- * is not what this driver is all about -- QuickPort is just a
- * connector type, and this driver is for the mouse port on the Chips
- * & Technologies 82C710 interface chip. 15Nov93 jem@iki.fi
- *
- * Added support for SIGIO. 28Jul95 jem@iki.fi
- *
- * Rearranged SIGIO support to use code from tty_io.  9Sept95 ctm@ardi.com
- *
- * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/semaphore.h>
-
-#include <linux/pc_keyb.h>		/* mouse enable command.. */
-
-
-/*
- * We use the same minor number as the PS/2 mouse for (bad) historical
- * reasons..
- */
-#define PSMOUSE_MINOR      1	       		/* Minor device # for this mouse */
-#define QP_BUF_SIZE	2048
-
-struct qp_queue {
-	unsigned long head;
-	unsigned long tail;
-	wait_queue_head_t proc_list;
-	struct fasync_struct *fasync;
-	unsigned char buf[QP_BUF_SIZE];
-};
-
-static struct qp_queue *queue;
-
-static unsigned int get_from_queue(void)
-{
-	unsigned int result;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	result = queue->buf[queue->tail];
-	queue->tail = (queue->tail + 1) & (QP_BUF_SIZE-1);
-	restore_flags(flags);
-	return result;
-}
-
-
-static inline int queue_empty(void)
-{
-	return queue->head == queue->tail;
-}
-
-static int fasync_qp(int fd, struct file *filp, int on)
-{
-	int retval;
-
-	retval = fasync_helper(fd, filp, on, &queue->fasync);
-	if (retval < 0)
-		return retval;
-	return 0;
-}
-
-/*
- *	82C710 Interface
- */
-
-#define QP_DATA         0x310		/* Data Port I/O Address */
-#define QP_STATUS       0x311		/* Status Port I/O Address */
-
-#define QP_DEV_IDLE     0x01		/* Device Idle */
-#define QP_RX_FULL      0x02		/* Device Char received */
-#define QP_TX_IDLE      0x04		/* Device XMIT Idle */
-#define QP_RESET        0x08		/* Device Reset */
-#define QP_INTS_ON      0x10		/* Device Interrupt On */
-#define QP_ERROR_FLAG   0x20		/* Device Error */
-#define QP_CLEAR        0x40		/* Device Clear */
-#define QP_ENABLE       0x80		/* Device Enable */
-
-#define QP_IRQ          12
-
-static int qp_present;
-static int qp_count;
-static spinlock_t qp_count_lock = SPIN_LOCK_UNLOCKED;
-static int qp_data = QP_DATA;
-static int qp_status = QP_STATUS;
-
-static int poll_qp_status(void);
-static int probe_qp(void);
-
-/*
- * Interrupt handler for the 82C710 mouse port. A character
- * is waiting in the 82C710.
- */
-
-static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
-{
-	int head = queue->head;
-	int maxhead = (queue->tail-1) & (QP_BUF_SIZE-1);
-
-	add_mouse_randomness(queue->buf[head] = inb(qp_data));
-	if (head != maxhead) {
-		head++;
-		head &= QP_BUF_SIZE-1;
-	}
-	queue->head = head;
-	kill_fasync(&queue->fasync, SIGIO, POLL_IN);
-	wake_up_interruptible(&queue->proc_list);
-}
-
-static int release_qp(struct inode * inode, struct file * file)
-{
-	unsigned char status;
-
-	fasync_qp(-1, file, 0);
- 	spin_lock( &qp_count_lock );	
-	if (!--qp_count) {
-		if (!poll_qp_status())
-			printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n");
-		status = inb_p(qp_status);
-		outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
-		if (!poll_qp_status())
-			printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n");
-		free_irq(QP_IRQ, NULL);
-	}
-	spin_unlock( &qp_count_lock );
-	return 0;
-}
-
-/*
- * Install interrupt handler.
- * Enable the device, enable interrupts. 
- */
-
-static int open_qp(struct inode * inode, struct file * file)
-{
-	unsigned char status;
-
-	if (!qp_present)
-		return -EINVAL;
-
-	spin_lock( &qp_count_lock );
-	if (qp_count++)
-	{
-		spin_unlock( &qp_count_lock );
-		return 0;
-	}
-	spin_unlock( &qp_count_lock );
-
-	if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse", NULL)) {
-		qp_count--;
-		return -EBUSY;
-	}
-
-	status = inb_p(qp_status);
-	status |= (QP_ENABLE|QP_RESET);
-	outb_p(status, qp_status);
-	status &= ~(QP_RESET);
-	outb_p(status, qp_status);
-
-	queue->head = queue->tail = 0;          /* Flush input queue */
-	status |= QP_INTS_ON;
-	outb_p(status, qp_status);              /* Enable interrupts */
-
-	while (!poll_qp_status()) {
-		printk(KERN_ERR "Error: Mouse device busy in open_qp()\n");
-		qp_count--;
-		status &= ~(QP_ENABLE|QP_INTS_ON);
-		outb_p(status, qp_status);
-		free_irq(QP_IRQ, NULL);
-		return -EBUSY;
-	}
-
-	outb_p(AUX_ENABLE_DEV, qp_data);	/* Wake up mouse */
-	return 0;
-}
-
-/*
- * Write to the 82C710 mouse device.
- */
-
-static ssize_t write_qp(struct file * file, const char * buffer,
-			size_t count, loff_t *ppos)
-{
-	ssize_t i = count;
-
-	while (i--) {
-		char c;
-		if (!poll_qp_status())
-			return -EIO;
-		get_user(c, buffer++);
-		outb_p(c, qp_data);
-	}
-	file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
-	return count;
-}
-
-static unsigned int poll_qp(struct file *file, poll_table * wait)
-{
-	poll_wait(file, &queue->proc_list, wait);
-	if (!queue_empty())
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-/*
- * Wait for device to send output char and flush any input char.
- */
-
-#define MAX_RETRIES (60)
-
-static int poll_qp_status(void)
-{
-	int retries=0;
-
-	while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE))
-		       != (QP_DEV_IDLE|QP_TX_IDLE)
-		       && retries < MAX_RETRIES) {
-
-		if (inb_p(qp_status)&(QP_RX_FULL))
-			inb_p(qp_data);
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout((5*HZ + 99) / 100);
-		retries++;
-	}
-	return !(retries==MAX_RETRIES);
-}
-
-/*
- * Put bytes from input queue to buffer.
- */
-
-static ssize_t read_qp(struct file * file, char * buffer,
-			size_t count, loff_t *ppos)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t i = count;
-	unsigned char c;
-
-	if (queue_empty()) {
-		if (file->f_flags & O_NONBLOCK)
-			return -EAGAIN;
-		add_wait_queue(&queue->proc_list, &wait);
-repeat:
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (queue_empty() && !signal_pending(current)) {
-			schedule();
-			goto repeat;
-		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue(&queue->proc_list, &wait);
-	}
-	while (i > 0 && !queue_empty()) {
-		c = get_from_queue();
-		put_user(c, buffer++);
-		i--;
-	}
-	if (count-i) {
-		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
-		return count-i;
-	}
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-	return 0;
-}
-
-struct file_operations qp_fops = {
-	owner:		THIS_MODULE,
-	read:		read_qp,
-	write:		write_qp,
-	poll:		poll_qp,
-	open:		open_qp,
-	release:	release_qp,
-	fasync:		fasync_qp,
-};
-
-/*
- * Initialize driver.
- */
-static struct miscdevice qp_mouse = {
-	minor:		PSMOUSE_MINOR,
-	name:		"QPmouse",
-	fops:		&qp_fops,
-};
-
-/*
- * Function to read register in 82C710.
- */
-
-static inline unsigned char read_710(unsigned char index)
-{
-	outb_p(index, 0x390);			/* Write index */
-	return inb_p(0x391);			/* Read the data */
-}
-
-
-/*
- * See if we can find a 82C710 device. Read mouse address.
- */
-
-static int __init probe_qp(void)
-{
-	outb_p(0x55, 0x2fa);			/* Any value except 9, ff or 36 */
-	outb_p(0xaa, 0x3fa);			/* Inverse of 55 */
-	outb_p(0x36, 0x3fa);			/* Address the chip */
-	outb_p(0xe4, 0x3fa);			/* 390/4; 390 = config address */
-	outb_p(0x1b, 0x2fa);			/* Inverse of e4 */
-	if (read_710(0x0f) != 0xe4)		/* Config address found? */
-	  return 0;				/* No: no 82C710 here */
-	qp_data = read_710(0x0d)*4;		/* Get mouse I/O address */
-	qp_status = qp_data+1;
-	outb_p(0x0f, 0x390);
-	outb_p(0x0f, 0x391);			/* Close config mode */
-	return 1;
-}
-
-static char msg_banner[] __initdata = KERN_INFO "82C710 type pointing device detected -- driver installed.\n";
-static char msg_nomem[]  __initdata = KERN_ERR "qpmouse: no queue memory.\n";
-
-static int __init qpmouse_init_driver(void)
-{
-	if (!probe_qp())
-		return -EIO;
-
-	printk(msg_banner);
-
-/*	printk("82C710 address = %x (should be 0x310)\n", qp_data); */
-	queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
-	if (queue == NULL) {
-		printk(msg_nomem);
-		return -ENOMEM;
-	}
-	qp_present = 1;
-	misc_register(&qp_mouse);
-	memset(queue, 0, sizeof(*queue));
-	queue->head = queue->tail = 0;
-	init_waitqueue_head(&queue->proc_list);
-	return 0;
-}
-
-static void __exit qpmouse_exit_driver(void)
-{
-	misc_deregister(&qp_mouse);
-	kfree(queue);
-}
-
-module_init(qpmouse_init_driver);
-module_exit(qpmouse_exit_driver);
-
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c
--- a/drivers/char/raw.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/char/raw.c	Tue Jul 16 16:49:41 2002
@@ -8,8 +8,8 @@
  * device are used to bind the other minor numbers to block devices.
  */
 
+#include <linux/init.h>
 #include <linux/fs.h>
-#include <linux/iobuf.h>
 #include <linux/major.h>
 #include <linux/blkdev.h>
 #include <linux/raw.h>
@@ -86,12 +86,6 @@
 		return 0;
 	}
 	
-	if (!filp->f_iobuf) {
-		err = alloc_kiovec(1, &filp->f_iobuf);
-		if (err)
-			return err;
-	}
-
 	down(&raw_devices[minor].mutex);
 	/*
 	 * No, it is a normal raw device.  All we need to do on open is
@@ -256,124 +250,46 @@
 	return err;
 }
 
-
-
-ssize_t	raw_read(struct file *filp, char * buf, 
-		 size_t size, loff_t *offp)
+ssize_t raw_read(struct file *filp, char * buf, size_t size, loff_t *offp)
 {
 	return rw_raw_dev(READ, filp, buf, size, offp);
 }
 
-ssize_t	raw_write(struct file *filp, const char *buf, 
-		  size_t size, loff_t *offp)
+ssize_t	raw_write(struct file *filp, const char *buf, size_t size, loff_t *offp)
 {
 	return rw_raw_dev(WRITE, filp, (char *) buf, size, offp);
 }
 
-#define SECTOR_BITS 9
-#define SECTOR_SIZE (1U << SECTOR_BITS)
-#define SECTOR_MASK (SECTOR_SIZE - 1)
-
-ssize_t	rw_raw_dev(int rw, struct file *filp, char *buf, 
-		   size_t size, loff_t *offp)
+ssize_t
+rw_raw_dev(int rw, struct file *filp, char *buf, size_t size, loff_t *offp)
 {
-	struct kiobuf * iobuf;
-	int		new_iobuf;
-	int		err = 0;
-	unsigned long	blocks;
-	size_t		transferred;
-	int		iosize;
-	int		minor;
-	kdev_t		dev;
-	unsigned long	limit;
-	int		sector_size, sector_bits, sector_mask;
-	sector_t	blocknr;
 	struct block_device *bdev;
-	
-	/*
-	 * First, a few checks on device size limits 
-	 */
+	struct inode *inode;
+	int minor;
+	ssize_t ret = 0;
 
 	minor = minor(filp->f_dentry->d_inode->i_rdev);
-
-	new_iobuf = 0;
-	iobuf = filp->f_iobuf;
-	if (test_and_set_bit(0, &filp->f_iobuf_lock)) {
-		/*
-		 * A parallel read/write is using the preallocated iobuf
-		 * so just run slow and allocate a new one.
-		 */
-		err = alloc_kiovec(1, &iobuf);
-		if (err)
-			goto out;
-		new_iobuf = 1;
-	}
-
 	bdev = raw_devices[minor].binding;
-	dev = to_kdev_t(bdev->bd_dev);
-	sector_size = raw_devices[minor].sector_size;
-	sector_bits = raw_devices[minor].sector_bits;
-	sector_mask = sector_size - 1;
-
-	limit = bdev->bd_inode->i_size >> sector_bits;
-	if (!limit)
-		limit = INT_MAX;
-	dprintk ("rw_raw_dev: dev %d:%d (+%d)\n",
-		 major(dev), minor(dev), limit);
-	
-	err = -EINVAL;
-	if ((*offp & sector_mask) || (size & sector_mask))
-		goto out_free;
-	err = 0;
-	if (size)
-		err = -ENXIO;
-	if ((*offp >> sector_bits) >= limit)
-		goto out_free;
-
-	transferred = 0;
-	blocknr = *offp >> sector_bits;
-	while (size > 0) {
-		blocks = size >> sector_bits;
-		if (blocks > limit - blocknr)
-			blocks = limit - blocknr;
-		if (!blocks)
-			break;
-
-		iosize = blocks << sector_bits;
+	inode = bdev->bd_inode;
 
-		err = map_user_kiobuf(rw, iobuf, (unsigned long) buf, iosize);
-		if (err)
-			break;
-
-		err = brw_kiovec(rw, 1, &iobuf, raw_devices[minor].binding, &blocknr, sector_size);
-
-		if (rw == READ && err > 0)
-			mark_dirty_kiobuf(iobuf, err);
-		
-		if (err >= 0) {
-			transferred += err;
-			size -= err;
-			buf += err;
-		}
-
-		blocknr += blocks;
-
-		unmap_kiobuf(iobuf);
-
-		if (err != iosize)
-			break;
+	if (size == 0)
+		goto out;
+	if (size < 0) {
+		ret = -EINVAL;
+		goto out;
 	}
-	
-	if (transferred) {
-		*offp += transferred;
-		err = transferred;
+	if (*offp >= inode->i_size) {
+		ret = -ENXIO;
+		goto out;
 	}
+	if (size + *offp > inode->i_size)
+		size = inode->i_size - *offp;
 
- out_free:
-	if (!new_iobuf)
-		clear_bit(0, &filp->f_iobuf_lock);
-	else
-		free_kiovec(1, &iobuf);
- out:	
-	return err;
+	ret = generic_file_direct_IO(rw, inode, buf, *offp, size);
+	if (ret > 0)
+		*offp += ret;
+	if (inode->i_mapping->nrpages)
+		invalidate_inode_pages2(inode->i_mapping);
+out:
+	return ret;
 }
diff -Nru a/drivers/char/serial.c b/drivers/char/serial.c
--- a/drivers/char/serial.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/char/serial.c	Tue Jul 16 16:49:42 2002
@@ -645,7 +645,7 @@
 		if (break_pressed && info->line == sercons.index) {
 			if (ch != 0 &&
 			    time_before(jiffies, break_pressed + HZ*5)) {
-				handle_sysrq(ch, regs, NULL, NULL);
+				handle_sysrq(ch, regs, NULL);
 				break_pressed = 0;
 				goto ignore_char;
 			}
diff -Nru a/drivers/char/sysrq.c b/drivers/char/sysrq.c
--- a/drivers/char/sysrq.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/char/sysrq.c	Tue Jul 16 16:49:42 2002
@@ -45,7 +45,8 @@
 
 /* Loglevel sysrq handler */
 static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs,
-		struct kbd_struct *kbd, struct tty_struct *tty) {
+				  struct tty_struct *tty) 
+{
 	int i;
 	i = key - '0';
 	console_loglevel = 7;
@@ -62,7 +63,8 @@
 /* SAK sysrq handler */
 #ifdef CONFIG_VT
 static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs,
-		struct kbd_struct *kbd, struct tty_struct *tty) {
+			     struct tty_struct *tty) 
+{
 	if (tty)
 		do_SAK(tty);
 	reset_vc(fg_console);
@@ -77,7 +79,10 @@
 
 /* unraw sysrq handler */
 static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs,
-		struct kbd_struct *kbd, struct tty_struct *tty) {
+			       struct tty_struct *tty) 
+{
+	struct kbd_struct *kbd = &kbd_table[fg_console];
+
 	if (kbd)
 		kbd->kbdmode = VC_XLATE;
 }
@@ -90,7 +95,8 @@
 
 /* reboot sysrq handler */
 static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
-		struct kbd_struct *kbd, struct tty_struct *tty) {
+				struct tty_struct *tty) 
+{
 	machine_restart(NULL);
 }
 static struct sysrq_key_op sysrq_reboot_op = {
@@ -218,7 +224,8 @@
 }
 
 static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
-		struct kbd_struct *kbd, struct tty_struct *tty) {
+			      struct tty_struct *tty) 
+{
 	emergency_sync_scheduled = EMERG_SYNC;
 	wakeup_bdflush();
 }
@@ -229,7 +236,8 @@
 };
 
 static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
-		struct kbd_struct *kbd, struct tty_struct *tty) {
+				 struct tty_struct *tty) 
+{
 	emergency_sync_scheduled = EMERG_REMOUNT;
 	wakeup_bdflush();
 }
@@ -245,7 +253,8 @@
 /* SHOW SYSRQ HANDLERS BLOCK */
 
 static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs,
-		struct kbd_struct *kbd, struct tty_struct *tty) {
+				  struct tty_struct *tty) 
+{
 	if (pt_regs)
 		show_regs(pt_regs);
 }
@@ -257,7 +266,8 @@
 
 
 static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs,
-		struct kbd_struct *kbd, struct tty_struct *tty) {
+				   struct tty_struct *tty) 
+{
 	show_state();
 }
 static struct sysrq_key_op sysrq_showstate_op = {
@@ -268,7 +278,8 @@
 
 
 static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs,
-		struct kbd_struct *kbd, struct tty_struct *tty) {
+				 struct tty_struct *tty) 
+{
 	show_mem();
 }
 static struct sysrq_key_op sysrq_showmem_op = {
@@ -296,7 +307,8 @@
 }
 
 static void sysrq_handle_term(int key, struct pt_regs *pt_regs,
-		struct kbd_struct *kbd, struct tty_struct *tty) {
+			      struct tty_struct *tty) 
+{
 	send_sig_all(SIGTERM);
 	console_loglevel = 8;
 }
@@ -307,7 +319,8 @@
 };
 
 static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
-		struct kbd_struct *kbd, struct tty_struct *tty) {
+			      struct tty_struct *tty) 
+{
 	send_sig_all(SIGKILL);
 	console_loglevel = 8;
 }
@@ -416,13 +429,13 @@
  * and any other keycode arrives.
  */
 
-void handle_sysrq(int key, struct pt_regs *pt_regs,
-		  struct kbd_struct *kbd, struct tty_struct *tty) {
+void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
+{
 	if (!sysrq_enabled)
 		return;
 
 	__sysrq_lock_table();
-	__handle_sysrq_nolock(key, pt_regs, kbd, tty);
+	__handle_sysrq_nolock(key, pt_regs, tty);
 	__sysrq_unlock_table();
 }
 
@@ -433,7 +446,8 @@
  */
 
 void __handle_sysrq_nolock(int key, struct pt_regs *pt_regs,
-		  struct kbd_struct *kbd, struct tty_struct *tty) {
+		  	   struct tty_struct *tty) 
+{
 	struct sysrq_key_op *op_p;
 	int orig_log_level;
 	int i, j;
@@ -449,7 +463,7 @@
         if (op_p) {
 		printk ("%s\n", op_p->action_msg);
 		console_loglevel = orig_log_level;
-		op_p->handler(key, pt_regs, kbd, tty);
+		op_p->handler(key, pt_regs, tty);
 	} else {
 		printk("HELP : ");
 		/* Only print the help msg once per handler */
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/char/tty_io.c	Tue Jul 16 16:49:42 2002
@@ -2245,9 +2245,8 @@
 static struct tty_driver dev_ptmx_driver;
 #endif
 #ifdef CONFIG_VT
-extern void con_init_devfs (void);
-extern void console_map_init(void);
 static struct tty_driver dev_console_driver;
+extern int vty_init(void);
 #endif
 
 /*
@@ -2287,13 +2286,6 @@
 	if (tty_register_driver(&dev_syscons_driver))
 		panic("Couldn't register /dev/console driver\n");
 
-	/* console calls tty_register_driver() before kmalloc() works.
-	 * Thus, we can't devfs_register() then.  Do so now, instead. 
-	 */
-#ifdef CONFIG_VT
-	con_init_devfs();
-#endif
-
 #ifdef CONFIG_UNIX98_PTYS
 	dev_ptmx_driver = dev_tty_driver;
 	dev_ptmx_driver.driver_name = "/dev/ptmx";
@@ -2317,10 +2309,7 @@
 
 	if (tty_register_driver(&dev_console_driver))
 		panic("Couldn't register /dev/tty0 driver\n");
-
-	vcs_init();
-	kbd_init();
-	console_map_init();
+	vty_init();
 #endif
 
 #ifdef CONFIG_ESPSERIAL  /* init ESP before rs, so rs doesn't see the port */
diff -Nru a/drivers/fc4/Config.in b/drivers/fc4/Config.in
--- a/drivers/fc4/Config.in	Tue Jul 16 16:49:42 2002
+++ b/drivers/fc4/Config.in	Tue Jul 16 16:49:42 2002
@@ -7,13 +7,13 @@
 tristate 'Fibre Channel and FC4 SCSI support' CONFIG_FC4
 if [ ! "$CONFIG_FC4" = "n" ]; then
    comment 'FC4 drivers'
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC
       tristate 'Sun SOC+ (aka SOCAL)' CONFIG_FC4_SOCAL
    fi
    comment 'FC4 targets'
    dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO $CONFIG_SCSI
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       dep_tristate 'Sun Enterprise Network Array (A5000 and EX500)' CONFIG_SCSI_FCAL $CONFIG_SCSI
    else
       dep_tristate 'Generic FC-AL disk driver' CONFIG_SCSI_FCAL $CONFIG_SCSI
diff -Nru a/drivers/fc4/fc.c b/drivers/fc4/fc.c
--- a/drivers/fc4/fc.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/fc4/fc.c	Tue Jul 16 16:49:42 2002
@@ -994,7 +994,7 @@
 	 */
 
 	fc->rst_pkt->host->eh_action = &sem;
-	fc->rst_pkt->request.rq_status = RQ_SCSI_BUSY;
+	fc->rst_pkt->request->rq_status = RQ_SCSI_BUSY;
 
 	fc->rst_pkt->done = fcp_scsi_reset_done;
 	fcp_scsi_queue_it(fc, fc->rst_pkt, fcmd, 0);
diff -Nru a/drivers/ide/Config.in b/drivers/ide/Config.in
--- a/drivers/ide/Config.in	Tue Jul 16 16:49:43 2002
+++ b/drivers/ide/Config.in	Tue Jul 16 16:49:43 2002
@@ -49,7 +49,7 @@
       dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
       dep_bool '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
       dep_bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_mbool '      HPT34X AUTODMA support (EXPERMENTAL)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_EXPERIMENTAL
+      dep_mbool '      HPT34X AUTODMA support (EXPERIMENTAL)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_EXPERIMENTAL
       dep_bool '    HPT36X/37X chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
       dep_bool '    Intel and Efar (SMsC) chipset support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
       if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
diff -Nru a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
--- a/drivers/ide/aec62xx.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/aec62xx.c	Tue Jul 16 16:49:42 2002
@@ -160,16 +160,15 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int aec62xx_udma_setup(struct ata_device *drive)
+static int __init aec62xx_modes_map(struct ata_channel *ch)
 {
-	u32 bmide = pci_resource_start(drive->channel->pci_dev, 4);
-	short speed;
+	u32 bmide = pci_resource_start(ch->pci_dev, 4);
 	int map;
 
-	map = XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA | XFER_SWDMA | XFER_UDMA;
+	map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA | XFER_UDMA;
 
-	if (drive->channel->udma_four)
-		switch (drive->channel->pci_dev->device) {
+	if (ch->udma_four)
+		switch (ch->pci_dev->device) {
 			case PCI_DEVICE_ID_ARTOP_ATP865R:
 			case PCI_DEVICE_ID_ARTOP_ATP865:
 				/* Can't use these modes simultaneously,
@@ -180,11 +179,7 @@
 				map |= XFER_UDMA_66;
 		}
 
-	speed = ata_timing_mode(drive, map);
-	aec_set_drive(drive, speed);
-	udma_enable(drive, drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO, 0);
-
-	return 0;
+	return map;
 }
 #endif
 
@@ -256,11 +251,12 @@
 
 	ch->tuneproc = aec62xx_tune_drive;
 	ch->speedproc = aec_set_drive;
-	ch->autodma = 0;
 
 	ch->io_32bit = 1;
 	ch->unmask = 1;
 
+	ch->udma_four = aec62xx_ata66_check(ch);
+
 	for (i = 0; i < 2; i++) {
 		ch->drives[i].autotune = 1;
 		ch->drives[i].dn = ch->unit * 2 + i;
@@ -269,11 +265,8 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (ch->dma_base) {
 		ch->highmem = 1;
-		ch->udma_setup = aec62xx_udma_setup;
-#ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			ch->autodma = 1;
-#endif
+		ch->modes_map = aec62xx_modes_map(ch);
+		ch->udma_setup = udma_generic_setup;
 	}
 #endif
 }
@@ -306,17 +299,15 @@
 		vendor: PCI_VENDOR_ID_ARTOP,
 		device: PCI_DEVICE_ID_ARTOP_ATP860,
 		init_chipset: aec62xx_init_chipset,
-		ata66_check: aec62xx_ata66_check,
 		init_channel: aec62xx_init_channel,
 		enablebits: { {0x4a,0x02,0x02},	{0x4a,0x04,0x04} },
 		bootable: NEVER_BOARD,
-		flags: ATA_F_IRQ | ATA_F_NOADMA | ATA_F_DMA
+		flags: ATA_F_IRQ | ATA_F_DMA
 	},
 	{
 		vendor: PCI_VENDOR_ID_ARTOP,
 		device: PCI_DEVICE_ID_ARTOP_ATP860R,
 		init_chipset: aec62xx_init_chipset,
-		ata66_check: aec62xx_ata66_check,
 		init_channel: aec62xx_init_channel,
 		enablebits: { {0x4a,0x02,0x02},	{0x4a,0x04,0x04} },
 		bootable: OFF_BOARD,
@@ -326,7 +317,6 @@
 		vendor: PCI_VENDOR_ID_ARTOP,
 		device: PCI_DEVICE_ID_ARTOP_ATP865,
 		init_chipset: aec62xx_init_chipset,
-		ata66_check: aec62xx_ata66_check,
 		init_channel: aec62xx_init_channel,
 		enablebits: { {0x4a,0x02,0x02},	{0x4a,0x04,0x04} },
 		bootable: NEVER_BOARD,
@@ -336,7 +326,6 @@
 		vendor: PCI_VENDOR_ID_ARTOP,
 		device: PCI_DEVICE_ID_ARTOP_ATP865R,
 		init_chipset: aec62xx_init_chipset,
-		ata66_check: aec62xx_ata66_check,
 		init_channel: aec62xx_init_channel,
 		enablebits: { {0x4a,0x02,0x02},	{0x4a,0x04,0x04} },
 		bootable: OFF_BOARD,
diff -Nru a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
--- a/drivers/ide/alim15x3.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ide/alim15x3.c	Tue Jul 16 16:49:43 2002
@@ -99,43 +99,6 @@
 	__restore_flags(flags);
 }
 
-static byte ali15x3_can_ultra(struct ata_device *drive)
-{
-	if (m5229_revision <= 0x20) {
-		return 0;
-	} else if ((m5229_revision < 0xC2) &&
-#ifndef CONFIG_WDC_ALI15X3
-		((chip_is_1543c_e && strstr(drive->id->model, "WDC ")) ||
-		 (drive->type != ATA_DISK))) {
-#else
-		(drive->type != ATA_DISK)) {
-#endif
-		return 0;
-	} else {
-		return 1;
-	}
-}
-
-static int ali15x3_ratemask(struct ata_device *drive)
-{
-	int map = 0;
-
-	if (!ali15x3_can_ultra(drive))
-		return 0;
-
-	map |= XFER_UDMA;
-
-	if (!eighty_ninty_three(drive))
-		return map;
-
-	if (m5229_revision >= 0xC4)
-		map |= XFER_UDMA_100;
-	if (m5229_revision >= 0xC2)
-		map |= XFER_UDMA_66;
-
-	return map;
-}
-
 static int ali15x3_tune_chipset(struct ata_device *drive, byte speed)
 {
 	struct pci_dev *dev = drive->channel->pci_dev;
@@ -156,6 +119,7 @@
 	if (speed < XFER_SW_DMA_0)
 		ali15x3_tune_drive(drive, speed);
 #ifdef CONFIG_BLK_DEV_IDEDMA
+	/* FIXME: no support for MWDMA and SWDMA modes  --bkz */
 	else if (speed >= XFER_UDMA_0) {
 		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
 		tmpbyte &= (0x0f << ((1-unit) << 2));
@@ -176,91 +140,40 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma(struct ata_device *drive, u8 udma)
+static int ali15x3_udma_setup(struct ata_device *drive, int map)
 {
-	int map;
-	u8 mode;
+#ifndef CONFIG_WDC_ALI15X3
+	if ((m5229_revision < 0xC2) && chip_is_1543c_e &&
+	    strstr(drive->id->model, "WDC "))
+		map &= ~XFER_UDMA_ALL;
+#endif
+	return udma_generic_setup(drive, map);
+}
 
-	if (udma)
-		map = ali15x3_ratemask(drive);
-	else
-		map = XFER_SWDMA | XFER_MWDMA;
-
-	mode = ata_timing_mode(drive, map);
-	if (mode < XFER_SW_DMA_0)
-		return 0;
+static int ali15x3_udma_init(struct ata_device *drive, struct request *rq)
+{
+	if ((m5229_revision < 0xC2) && (drive->type != ATA_DISK))
+		return ATA_OP_FINISHED;	/* try PIO instead of DMA */
 
-	return !ali15x3_tune_chipset(drive, mode);
+	return udma_pci_init(drive, rq);
 }
 
-static int ali15x3_udma_setup(struct ata_device *drive)
+static int __init ali15x3_modes_map(struct ata_channel *ch)
 {
-	struct hd_driveid *id = drive->id;
-	struct ata_channel *hwif = drive->channel;
-	int on = 1;
-	int verbose = 1;
-	byte can_ultra_dma = ali15x3_can_ultra(drive);
-
-	if ((m5229_revision<=0x20) && (drive->type != ATA_DISK)) {
-		udma_enable(drive, 0, 0);
-		return 0;
-	}
-
-	if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (udma_black_list(drive)) {
-			on = 0;
-			goto fast_ata_pio;
-		}
-		on = 0;
-		verbose = 0;
-		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				on = config_chipset_for_dma(drive, can_ultra_dma);
-				if ((id->field_valid & 2) &&
-				    (!on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				on = config_chipset_for_dma(drive, can_ultra_dma);
-				if (!on)
-					goto no_dma_set;
-			}
-		} else if (udma_white_list(drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			on = config_chipset_for_dma(drive, can_ultra_dma);
-			if (!on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		on = 0;
-		verbose = 0;
-no_dma_set:
-		ali15x3_tune_drive(drive, 255);
-	}
+	int map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA;
 
-	udma_enable(drive, on, verbose);
+	if (m5229_revision <= 0x20)
+		return map;
 
-	return 0;
-}
+	map |= XFER_UDMA;
 
-static int ali15x3_udma_init(struct ata_device *drive, struct request *rq)
-{
-	if ((m5229_revision < 0xC2) && (drive->type != ATA_DISK))
-		return ide_stopped;	/* try PIO instead of DMA */
+	if (m5229_revision >= 0xC2) {
+		map |= XFER_UDMA_66;
+		if (m5229_revision >= 0xC4)
+			map |= XFER_UDMA_100;
+	}
 
-	return udma_pci_init(drive, rq);
+	return map;
 }
 #endif
 
@@ -426,6 +339,8 @@
 	}
 #endif /* CONFIG_SPARC64 */
 
+	hwif->udma_four = ali15x3_ata66_check(hwif);
+
 	hwif->tuneproc = &ali15x3_tune_drive;
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
@@ -436,22 +351,21 @@
 		/*
 		 * M1543C or newer for DMAing
 		 */
-		hwif->udma_init = ali15x3_udma_init;
+		hwif->modes_map = ali15x3_modes_map(hwif);
+		if (m5229_revision < 0xC2)
+			hwif->no_atapi_autodma = 1;
 		hwif->udma_setup = ali15x3_udma_setup;
-		hwif->autodma = 1;
+		hwif->udma_init = ali15x3_udma_init;
 	}
-
-	if (noautodma)
-		hwif->autodma = 0;
-#else
-	hwif->autodma = 0;
 #endif
 }
 
 static void __init ali15x3_init_dma(struct ata_channel *ch, unsigned long dmabase)
 {
-	if ((dmabase) && (m5229_revision < 0x20))
+	if (dmabase && (m5229_revision < 0x20)) {
+		ch->autodma = 0;
 		return;
+	}
 
 	ata_init_dma(ch, dmabase);
 }
@@ -472,7 +386,6 @@
 		vendor: PCI_VENDOR_ID_AL,
 	        device: PCI_DEVICE_ID_AL_M5229,
 		init_chipset: ali15x3_init_chipset,
-		ata66_check: ali15x3_ata66_check,
 		init_channel: ali15x3_init_channel,
 		init_dma: ali15x3_init_dma,
 		enablebits: { {0x00,0x00,0x00}, {0x00,0x00,0x00} },
diff -Nru a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
--- a/drivers/ide/amd74xx.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/amd74xx.c	Tue Jul 16 16:49:42 2002
@@ -175,21 +175,15 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int amd74xx_udma_setup(struct ata_device *drive)
+static int __init amd_modes_map(struct ata_channel *ch)
 {
-	short w80 = drive->channel->udma_four;
+	short w80 = ch->udma_four;
+	int map = XFER_EPIO | XFER_MWDMA | XFER_UDMA |
+		  ((amd_config->flags & AMD_BAD_SWDMA) ? 0 : XFER_SWDMA) |
+		  (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_66 ? XFER_UDMA_66 : 0) |
+		  (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0);
 
-	short speed = ata_timing_mode(drive,
-			XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA |
-			((amd_config->flags & AMD_BAD_SWDMA) ? 0 : XFER_SWDMA) |
-			(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_66 ? XFER_UDMA_66 : 0) |
-			(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0));
-
-	amd_set_drive(drive, speed);
-
-	udma_enable(drive, drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO, 0);
-
-	return 0;
+	return map;
 }
 #endif
 
@@ -274,9 +268,10 @@
 {
 	int i;
 
+	hwif->udma_four = amd74xx_ata66_check(hwif);
+
 	hwif->tuneproc = &amd74xx_tune_drive;
 	hwif->speedproc = &amd_set_drive;
-	hwif->autodma = 0;
 
 	hwif->io_32bit = 1;
 	hwif->unmask = 1;
@@ -289,11 +284,8 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
 		hwif->highmem = 1;
-		hwif->udma_setup = amd74xx_udma_setup;
-# ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-# endif
+		hwif->modes_map = amd_modes_map(hwif);
+		hwif->udma_setup = udma_generic_setup;
 	}
 #endif
 }
@@ -314,7 +306,6 @@
 		vendor: PCI_VENDOR_ID_AMD,
 		device: PCI_DEVICE_ID_AMD_COBRA_7401,
 		init_chipset: amd74xx_init_chipset,
-		ata66_check: amd74xx_ata66_check,
 		init_channel: amd74xx_init_channel,
 		init_dma: amd74xx_init_dma,
 		enablebits: {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
@@ -324,7 +315,6 @@
 		vendor:	PCI_VENDOR_ID_AMD,
 		device:	PCI_DEVICE_ID_AMD_VIPER_7409,
 		init_chipset: amd74xx_init_chipset,
-		ata66_check: amd74xx_ata66_check,
 		init_channel: amd74xx_init_channel,
 		init_dma: amd74xx_init_dma,
 		enablebits: {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
@@ -335,7 +325,6 @@
 		vendor:	PCI_VENDOR_ID_AMD,
 		device:	PCI_DEVICE_ID_AMD_VIPER_7411,
 		init_chipset: amd74xx_init_chipset,
-		ata66_check: amd74xx_ata66_check,
 		init_channel: amd74xx_init_channel,
 		init_dma: amd74xx_init_dma,
 		enablebits: {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
@@ -345,7 +334,6 @@
 		vendor:	PCI_VENDOR_ID_AMD,
 		device:	PCI_DEVICE_ID_AMD_OPUS_7441,
 		init_chipset: amd74xx_init_chipset,
-		ata66_check: amd74xx_ata66_check,
 		init_channel: amd74xx_init_channel,
 		init_dma: amd74xx_init_dma,
 		enablebits: {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
@@ -355,7 +343,6 @@
 		vendor:	PCI_VENDOR_ID_AMD,
 		device:	PCI_DEVICE_ID_AMD_8111_IDE,
 		init_chipset: amd74xx_init_chipset,
-		ata66_check: amd74xx_ata66_check,
 		init_channel: amd74xx_init_channel,
 		init_dma: amd74xx_init_dma,
 		enablebits: {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
@@ -365,7 +352,6 @@
 		vendor:	PCI_VENDOR_ID_NVIDIA,
 		device:	PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,
 		init_chipset: amd74xx_init_chipset,
-		ata66_check: amd74xx_ata66_check,
 		init_channel: amd74xx_init_channel,
 		init_dma: amd74xx_init_dma,
 		enablebits: {{0x50,0x01,0x01}, {0x50,0x02,0x02}},
diff -Nru a/drivers/ide/ata-timing.c b/drivers/ide/ata-timing.c
--- a/drivers/ide/ata-timing.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/ata-timing.c	Tue Jul 16 16:49:42 2002
@@ -86,9 +86,11 @@
 		if ((map & XFER_UDMA_100) == XFER_UDMA_100)
 			if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best;
 
-		if ((map & XFER_UDMA_66) == XFER_UDMA_66)
-			if ((best = (id->dma_ultra & 0x0010) ? XFER_UDMA_4 :
-				    (id->dma_ultra & 0x0008) ? XFER_UDMA_3 : 0)) return best;
+		if ((map & XFER_UDMA_66_4) == XFER_UDMA_66_4)
+			if ((best = (id->dma_ultra & 0x0010) ? XFER_UDMA_4 : 0)) return best;
+
+		if ((map & XFER_UDMA_66_3) == XFER_UDMA_66_3)
+			if ((best = (id->dma_ultra & 0x0008) ? XFER_UDMA_3 : 0)) return best;
 
                 if ((best = (id->dma_ultra & 0x0004) ? XFER_UDMA_2 :
 			    (id->dma_ultra & 0x0002) ? XFER_UDMA_1 :
diff -Nru a/drivers/ide/ata-timing.h b/drivers/ide/ata-timing.h
--- a/drivers/ide/ata-timing.h	Tue Jul 16 16:49:43 2002
+++ b/drivers/ide/ata-timing.h	Tue Jul 16 16:49:43 2002
@@ -59,15 +59,22 @@
 #define ENOUGH(v,unit)	(((v)-1)/(unit)+1)
 #define EZ(v,unit)	((v)?ENOUGH(v,unit):0)
 
-#define XFER_MODE	0xf0
-#define XFER_UDMA_133	0x48
-#define XFER_UDMA_100	0x44
-#define XFER_UDMA_66	0x42
-#define XFER_UDMA	0x40
-#define XFER_MWDMA	0x20
-#define XFER_SWDMA	0x10
-#define XFER_EPIO	0x01
-#define XFER_PIO	0x00
+/* see hpt366.c for details */
+#define XFER_UDMA_66_3	0x100
+#define XFER_UDMA_66_4	0x200
+
+#define XFER_MODE	0xff0
+#define XFER_UDMA_133	0x800
+#define XFER_UDMA_100	0x400
+#define XFER_UDMA_66	0x300
+#define XFER_UDMA	0x040
+#define XFER_MWDMA	0x020
+#define XFER_SWDMA	0x010
+#define XFER_EPIO	0x001
+#define XFER_PIO	0x000
+
+#define XFER_UDMA_ALL	0xf40
+#define XFER_UDMA_80W	0xf00
 
 /* External interface to host chips channel timing setup.
  *
diff -Nru a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
--- a/drivers/ide/cmd64x.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/cmd64x.c	Tue Jul 16 16:49:42 2002
@@ -217,10 +217,10 @@
 	ide_config_drive_speed(drive, speed);
 }
 
-static int cmd64x_ratemask(struct ata_device *drive)
+static int __init cmd6xx_modes_map(struct ata_channel *ch)
 {
-	struct pci_dev *dev = drive->channel->pci_dev;
-	int map = 0;
+	struct pci_dev *dev = ch->pci_dev;
+	int map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA;
 
 	switch(dev->device) {
 		case PCI_DEVICE_ID_CMD_680:
@@ -234,10 +234,9 @@
 			break;
 		case PCI_DEVICE_ID_CMD_646:
 		{
-			u32 class_rev;
-			pci_read_config_dword(dev,
-				PCI_CLASS_REVISION, &class_rev);
-			class_rev &= 0xff;
+			u32 rev;
+			pci_read_config_dword(dev, PCI_CLASS_REVISION, &rev);
+			rev &= 0xff;
 		/*
 		 * UltraDMA only supported on PCI646U and PCI646U2, which
 		 * correspond to revisions 0x03, 0x05 and 0x07 respectively.
@@ -250,7 +249,7 @@
 		 *
 		 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
 		 */
-			switch(class_rev) {
+			switch(rev) {
 				case 0x07:
 				case 0x05:
 					map |= XFER_UDMA;
@@ -260,11 +259,6 @@
 		}
 	}
 
-	if (!eighty_ninty_three(drive)) {
-		if (map & XFER_UDMA)
-			return XFER_UDMA;
-		return 0;
-	}
 	return map;
 }
 
@@ -515,80 +509,6 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma(struct ata_device *drive, u8 udma)
-{
-	int map;
-	u8 mode;
-
-	if (udma)
-		map = cmd64x_ratemask(drive);
-	else
-		map = XFER_SWDMA | XFER_MWDMA;
-
-	mode = ata_timing_mode(drive, map);
-
-	return !drive->channel->speedproc(drive, mode);
-}
-
-static int cmd6xx_udma_setup(struct ata_device *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	struct ata_channel *hwif = drive->channel;
-	int on = 1;
-	int verbose = 1;
-
-	hwif->tuneproc(drive, 255);
-
-	if ((id != NULL) && ((id->capability & 1) != 0) &&
-	    hwif->autodma && (drive->type == ATA_DISK)) {
-		/* Consult the list of known "bad" drives */
-		if (udma_black_list(drive)) {
-			on = 0;
-			goto fast_ata_pio;
-		}
-		on = 0;
-		verbose = 0;
-		if ((id->field_valid & 4)) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				on = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (!on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				on = config_chipset_for_dma(drive, 0);
-				if (!on)
-					goto no_dma_set;
-			}
-		} else if (udma_white_list(drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			on = config_chipset_for_dma(drive, 0);
-			if (!on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		on = 0;
-		verbose = 0;
-no_dma_set:
-		hwif->tuneproc(drive, 255);
-	}
-
-	udma_enable(drive, on, verbose);
-
-	return 0;
-}
-
 static int cmd64x_udma_stop(struct ata_device *drive)
 {
 	struct ata_channel *ch = drive->channel;
@@ -822,13 +742,6 @@
 	return (ata66 & mask) ? 1 : 0;
 }
 
-static unsigned int __init cmd64x_ata66_check(struct ata_channel *hwif)
-{
-	if (hwif->pci_dev->device == PCI_DEVICE_ID_CMD_680)
-		return cmd680_ata66(hwif);
-	return cmd64x_ata66(hwif);
-}
-
 static void __init cmd64x_init_channel(struct ata_channel *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
@@ -843,32 +756,28 @@
 	switch(dev->device) {
 		case PCI_DEVICE_ID_CMD_680:
 			hwif->busproc	= cmd680_busproc;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-			if (hwif->dma_base)
-				hwif->udma_setup = cmd6xx_udma_setup;
-#endif
 			hwif->resetproc = cmd680_reset;
 			hwif->speedproc	= cmd680_tune_chipset;
 			hwif->tuneproc	= cmd680_tuneproc;
+			hwif->udma_four = cmd680_ata66(hwif);
 			break;
 		case PCI_DEVICE_ID_CMD_649:
 		case PCI_DEVICE_ID_CMD_648:
 		case PCI_DEVICE_ID_CMD_643:
 #ifdef CONFIG_BLK_DEV_IDEDMA
 			if (hwif->dma_base) {
-				hwif->udma_setup = cmd6xx_udma_setup;
 				hwif->udma_stop	= cmd64x_udma_stop;
 				hwif->udma_irq_status = cmd64x_udma_irq_status;
 			}
 #endif
 			hwif->tuneproc	= cmd64x_tuneproc;
 			hwif->speedproc = cmd64x_tune_chipset;
+			hwif->udma_four = cmd64x_ata66(hwif);
 			break;
 		case PCI_DEVICE_ID_CMD_646:
 			hwif->chipset = ide_cmd646;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 			if (hwif->dma_base) {
-				hwif->udma_setup = cmd6xx_udma_setup;
 				if (class_rev == 0x01) {
 					hwif->udma_stop = cmd646_1_udma_stop;
 				} else {
@@ -879,6 +788,7 @@
 #endif
 			hwif->tuneproc	= cmd64x_tuneproc;
 			hwif->speedproc	= cmd64x_tune_chipset;
+			hwif->udma_four = cmd64x_ata66(hwif);
 			break;
 		default:
 			break;
@@ -887,10 +797,9 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
 		hwif->highmem = 1;
-# ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-# endif
+		hwif->modes_map = cmd6xx_modes_map(hwif);
+		hwif->no_atapi_autodma = 1;
+		hwif->udma_setup = udma_generic_setup;
 	}
 #endif
 }
@@ -919,7 +828,6 @@
 		vendor: PCI_VENDOR_ID_CMD,
 		device: PCI_DEVICE_ID_CMD_648,
 		init_chipset: cmd64x_init_chipset,
-		ata66_check: cmd64x_ata66_check,
 		init_channel: cmd64x_init_channel,
 		bootable: ON_BOARD,
 		flags: ATA_F_DMA
@@ -928,7 +836,6 @@
 		vendor: PCI_VENDOR_ID_CMD,
 		device: PCI_DEVICE_ID_CMD_649,
 		init_chipset: cmd64x_init_chipset,
-		ata66_check: cmd64x_ata66_check,
 		init_channel: cmd64x_init_channel,
 		bootable: ON_BOARD,
 		flags: ATA_F_DMA
@@ -937,7 +844,6 @@
 		vendor: PCI_VENDOR_ID_CMD,
 		device: PCI_DEVICE_ID_CMD_680,
 		init_chipset: cmd64x_init_chipset,
-		ata66_check: cmd64x_ata66_check,
 		init_channel: cmd64x_init_channel,
 		bootable: ON_BOARD,
 		flags: ATA_F_DMA
diff -Nru a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
--- a/drivers/ide/cs5530.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ide/cs5530.c	Tue Jul 16 16:49:43 2002
@@ -191,7 +191,7 @@
 	return 0;
 }
 
-static int cs5530_udma_setup(struct ata_device *drive)
+static int cs5530_udma_setup(struct ata_device *drive, int map)
 {
 	return cs5530_config_dma(drive);
 }
@@ -285,17 +285,15 @@
  */
 static void __init ide_init_cs5530(struct ata_channel *hwif)
 {
+	u32 basereg, d0_timings;
+
 	hwif->serialized = 1;
-	if (!hwif->dma_base) {
-		hwif->autodma = 0;
-	} else {
-		unsigned int basereg, d0_timings;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->udma_setup = cs5530_udma_setup;
-	hwif->highmem = 1;
-#else
-	hwif->autodma = 0;
+	if (hwif->dma_base) {
+		hwif->highmem = 1;
+		hwif->udma_setup = cs5530_udma_setup;
+	}
 #endif
 
 		hwif->tuneproc = &cs5530_tuneproc;
@@ -311,7 +309,6 @@
 			if (!hwif->drives[1].autotune)
 				hwif->drives[1].autotune = 1;	/* needs autotuning later */
 		}
-	}
 }
 
 
diff -Nru a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
--- a/drivers/ide/cy82c693.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/cy82c693.c	Tue Jul 16 16:49:42 2002
@@ -237,7 +237,7 @@
 /*
  * used to set DMA mode for CY82C693 (single and multi modes)
  */
-static int cy82c693_udma_setup(struct ata_device *drive)
+static int cy82c693_udma_setup(struct ata_device *drive, int map)
 {
 	/*
 	 * Set dma mode for drive everything else is done by the defaul func.
@@ -414,14 +414,11 @@
 	hwif->tuneproc = cy82c693_tune_drive;
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
 		hwif->highmem = 1;
 		hwif->udma_setup = cy82c693_udma_setup;
-		if (!noautodma)
-			hwif->autodma = 1;
 	}
 #endif
 }
diff -Nru a/drivers/ide/device.c b/drivers/ide/device.c
--- a/drivers/ide/device.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/device.c	Tue Jul 16 16:49:42 2002
@@ -80,29 +80,7 @@
 }
 
 /*
- * Spin until the drive is no longer busy.
- *
- * Not exported, since it's not used within any modules.
- */
-int ata_busy_poll(struct ata_device *drive, unsigned long timeout)
-{
-	/* spec allows drive 400ns to assert "BUSY" */
-	udelay(1);
-	if (!ata_status(drive, 0, BUSY_STAT)) {
-		timeout += jiffies;
-		while (!ata_status(drive, 0, BUSY_STAT)) {
-			if (time_after(jiffies, timeout))
-				return 1;
-		}
-	}
-
-	return 0;
-}
-
-/*
  * Check the state of the status register.
- *
- * FIXME: Channel lock should be held.
  */
 int ata_status(struct ata_device *drive, u8 good, u8 bad)
 {
@@ -120,31 +98,33 @@
  * all of the "good" bits and none of the "bad" bits, and if all is okay it
  * returns 0.  All other cases return 1 after invoking error handler -- caller
  * should just return.
- *
- * This routine should get fixed to not hog the cpu during extra long waits..
- * That could be done by busy-waiting for the first jiffy or two, and then
- * setting a timer to wake up at half second intervals thereafter, until
- * timeout is achieved, before timing out.
- *
- * Channel lock should be held.
  */
 int ata_status_poll(struct ata_device *drive, u8 good, u8 bad,
-		unsigned long timeout,
-		struct request *rq, ide_startstop_t *startstop)
+		unsigned long timeout, struct request *rq)
 {
 	int i;
 
 	/* bail early if we've exceeded max_failures */
-	if (drive->max_failures && (drive->failures > drive->max_failures)) {
-		*startstop = ide_stopped;
-
-		return 1;
-	}
-
-	if (ata_busy_poll(drive, timeout)) {
-		*startstop = ata_error(drive, rq, "status timeout");
+	if (drive->max_failures && (drive->failures > drive->max_failures))
+		return ATA_OP_FINISHED;
+	/*
+	 * Spin until the drive is no longer busy.
+	 * Spec allows drive 400ns to assert "BUSY"
+	 */
+	udelay(1);
+	if (!ata_status(drive, 0, BUSY_STAT)) {
+		unsigned long flags;
 
-		return 1;
+		__save_flags(flags);
+		ide__sti();
+		timeout += jiffies;
+		while (!ata_status(drive, 0, BUSY_STAT)) {
+			if (time_after(jiffies, timeout)) {
+				__restore_flags(flags);
+				return ata_error(drive, rq, "status timeout");
+			}
+		}
+		__restore_flags(flags);
 	}
 
 	/*
@@ -156,12 +136,10 @@
 	for (i = 0; i < 10; i++) {
 		udelay(1);
 		if (ata_status(drive, good, bad))
-			return 0;
+			return ATA_OP_READY;
 	}
 
-	*startstop = ata_error(drive, rq, "status error");
-
-	return 1;
+	return ata_error(drive, rq, "status error");
 }
 
 EXPORT_SYMBOL(ata_status_poll);
diff -Nru a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c
--- a/drivers/ide/hpt34x.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ide/hpt34x.c	Tue Jul 16 16:49:41 2002
@@ -72,83 +72,13 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma(struct ata_device *drive, u8 udma)
+static int hpt34x_udma_setup(struct ata_device *drive, int map)
 {
-	int map;
-	u8 mode;
-
-	if (drive->type != ATA_DISK)
-		return 0;
-
-	if (udma)
-		map = XFER_UDMA;
-	else
-		map = XFER_SWDMA | XFER_MWDMA;
-
-	mode = ata_timing_mode(drive, map);
-	if (mode < XFER_SW_DMA_0)
-		return 0;
-
-	return !hpt34x_tune_chipset(drive, mode);
-}
-
-static int hpt34x_udma_setup(struct ata_device *drive)
-{
-	struct hd_driveid *id = drive->id;
-	int on = 1;
-	int verbose = 1;
-
-	if (id && (id->capability & 1) && drive->channel->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (udma_black_list(drive)) {
-			on = 0;
-			goto fast_ata_pio;
-		}
-		on = 0;
-		verbose = 0;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x0007) {
-				/* Force if Capable UltraDMA */
-				on = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (!on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				on = config_chipset_for_dma(drive, 0);
-				if (!on)
-					goto no_dma_set;
-			}
-		} else if (udma_white_list(drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			on = config_chipset_for_dma(drive, 0);
-			if (!on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		on = 0;
-		verbose = 0;
-no_dma_set:
-		hpt34x_tune_chipset(drive, ata_best_pio_mode(drive));
-	}
-
-#ifndef CONFIG_HPT34X_AUTODMA
-	if (on)
-		on = 0;
-#endif
-	udma_enable(drive, on, verbose);
-
+#ifdef CONFIG_HPT34X_AUTODMA
+	return udma_generic_setup(drive, map);
+#else
 	return 0;
+#endif
 }
 
 static int hpt34x_udma_stop(struct ata_device *drive)
@@ -173,7 +103,7 @@
 	u8 cmd;
 
 	if (!(count = udma_new_table(drive, rq)))
-		return ide_stopped;	/* try PIO instead of DMA */
+		return ATA_OP_FINISHED;	/* try PIO instead of DMA */
 
 	if (rq_data_dir(rq) == READ)
 		cmd = 0x09;
@@ -189,7 +119,7 @@
 		OUT_BYTE((cmd == 0x09) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 	}
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 #endif
 
@@ -252,24 +182,21 @@
 		unsigned short pcicmd = 0;
 
 		pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
-		if (!noautodma)
-			hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
-		else
-			hwif->autodma = 0;
-
+#ifdef CONFIG_IDEDMA_AUTO
+		hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
+#endif
 		hwif->udma_stop = hpt34x_udma_stop;
 		hwif->udma_init = hpt34x_udma_init;
+		hwif->modes_map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA | XFER_UDMA;
+		hwif->no_atapi_autodma = 1;
 		hwif->udma_setup = hpt34x_udma_setup;
 		hwif->highmem = 1;
-	} else {
+	} else 
+#endif
+	{
 		hwif->drives[0].autotune = 1;
 		hwif->drives[1].autotune = 1;
 	}
-#else
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif
 }
 
 
@@ -281,7 +208,7 @@
 	init_channel:	ide_init_hpt34x,
 	bootable: NEVER_BOARD,
 	extra: 16,
-	flags: ATA_F_NOADMA | ATA_F_DMA
+	flags: ATA_F_DMA
 };
 
 int __init init_hpt34x(void)
diff -Nru a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
--- a/drivers/ide/hpt366.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ide/hpt366.c	Tue Jul 16 16:49:41 2002
@@ -493,37 +493,23 @@
 	return class_rev;
 }
 
-static int hpt3xx_ratemask(struct ata_device *drive)
+static int __init hpt3xx_modes_map(struct ata_channel *ch)
 {
-	u32 rev = hpt_revision(drive->channel->pci_dev);
-	int map = XFER_UDMA;
+	u32 rev = hpt_revision(ch->pci_dev);
+	int map = XFER_EPIO | XFER_MWDMA | XFER_UDMA | XFER_UDMA_66;
 
 	if (rev >= 8) {					/* HPT374 */
 		if (HPT374_ALLOW_ATA133_6)
 			map |= XFER_UDMA_133;
-		map |= (XFER_UDMA_100 | XFER_UDMA_66);
+		map |= XFER_UDMA_100;
 	} else if (rev >= 5) {				/* HPT372 */
 		if (HPT372_ALLOW_ATA133_6)
 			map |= XFER_UDMA_133;
-		map |= (XFER_UDMA_100 | XFER_UDMA_66);
-	} else if (rev >= 4) {				/* HPT370A */
+		map |= XFER_UDMA_100;
+	} else if (rev >= 3) {				/* HPT370A / HPT370 */
 		if (HPT370_ALLOW_ATA100_5)
 			map |= XFER_UDMA_100;
-		map |= XFER_UDMA_66;
-	} else if (rev >= 3) {				/* HPT370 */
-		if (HPT370_ALLOW_ATA100_5)
-			map |= XFER_UDMA_100;
-		map |= XFER_UDMA_66;
-		if (check_in_drive_lists(drive, bad_ata33))
-			return 0;
-	} else {					/* HPT366 and HPT368 */
-		map |= XFER_UDMA_66;
-		if (check_in_drive_lists(drive, bad_ata33))
-			return 0;
-	}
-
-	if (!eighty_ninty_three(drive))
-		return XFER_UDMA;
+	}						/* HPT366 / HPT368 */
 
 	return map;
 }
@@ -662,62 +648,42 @@
 	return ide_config_drive_speed(drive, speed);
 }
 
+/* FIXME: pio == 255 -> ata_best_pio_mode(drive)  --bkz */
 static void hpt3xx_tune_drive(struct ata_device *drive, u8 pio)
 {
 	(void) hpt3xx_tune_chipset(drive, XFER_PIO_0 + min_t(u8, pio, 4));
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma(struct ata_device *drive)
+static int hpt3xx_udma_setup(struct ata_device *drive, int map)
 {
-	int map;
 	u32 rev;
-	u8 mode;
 
 	if (drive->type != ATA_DISK)
 		return 0;
 
 	rev = hpt_revision(drive->channel->pci_dev);
 
-	/* FIXME: check SWDMA modes --bkz */
-	map = hpt3xx_ratemask(drive) | XFER_MWDMA;
-	mode = ata_timing_mode(drive, map);
-
-	/* FIXME: badlists need futher investigation --bkz
-		  bad_ata100_5 is for HPT370/370A,
-		  bad_ata66_4, bad_ata66_3 and bad_ata33 are for HPT366/368
-	 */
-	if (mode == XFER_UDMA_5 && rev < 5) {
-		if (check_in_drive_lists(drive, bad_ata100_5)) {
-			/* FIXME: make XFER_UDMA_66/100/133
-				  independent of XFER_UDMA --bkz */
-			map &= ~XFER_UDMA_100;
-			map |= XFER_UDMA;
-			mode = ata_timing_mode(drive, map);
-		}
-	}
-	if (mode == XFER_UDMA_4 && rev < 3) {
-		if (check_in_drive_lists(drive, bad_ata66_4)) {
-			if (drive->id->dma_ultra & 0x0008) {
-				mode = XFER_UDMA_3;
-			} else {
-				map &= ~XFER_UDMA_66;
-				map |= XFER_UDMA;
-				mode = ata_timing_mode(drive, map);
-			}
-		}
-	}
-	if (mode == XFER_UDMA_3 && rev < 3) {
-		if (check_in_drive_lists(drive, bad_ata66_3)) {
-			map &= ~XFER_UDMA_66;
-			map |= XFER_UDMA;
-			mode = ata_timing_mode(drive, map);
-		}
+	/* FIXME: badlists need futher investigation  --bkz */
+
+	/* bad_ata100_5 is for HPT370/370A,
+	   bad_ata66_4, bad_ata66_3 and bad_ata33 are for HPT366/368 */
+
+	if (rev < 5 && check_in_drive_lists(drive, bad_ata100_5))
+		map &= ~XFER_UDMA_100;
+
+	if (rev < 3) {
+		if (check_in_drive_lists(drive, bad_ata66_4))
+			map &= ~XFER_UDMA_66_4;
+
+		if (check_in_drive_lists(drive, bad_ata66_3))
+			map &= ~XFER_UDMA_66_3;
+
+		if (check_in_drive_lists(drive, bad_ata33))
+			map &= ~XFER_UDMA_ALL;
 	}
-	if (check_in_drive_lists(drive, bad_ata33) && rev < 3)
-		mode = ata_timing_mode(drive, XFER_MWDMA);
 
-	return !hpt3xx_tune_chipset(drive, mode);
+	return udma_generic_setup(drive, map);
 }
 
 static int hpt3xx_quirkproc(struct ata_device *drive)
@@ -754,59 +720,6 @@
 	}
 }
 
-static int hpt3xx_udma_setup(struct ata_device *drive)
-{
-	struct hd_driveid *id = drive->id;
-	int on = 1;
-	int verbose = 1;
-
-	if (id && (id->capability & 1) && drive->channel->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (udma_black_list(drive)) {
-			on = 0;
-			goto fast_ata_pio;
-		}
-		on = 0;
-		verbose = 0;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				on = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (!on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if (id->dma_mword & 0x0007) {
-				/* Force if Capable regular DMA modes */
-				on = config_chipset_for_dma(drive);
-				if (!on)
-					goto no_dma_set;
-			}
-		} else if (udma_white_list(drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			on = config_chipset_for_dma(drive);
-			if (!on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		on = 0;
-		verbose = 0;
-no_dma_set:
-		hpt3xx_tune_chipset(drive, ata_best_pio_mode(drive));
-	}
-	udma_enable(drive, on, verbose);
-
-	return 0;
-}
-
 static void hpt366_udma_irq_lost(struct ata_device *drive)
 {
 	struct pci_dev *dev = drive->channel->pci_dev;
@@ -1232,6 +1145,8 @@
 	struct pci_dev *dev = ch->pci_dev;
 	u32 rev = hpt_revision(dev);
 
+	ch->udma_four = hpt366_ata66_check(ch);
+
 	ch->tuneproc = hpt3xx_tune_drive;
 	ch->speedproc = hpt3xx_tune_chipset;
 	ch->quirkproc = hpt3xx_quirkproc;
@@ -1272,17 +1187,12 @@
 //			ch->resetproc = hpt3xx_reset;
 //			ch->busproc = hpt3xx_tristate;
 		}
+		ch->modes_map = hpt3xx_modes_map(ch);
 		ch->udma_setup = hpt3xx_udma_setup;
-
-		if (!noautodma)
-			ch->autodma = 1;
-		else
-			ch->autodma = 0;
 		ch->highmem = 1;
 	} else
 #endif
 	{
-		ch->autodma = 0;
 		ch->drives[0].autotune = 1;
 		ch->drives[1].autotune = 1;
 	}
@@ -1315,7 +1225,6 @@
 		vendor: PCI_VENDOR_ID_TTI,
 		device: PCI_DEVICE_ID_TTI_HPT366,
 		init_chipset: hpt366_init_chipset,
-		ata66_check: hpt366_ata66_check,
 		init_channel: hpt366_init_channel,
 		init_dma: hpt366_init_dma,
 		bootable: OFF_BOARD,
@@ -1326,7 +1235,6 @@
 		vendor: PCI_VENDOR_ID_TTI,
 		device: PCI_DEVICE_ID_TTI_HPT372,
 		init_chipset: hpt366_init_chipset,
-		ata66_check: hpt366_ata66_check,
 		init_channel: hpt366_init_channel,
 		init_dma: hpt366_init_dma,
 		bootable: OFF_BOARD,
@@ -1337,7 +1245,6 @@
 		vendor: PCI_VENDOR_ID_TTI,
 		device: PCI_DEVICE_ID_TTI_HPT374,
 		init_chipset: hpt366_init_chipset,
-		ata66_check: hpt366_ata66_check,
 		init_channel: hpt366_init_channel,
 		init_dma: hpt366_init_dma,
 		bootable: OFF_BOARD,
diff -Nru a/drivers/ide/icside.c b/drivers/ide/icside.c
--- a/drivers/ide/icside.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ide/icside.c	Tue Jul 16 16:49:41 2002
@@ -405,7 +405,7 @@
 #endif
 }
 
-static int icside_dma_check(struct ata_device *drive)
+static int icside_dma_check(struct ata_device *drive, int map)
 {
 	struct hd_driveid *id = drive->id;
 	struct ata_channel *ch = drive->channel;
@@ -466,7 +466,7 @@
 	if (ata_status(drive, DRIVE_READY, drive->bad_wstat | DRQ_STAT)) {
 		if (!dma_stat) {
 			__ide_end_request(drive, rq, 1, rq->nr_sectors);
-			return ide_stopped;
+			return ATA_OP_FINISHED;
 		}
 		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n",
 		       drive->name, dma_stat);
@@ -516,10 +516,10 @@
 	u8 int cmd;
 
 	if (icside_dma_common(drive, rq, DMA_MODE_WRITE))
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 
 	if (drive->type != ATA_DISK)
-		return ide_started;
+		return ATA_OP_CONTINUES;
 
 	ata_set_handler(drive, icside_dmaintr, WAIT_CMD, NULL);
 
@@ -535,7 +535,7 @@
 
 	enable_dma(ch->hw.dma);
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 static int icside_irq_status(struct ata_device *drive)
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/ide-cd.c	Tue Jul 16 16:49:42 2002
@@ -556,7 +556,7 @@
 	if ((rq->flags & REQ_CMD) && !rq->current_nr_sectors)
 		uptodate = 1;
 
-	ata_end_request(drive, rq, uptodate);
+	__ata_end_request(drive, rq, uptodate, 0);
 }
 
 
@@ -581,7 +581,7 @@
 
 	if (rq == NULL) {
 		printk("%s: missing rq in %s\n", drive->name, __FUNCTION__);
-		*startstop = ide_stopped;
+		*startstop = ATA_OP_FINISHED;
 		return 1;
 	}
 
@@ -688,14 +688,12 @@
 		blk_dump_rq_flags(rq, "ide-cd bad flags");
 
 	/* Retry, or handle the next request. */
-	*startstop = ide_stopped;
+	*startstop = ATA_OP_FINISHED;
 	return 1;
 }
 
-static int cdrom_timer_expiry(struct ata_device *drive, struct request *rq)
+static ide_startstop_t cdrom_timer_expiry(struct ata_device *drive, struct request *rq, unsigned long *wait)
 {
-	unsigned long wait = 0;
-
 	/*
 	 * Some commands are *slow* and normally take a long time to
 	 * complete. Usually we can use the ATAPI "disconnect" to bypass
@@ -706,14 +704,14 @@
 		case GPCMD_BLANK:
 		case GPCMD_FORMAT_UNIT:
 		case GPCMD_RESERVE_RZONE_TRACK:
-			wait = WAIT_CMD;
-			break;
+			*wait = WAIT_CMD;
+			return ATA_OP_CONTINUES;
 		default:
-			wait = 0;
+			*wait = 0;
 			break;
 	}
 
-	return wait;
+	return ATA_OP_FINISHED;
 }
 
 /* Set up the device registers for transferring a packet command on DEV,
@@ -728,51 +726,40 @@
 						  int xferlen,
 						  ata_handler_t handler)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
-	ide_startstop_t startstop;
 	struct cdrom_info *info = drive->driver_data;
 	int ret;
 
-	spin_lock_irqsave(ch->lock, flags);
 	/* Wait for the controller to be idle. */
-	if (ata_status_poll(drive, 0, BUSY_STAT, WAIT_READY, rq, &startstop))
-		ret = startstop;
-	else {
-		if (info->dma) {
-			if (info->cmd == READ || info->cmd == WRITE)
-				info->dma = udma_init(drive, rq);
-			else
-				printk("ide-cd: DMA set, but not allowed\n");
-		}
+	ret = ata_status_poll(drive, 0, BUSY_STAT, WAIT_READY, rq);
+	if (ret != ATA_OP_READY)
+		return ret;
 
-		/* Set up the controller registers. */
-		OUT_BYTE(info->dma, IDE_FEATURE_REG);
-		OUT_BYTE(0, IDE_NSECTOR_REG);
-		OUT_BYTE(0, IDE_SECTOR_REG);
-
-		OUT_BYTE(xferlen & 0xff, IDE_LCYL_REG);
-		OUT_BYTE(xferlen >> 8  , IDE_HCYL_REG);
-		ata_irq_enable(drive, 1);
-		if (info->dma)
-			udma_start(drive, rq);
-
-		if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
-			ata_set_handler(drive, handler, WAIT_CMD, cdrom_timer_expiry);
-			OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-			ret = ide_started;
-		} else {
-			OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+	if (info->dma) {
+		if (info->cmd == READ || info->cmd == WRITE)
+			info->dma = udma_init(drive, rq);
+		else
+			printk("ide-cd: DMA set, but not allowed\n");
+	}
+
+	/* Set up the controller registers. */
+	OUT_BYTE(info->dma, IDE_FEATURE_REG);
+	OUT_BYTE(0, IDE_NSECTOR_REG);
+	OUT_BYTE(0, IDE_SECTOR_REG);
+
+	OUT_BYTE(xferlen & 0xff, IDE_LCYL_REG);
+	OUT_BYTE(xferlen >> 8  , IDE_HCYL_REG);
+	ata_irq_enable(drive, 1);
+	if (info->dma)
+		udma_start(drive, rq);
 
-			/* FIXME: Oj kurwa! We have to ungrab the lock before
-			 * the IRQ handler gets called.
-			 */
-			spin_unlock_irqrestore(ch->lock, flags);
-			ret = handler(drive, rq);
-			spin_lock_irqsave(ch->lock, flags);
-		}
+	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+		ata_set_handler(drive, handler, WAIT_CMD, cdrom_timer_expiry);
+		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		ret = ATA_OP_CONTINUES;
+	} else {
+		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		ret = handler(drive, rq);
 	}
-	spin_unlock_irqrestore(ch->lock, flags);
 
 	return ret;
 }
@@ -787,8 +774,6 @@
 		unsigned char *cmd, unsigned long timeout,
 		ata_handler_t handler)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	ide_startstop_t startstop;
 
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
@@ -800,26 +785,18 @@
 		if (cdrom_decode_status(&startstop, drive, rq, DRQ_STAT, &stat_dum))
 			return startstop;
 	} else {
-		/* FIXME: make this locking go away */
-		spin_lock_irqsave(ch->lock, flags);
 		/* Otherwise, we must wait for DRQ to get set. */
-		if (ata_status_poll(drive, DRQ_STAT, BUSY_STAT,
-					WAIT_READY, rq, &startstop)) {
-			spin_unlock_irqrestore(ch->lock, flags);
-
+		startstop = ata_status_poll(drive, DRQ_STAT, BUSY_STAT,
+				WAIT_READY, rq);
+		if (startstop != ATA_OP_READY)
 			return startstop;
-		}
-		spin_unlock_irqrestore(ch->lock, flags);
 	}
 
 	/* Arm the interrupt handler and send the command to the device. */
-	/* FIXME: make this locking go away */
-	spin_lock_irqsave(ch->lock, flags);
 	ata_set_handler(drive, handler, timeout, cdrom_timer_expiry);
 	atapi_write(drive, cmd, CDROM_PACKET_SIZE);
-	spin_unlock_irqrestore(ch->lock, flags);
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 /****************************************************************************
@@ -917,8 +894,6 @@
  */
 static ide_startstop_t cdrom_read_intr(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	int stat;
 	int ireason, len, sectors_to_transfer, nskip;
 	struct cdrom_info *info = drive->driver_data;
@@ -937,15 +912,9 @@
 
 	if (dma) {
 		if (!dma_error) {
-			/* FIXME: this locking should encompass the above register
-			 * file access too.
-			 */
-
-			spin_lock_irqsave(ch->lock, flags);
 			__ata_end_request(drive, rq, 1, rq->nr_sectors);
-			spin_unlock_irqrestore(ch->lock, flags);
 
-			return ide_stopped;
+			return ATA_OP_FINISHED;
 		} else
 			return ata_error(drive, rq, "dma error");
 	}
@@ -964,12 +933,12 @@
 			cdrom_end_request(drive, rq, 0);
 		} else
 			cdrom_end_request(drive, rq, 1);
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	/* Check that the drive is expecting to do the same thing we are. */
 	if (cdrom_read_check_ireason(drive, rq, len, ireason))
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 
 	/* Assume that the drive will always provide data in multiples
 	   of at least SECTOR_SIZE, as it gets hairy to keep track
@@ -984,7 +953,7 @@
 			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
 		}
 		cdrom_end_request(drive, rq, 0);
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	/* The number of sectors we need to read from the drive. */
@@ -1040,11 +1009,9 @@
 	}
 
 	/* Done moving data! Wait for another interrupt. */
-	spin_lock_irqsave(ch->lock, flags);
 	ata_set_handler(drive, cdrom_read_intr, WAIT_CMD, NULL);
-	spin_unlock_irqrestore(ch->lock, flags);
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 /*
@@ -1132,7 +1099,7 @@
 			printk ("%s: %s: buffer botch (%u)\n",
 				drive->name, __FUNCTION__, rq->current_nr_sectors);
 			cdrom_end_request(drive, rq, 0);
-			return ide_stopped;
+			return ATA_OP_FINISHED;
 		}
 		sector -= nskip;
 		nsect += nskip;
@@ -1181,7 +1148,7 @@
 			drive->dsc_overlap = 0;
 		}
 	}
-	return ide_stopped;
+	return ATA_OP_FINISHED;
 }
 
 static ide_startstop_t cdrom_start_seek_continuation(struct ata_device *drive, struct request *rq)
@@ -1243,7 +1210,7 @@
 
 	/* Satisfy whatever we can of this request from our cached sector. */
 	if (cdrom_read_from_buffer(drive, rq))
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 
 	blk_attempt_remerge(&drive->queue, rq);
 
@@ -1269,8 +1236,6 @@
 /* Interrupt routine for packet command completion. */
 static ide_startstop_t cdrom_pc_intr(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	int ireason, len, stat, thislen;
 
 	/* FIXME --mdcki */
@@ -1312,7 +1277,7 @@
 			pc->stat = 1;
 			cdrom_end_request(drive, rq, 1);
 		}
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	/* Figure out how much data to transfer. */
@@ -1363,11 +1328,9 @@
 	}
 
 	/* Now we wait for another interrupt. */
-	spin_lock_irqsave(ch->lock, flags);
 	ata_set_handler(drive, cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
-	spin_unlock_irqrestore(ch->lock, flags);
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 static ide_startstop_t cdrom_do_pc_continuation(struct ata_device *drive, struct request *rq)
@@ -1508,8 +1471,6 @@
 
 static ide_startstop_t cdrom_write_intr(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	int stat, ireason, len, sectors_to_transfer, uptodate;
 	struct cdrom_info *info = drive->driver_data;
 	int dma_error = 0, dma = info->dma;
@@ -1536,15 +1497,9 @@
 		if (dma_error)
 			return ata_error(drive, rq, "dma error");
 
-		/* FIXME: this locking should encompass the above register
-		 * file access too.
-		 */
-
-		spin_lock_irqsave(ch->lock, flags);
 		__ata_end_request(drive, rq, 1, rq->nr_sectors);
-		spin_unlock_irqrestore(ch->lock, flags);
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	/* Read the interrupt reason and the transfer length. */
@@ -1563,13 +1518,13 @@
 			uptodate = 0;
 		}
 		cdrom_end_request(drive, rq, uptodate);
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	/* Check that the drive is expecting to do the same thing we are. */
 	if (ireason & 3)
 		if (cdrom_write_check_ireason(drive, rq, len, ireason))
-			return ide_stopped;
+			return ATA_OP_FINISHED;
 
 	sectors_to_transfer = len / SECTOR_SIZE;
 
@@ -1607,11 +1562,9 @@
 	}
 
 	/* re-arm handler */
-	spin_lock_irqsave(ch->lock, flags);
 	ata_set_handler(drive, cdrom_write_intr, 5 * WAIT_CMD, NULL);
-	spin_unlock_irqrestore(ch->lock, flags);
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 static ide_startstop_t cdrom_start_write_cont(struct ata_device *drive, struct request *rq)
@@ -1628,7 +1581,7 @@
 	 */
 	if ((rq->nr_sectors & 3) || (rq->sector & 3)) {
 		cdrom_end_request(drive, rq, 0);
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	/*
@@ -1658,7 +1611,6 @@
 static ide_startstop_t
 ide_cdrom_do_request(struct ata_device *drive, struct request *rq, sector_t block)
 {
-	struct ata_channel *ch = drive->channel;
 	int ret;
 	struct cdrom_info *info = drive->driver_data;
 
@@ -1669,14 +1621,12 @@
 			if (!ata_status(drive, SEEK_STAT, 0)) {
 				if (elpased < IDECD_SEEK_TIMEOUT) {
 					ide_stall_queue(drive, IDECD_SEEK_TIMER);
-					return ide_stopped;
+					return ATA_OP_FINISHED;
 				}
 				printk ("%s: DSC timeout\n", drive->name);
 			}
 			CDROM_CONFIG_FLAGS(drive)->seeking = 0;
 		}
-		/* FIXME: make this unlocking go away*/
-		spin_unlock_irq(ch->lock);
 		if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) {
 			ret = cdrom_start_seek(drive, rq, block);
 		} else {
@@ -1686,13 +1636,9 @@
 				ret = cdrom_start_write(drive, rq);
 		}
 		info->last_block = block;
-		spin_lock_irq(ch->lock);
 		return ret;
 	} else if (rq->flags & (REQ_PC | REQ_SENSE)) {
-		/* FIXME: make this unlocking go away*/
-		spin_unlock_irq(ch->lock);
 		ret = cdrom_do_packet_command(drive, rq);
-		spin_lock_irq(ch->lock);
 
 		return ret;
 	} else if (rq->flags & REQ_SPECIAL) {
@@ -1703,12 +1649,9 @@
 		 * right now this can only be a reset...
 		 */
 
-	        /* FIXME: make this unlocking go away*/
-		spin_unlock_irq(ch->lock);
 		cdrom_end_request(drive, rq, 1);
-		spin_lock_irq(ch->lock);
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	} else if (rq->flags & REQ_BLOCK_PC) {
 		struct packet_command pc;
 		ide_startstop_t startstop;
@@ -1720,10 +1663,7 @@
 		/* FIXME --mdcki */
 		rq->special = (char *) &pc;
 
-		/* FIXME: make this unlocking go away*/
-		spin_unlock_irq(ch->lock);
 		startstop = cdrom_do_packet_command(drive, rq);
-		spin_lock_irq(ch->lock);
 
 		if (pc.stat)
 			++rq->errors;
@@ -1732,12 +1672,10 @@
 	}
 
 	blk_dump_rq_flags(rq, "ide-cd bad flags");
-	/* FIXME: make this unlocking go away*/
-	spin_unlock_irq(ch->lock);
+
 	cdrom_end_request(drive, rq, 0);
-	spin_lock_irq(ch->lock);
 
-	return ide_stopped;
+	return ATA_OP_FINISHED;
 }
 
 
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ide/ide-disk.c	Tue Jul 16 16:49:41 2002
@@ -11,8 +11,6 @@
  * This is the ATA disk device driver, as evolved from hd.c and ide.c.
  */
 
-#define IDEDISK_VERSION	"1.14"
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -41,6 +39,24 @@
 #endif
 
 /*
+ * for now, taskfile requests are special :/
+ */
+static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
+{
+	if (rq->bio)
+		return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
+	else
+		return rq->buffer + ((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE;
+}
+
+static inline void ide_unmap_rq(struct request *rq, char *to,
+				unsigned long *flags)
+{
+	if (rq->bio)
+		bio_kunmap_irq(to, flags);
+}
+
+/*
  * Perform a sanity check on the claimed "lba_capacity"
  * value for this drive (from its reported identification information).
  *
@@ -95,25 +111,17 @@
  */
 static ide_startstop_t task_in_intr(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	int ret;
 
-	spin_lock_irqsave(ch->lock, flags);
-
 	if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
-		if (drive->status & (ERR_STAT | DRQ_STAT)) {
-			spin_unlock_irqrestore(ch->lock, flags);
-
+		if (drive->status & (ERR_STAT | DRQ_STAT))
 			return ata_error(drive, rq, __FUNCTION__);
-		}
 
 		/* no data yet, so wait for another interrupt */
 		ata_set_handler(drive, task_in_intr, WAIT_CMD, NULL);
 
-		ret = ide_started;
+		ret = ATA_OP_CONTINUES;
 	} else {
-
 		//	printk("Read: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
 		{
 			unsigned long flags;
@@ -134,18 +142,16 @@
 		if (rq->current_nr_sectors <= 0) {
 			if (!__ata_end_request(drive, rq, 1, 0)) {
 			//		printk("Request Ended stat: %02x\n", drive->status);
-				spin_unlock_irqrestore(ch->lock, flags);
 
-				return ide_stopped;
+				return ATA_OP_FINISHED;
 			}
 		}
 
 		/* still data left to transfer */
 		ata_set_handler(drive, task_in_intr,  WAIT_CMD, NULL);
 
-		ret = ide_started;
+		ret = ATA_OP_CONTINUES;
 	}
-	spin_unlock_irqrestore(ch->lock, flags);
 
 	return ret;
 }
@@ -155,19 +161,13 @@
  */
 static ide_startstop_t task_out_intr(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	int ret;
 
-	spin_lock_irqsave(ch->lock, flags);
-	if (!ata_status(drive, DRIVE_READY, drive->bad_wstat)) {
-		spin_unlock_irqrestore(ch->lock, flags);
-
+	if (!ata_status(drive, DRIVE_READY, drive->bad_wstat))
 		return ata_error(drive, rq, __FUNCTION__);
-	}
 
 	if (!rq->current_nr_sectors && !__ata_end_request(drive, rq, 1, 0)) {
-		ret = ide_stopped;
+		ret = ATA_OP_FINISHED;
 	} else {
 		if ((rq->nr_sectors == 1) != (drive->status & DRQ_STAT)) {
 			unsigned long flags;
@@ -183,9 +183,8 @@
 		}
 		ata_set_handler(drive, task_out_intr, WAIT_CMD, NULL);
 
-		ret = ide_started;
+		ret = ATA_OP_CONTINUES;
 	}
-	spin_unlock_irqrestore(ch->lock, flags);
 
 	return ret;
 }
@@ -195,22 +194,16 @@
  */
 static ide_startstop_t task_mulin_intr(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	int ret;
 
-	spin_lock_irqsave(ch->lock, flags);
 	if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
-		if (drive->status & (ERR_STAT | DRQ_STAT)) {
-			spin_unlock_irqrestore(ch->lock, flags);
-
+		if (drive->status & (ERR_STAT | DRQ_STAT))
 			return ata_error(drive, rq, __FUNCTION__);
-		}
 
 		/* no data yet, so wait for another interrupt */
 		ata_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
 
-		ret = ide_started;
+		ret = ATA_OP_CONTINUES;
 	} else {
 		unsigned int msect;
 
@@ -242,11 +235,8 @@
 
 			/* FIXME: this seems buggy */
 			if (rq->current_nr_sectors <= 0) {
-				if (!__ata_end_request(drive, rq, 1, 0)) {
-					spin_unlock_irqrestore(ch->lock, flags);
-
-					return ide_stopped;
-				}
+				if (!__ata_end_request(drive, rq, 1, 0))
+					return ATA_OP_FINISHED;
 			}
 			msect -= nsect;
 		} while (msect);
@@ -254,22 +244,17 @@
 		/* more data left */
 		ata_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
 
-		ret = ide_started;
+		ret = ATA_OP_CONTINUES;
 	}
-	spin_unlock_irqrestore(ch->lock, flags);
 
 	return ret;
 }
 
 static ide_startstop_t task_mulout_intr(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	int ok;
 	int ret;
 
-	spin_lock_irqsave(ch->lock, flags);
-
 	/*
 	 * FIXME: the drive->status checks here seem to be messy.
 	 *
@@ -280,24 +265,24 @@
 	ok = ata_status(drive, DATA_READY, BAD_R_STAT);
 
 	if (!ok || !rq->nr_sectors) {
-		if (drive->status & (ERR_STAT | DRQ_STAT)) {
-			spin_unlock_irqrestore(ch->lock, flags);
-
+		if (drive->status & (ERR_STAT | DRQ_STAT))
 			return ata_error(drive, rq, __FUNCTION__);
-		}
 	}
 	if (!rq->nr_sectors) {
 		__ata_end_request(drive, rq, 1, rq->hard_nr_sectors);
 		rq->bio = NULL;
-		ret = ide_stopped;
+		ret = ATA_OP_FINISHED;
 	} else if (!ok) {
-		/* no data yet, so wait for another interrupt */
-		if (!ch->handler)
-			ata_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
-		ret = ide_started;
+		/* not ready yet, so wait for next IRQ */
+		ata_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
+
+		ret = ATA_OP_CONTINUES;
 	} else {
 		int mcount = drive->mult_count;
 
+		/* prepare for next IRQ */
+		ata_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
+
 		do {
 			char *buf;
 			int nsect = rq->current_nr_sectors;
@@ -325,6 +310,7 @@
 					rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
 				}
 			}
+			rq->errors = 0; /* FIXME: why?  --bzolnier */
 
 			/*
 			 * Ok, we're all setup for the interrupt re-entering us on the
@@ -334,31 +320,209 @@
 			bio_kunmap_irq(buf, &flags);
 		} while (mcount);
 
-		rq->errors = 0;
-
-		if (!ch->handler)
-			ata_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
-
-		ret = ide_started;
+		ret = ATA_OP_CONTINUES;
 	}
-	spin_unlock_irqrestore(ch->lock, flags);
 
-	return ide_started;
+	return ret;
 }
 
 /*
- * Channel lock should be held on entry.
+ * Issue a READ or WRITE command to a disk, using LBA if supported, or CHS
+ * otherwise, to address sectors.  It also takes care of issuing special
+ * DRIVE_CMDs.
  */
-static ide_startstop_t __do_request(struct ata_device *drive,
-		struct ata_taskfile *ar, struct request *rq)
+static ide_startstop_t idedisk_do_request(struct ata_device *drive, struct request *rq, sector_t block)
 {
+	struct ata_taskfile args;
+	struct ata_taskfile *ar;
 	struct hd_driveid *id = drive->id;
+	u8 cmd;
+
+	/* Special drive commands don't need any kind of setup.
+	 */
+	if (rq->flags & REQ_SPECIAL) {
+		ar = rq->special;
+		cmd  = ar->cmd;
+	} else  {
+		unsigned int sectors;
+
+		/* FIXME: this check doesn't make sense */
+		if (!(rq->flags & REQ_CMD)) {
+			blk_dump_rq_flags(rq, "idedisk_do_request - bad command");
+			__ata_end_request(drive, rq, 0, 0);
+
+			return ATA_OP_FINISHED;
+		}
+
+		if (IS_PDC4030_DRIVE) {
+			extern ide_startstop_t promise_do_request(struct ata_device *, struct request *, sector_t);
+
+			return promise_do_request(drive, rq, block);
+		}
+
+		/*
+		 * start a tagged operation
+		 */
+		if (drive->using_tcq) {
+			int st = blk_queue_start_tag(&drive->queue, rq);
+
+			if (ata_pending_commands(drive) > drive->max_depth)
+				drive->max_depth = ata_pending_commands(drive);
+			if (ata_pending_commands(drive) > drive->max_last_depth)
+				drive->max_last_depth = ata_pending_commands(drive);
+
+			if (st) {
+				BUG_ON(!ata_pending_commands(drive));
+
+				return ATA_OP_CONTINUES;
+			}
+		}
+		ar = &args;
+
+		memset(&args, 0, sizeof(args));
+		sectors = rq->nr_sectors;
+		/* Dispatch depending up on the drive access method. */
+		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
+			/* LBA 48 bit */
+			/*
+			 * 268435455  == 137439 MB or 28bit limit
+			 * 320173056  == 163929 MB or 48bit addressing
+			 * 1073741822 == 549756 MB or 48bit addressing fake drive
+			 */
+			if (sectors == 65536)
+				sectors = 0;
+
+			if (blk_rq_tagged(rq)) {
+				args.taskfile.feature = sectors;
+				args.hobfile.feature = sectors >> 8;
+				args.taskfile.sector_count = rq->tag << 3;
+			} else {
+				args.taskfile.sector_count = sectors;
+				args.hobfile.sector_count = sectors >> 8;
+			}
+
+			args.taskfile.sector_number = block;		/* low lba */
+			args.taskfile.low_cylinder = (block >>= 8);	/* mid lba */
+			args.taskfile.high_cylinder = (block >>= 8);	/* hi  lba */
+			args.taskfile.device_head = drive->select.all;
+
+			args.hobfile.sector_number = (block >>= 8);	/* low lba */
+			args.hobfile.low_cylinder = (block >>= 8);	/* mid lba */
+			args.hobfile.high_cylinder = (block >>= 8);	/* hi  lba */
+		} else if (drive->select.b.lba) {
+			/* LBA 28 bit  */
+			if (sectors == 256)
+				sectors = 0;
+
+			if (blk_rq_tagged(rq)) {
+				args.taskfile.feature = sectors;
+				args.taskfile.sector_count = rq->tag << 3;
+			} else
+				args.taskfile.sector_count = sectors;
+
+			args.taskfile.sector_number = block;
+			args.taskfile.low_cylinder = (block >>= 8);
+			args.taskfile.high_cylinder = (block >>= 8);
+			args.taskfile.device_head = ((block >> 8) & 0x0f);
+		} else {
+			/* CHS */
+			unsigned int track	= (block / drive->sect);
+			unsigned int sect	= (block % drive->sect) + 1;
+			unsigned int head	= (track % drive->head);
+			unsigned int cyl	= (track / drive->head);
+
+			if (sectors == 256)
+				sectors = 0;
+
+			if (blk_rq_tagged(rq)) {
+				args.taskfile.feature = sectors;
+				args.taskfile.sector_count = rq->tag << 3;
+			} else
+				args.taskfile.sector_count = sectors;
+
+			args.taskfile.sector_number = sect;
+			args.taskfile.low_cylinder = cyl;
+			args.taskfile.high_cylinder = (cyl>>8);
+			args.taskfile.device_head = head;
+		}
+		args.taskfile.device_head |= drive->select.all;
+
+		/*
+		 * Decode with physical ATA command to use and setup associated data.
+		 */
+
+		if (rq_data_dir(rq) == READ) {
+			args.command_type = IDE_DRIVE_TASK_IN;
+			if (drive->addressing) {
+				if (drive->using_tcq) {
+					cmd = WIN_READDMA_QUEUED_EXT;
+				} else if (drive->using_dma) {
+					cmd = WIN_READDMA_EXT;
+				} else if (drive->mult_count) {
+					args.XXX_handler = task_mulin_intr;
+					cmd = WIN_MULTREAD_EXT;
+				} else {
+					args.XXX_handler = task_in_intr;
+					cmd = WIN_READ_EXT;
+				}
+			} else {
+				if (drive->using_tcq) {
+					cmd = WIN_READDMA_QUEUED;
+				} else if (drive->using_dma) {
+					cmd = WIN_READDMA;
+				} else if (drive->mult_count) {
+					args.XXX_handler = task_mulin_intr;
+					cmd = WIN_MULTREAD;
+				} else {
+					args.XXX_handler = task_in_intr;
+					cmd = WIN_READ;
+				}
+			}
+		} else {
+			args.command_type = IDE_DRIVE_TASK_RAW_WRITE;
+			if (drive->addressing) {
+				if (drive->using_tcq) {
+					cmd = WIN_WRITEDMA_QUEUED_EXT;
+				} else if (drive->using_dma) {
+					cmd = WIN_WRITEDMA_EXT;
+				} else if (drive->mult_count) {
+					args.XXX_handler = task_mulout_intr;
+					cmd = WIN_MULTWRITE_EXT;
+				} else {
+					args.XXX_handler = task_out_intr;
+					cmd = WIN_WRITE_EXT;
+				}
+			} else {
+				if (drive->using_tcq) {
+					cmd = WIN_WRITEDMA_QUEUED;
+				} else if (drive->using_dma) {
+					cmd = WIN_WRITEDMA;
+				} else if (drive->mult_count) {
+					args.XXX_handler = task_mulout_intr;
+					cmd = WIN_MULTWRITE;
+				} else {
+					args.XXX_handler = task_out_intr;
+					cmd = WIN_WRITE;
+				}
+			}
+		}
+#ifdef DEBUG
+		printk("%s: %sing: ", drive->name,
+				(rq_data_dir(rq)==READ) ? "read" : "writ");
+		if (lba)	printk("LBAsect=%lld, ", block);
+		else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
+		printk("sectors=%ld, ", rq->nr_sectors);
+		printk("buffer=%p\n", rq->buffer);
+#endif
+	ar->cmd = cmd;
+	rq->special = ar;
+	}
 
 	/* (ks/hs): Moved to start, do not use for multiple out commands.
 	 * FIXME: why not?! */
-	if (!(ar->cmd == CFA_WRITE_MULTI_WO_ERASE ||
-	      ar->cmd == WIN_MULTWRITE ||
-	      ar->cmd == WIN_MULTWRITE_EXT)) {
+	if (!(cmd == CFA_WRITE_MULTI_WO_ERASE ||
+	      cmd == WIN_MULTWRITE ||
+	      cmd == WIN_MULTWRITE_EXT)) {
 		ata_irq_enable(drive, 1);
 		ata_mask(drive);
 	}
@@ -372,57 +536,58 @@
 	OUT_BYTE((ar->taskfile.device_head & (drive->addressing ? 0xE0 : 0xEF)) | drive->select.all,
 			IDE_SELECT_REG);
 
+	/* FIXME: this is actually distingushing between PIO and DMA requests.
+	 */
 	if (ar->XXX_handler) {
-		struct ata_channel *ch = drive->channel;
+		if (ar->command_type == IDE_DRIVE_TASK_IN ||
+		    ar->command_type == IDE_DRIVE_TASK_NO_DATA) {
 
-		ata_set_handler(drive, ar->XXX_handler, WAIT_CMD, NULL);
-		OUT_BYTE(ar->cmd, IDE_COMMAND_REG);
+			ata_set_handler(drive, ar->XXX_handler, WAIT_CMD, NULL);
+			OUT_BYTE(cmd, IDE_COMMAND_REG);
+
+			return ATA_OP_CONTINUES;
+		}
 
 		/* FIXME: Warning check for race between handler and prehandler
 		 * for writing first block of data.  however since we are well
 		 * inside the boundaries of the seek, we should be okay.
-		 *
-		 * FIXME: Replace the switch by using a proper command_type.
+		 * FIXME: should be fixed  --bzolnier
 		 */
+		if (ar->command_type == IDE_DRIVE_TASK_RAW_WRITE) {
+			ide_startstop_t ret;
 
-		if (ar->cmd == CFA_WRITE_SECT_WO_ERASE ||
-		    ar->cmd == WIN_WRITE ||
-		    ar->cmd == WIN_WRITE_EXT ||
-		    ar->cmd == WIN_WRITE_VERIFY ||
-		    ar->cmd == WIN_WRITE_BUFFER ||
-		    ar->cmd == WIN_DOWNLOAD_MICROCODE ||
-		    ar->cmd == CFA_WRITE_MULTI_WO_ERASE ||
-		    ar->cmd == WIN_MULTWRITE ||
-		    ar->cmd == WIN_MULTWRITE_EXT) {
-			ide_startstop_t startstop;
+			OUT_BYTE(cmd, IDE_COMMAND_REG);
 
-			if (ata_status_poll(drive, DATA_READY, drive->bad_wstat,
-						WAIT_DRQ, rq, &startstop)) {
+			ret = ata_status_poll(drive, DATA_READY, drive->bad_wstat,
+						WAIT_DRQ, rq);
+			if (ret != ATA_OP_READY) {
 				printk(KERN_ERR "%s: no DRQ after issuing %s\n",
 						drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
 
-				return startstop;
+				return ret;
 			}
 
 			/* FIXME: This doesn't make the slightest sense.
 			 * (ks/hs): Fixed Multi Write
 			 */
-			if (!(ar->cmd == CFA_WRITE_MULTI_WO_ERASE ||
-			      ar->cmd == WIN_MULTWRITE ||
-			      ar->cmd == WIN_MULTWRITE_EXT)) {
+			if (!(cmd == CFA_WRITE_MULTI_WO_ERASE ||
+			      cmd == WIN_MULTWRITE ||
+			      cmd == WIN_MULTWRITE_EXT)) {
 				unsigned long flags;
 				char *buf = ide_map_rq(rq, &flags);
 
+				ata_set_handler(drive, ar->XXX_handler, WAIT_CMD, NULL);
+
 				/* For Write_sectors we need to stuff the first sector */
+				/* FIXME: what if !rq->current_nr_sectors  --bzolnier */
 				ata_write(drive, buf, SECTOR_WORDS);
 
 				rq->current_nr_sectors--;
 				ide_unmap_rq(rq, buf, &flags);
 
-				return ide_started;
+				return ATA_OP_CONTINUES;
 			} else {
 				int i;
-				int ret;
 
 				/* Polling wait until the drive is ready.
 				 *
@@ -438,14 +603,16 @@
 						break;
 				}
 				if (!drive_is_ready(drive)) {
-					printk(KERN_ERR "DISASTER WAITING TO HAPPEN!\n");
+					/* We are compleatly missing an error
+					 * return path here.
+					 * FIXME: We have only one? -alat
+					 */
+					printk(KERN_ERR "DISASTER WAITING TO HAPPEN! Try to Stop it!\n");
+					return ata_error(drive, rq, __FUNCTION__);
 				}
-				/* FIXME: make this unlocking go away*/
-				spin_unlock_irq(ch->lock);
-				ret =  ar->XXX_handler(drive, rq);
-				spin_lock_irq(ch->lock);
 
-				return ret;
+				/* will set handler for us */
+				return ar->XXX_handler(drive, rq);
 			}
 		}
 	} else {
@@ -456,221 +623,34 @@
 		 * FIXME: Handle the alternateives by a command type.
 		 */
 
+		/* FIXME: ATA_OP_CONTINUES?  --bzolnier */
+		/* Not started a request - BUG() ot ATA_OP_FINISHED to avoid lockup ? - alat*/
 		if (!drive->using_dma)
-			return ide_started;
+			return ATA_OP_CONTINUES;
 
 		/* for dma commands we don't set the handler */
-		if (ar->cmd == WIN_WRITEDMA ||
-		    ar->cmd == WIN_WRITEDMA_EXT ||
-		    ar->cmd == WIN_READDMA ||
-		    ar->cmd == WIN_READDMA_EXT)
+		if (cmd == WIN_WRITEDMA ||
+		    cmd == WIN_WRITEDMA_EXT ||
+		    cmd == WIN_READDMA ||
+		    cmd == WIN_READDMA_EXT)
 			return udma_init(drive, rq);
 #ifdef CONFIG_BLK_DEV_IDE_TCQ
-		else if (ar->cmd == WIN_WRITEDMA_QUEUED ||
-			 ar->cmd == WIN_WRITEDMA_QUEUED_EXT ||
-			 ar->cmd == WIN_READDMA_QUEUED ||
-			 ar->cmd == WIN_READDMA_QUEUED_EXT)
+		else if (cmd == WIN_WRITEDMA_QUEUED ||
+			 cmd == WIN_WRITEDMA_QUEUED_EXT ||
+			 cmd == WIN_READDMA_QUEUED ||
+			 cmd == WIN_READDMA_QUEUED_EXT)
 			return udma_tcq_init(drive, rq);
 #endif
 		else {
-			printk(KERN_ERR "%s: unknown command %x\n", __FUNCTION__, ar->cmd);
-			return ide_stopped;
-		}
-	}
-
-	return ide_started;
-}
-
-/*
- * Issue a READ or WRITE command to a disk, using LBA if supported, or CHS
- * otherwise, to address sectors.  It also takes care of issuing special
- * DRIVE_CMDs.
- *
- * Channel lock should be held.
- */
-static ide_startstop_t idedisk_do_request(struct ata_device *drive, struct request *rq, sector_t block)
-{
-	struct ata_taskfile args;
-	unsigned int sectors;
-
-	/* This issues a special drive command.
-	 */
-	if (rq->flags & REQ_SPECIAL)
-		return __do_request(drive, rq->special, rq);
-
-	/* FIXME: this check doesn't make sense */
-	if (!(rq->flags & REQ_CMD)) {
-		blk_dump_rq_flags(rq, "idedisk_do_request - bad command");
-		__ata_end_request(drive, rq, 0, 0);
-
-		return ide_stopped;
-	}
-
-	if (IS_PDC4030_DRIVE) {
-		extern ide_startstop_t promise_do_request(struct ata_device *, struct request *, sector_t);
-
-		return promise_do_request(drive, rq, block);
-	}
-
-	/*
-	 * start a tagged operation
-	 */
-	if (drive->using_tcq) {
-		int st = blk_queue_start_tag(&drive->queue, rq);
-
-		if (ata_pending_commands(drive) > drive->max_depth)
-			drive->max_depth = ata_pending_commands(drive);
-		if (ata_pending_commands(drive) > drive->max_last_depth)
-			drive->max_last_depth = ata_pending_commands(drive);
-
-		if (st) {
-			BUG_ON(!ata_pending_commands(drive));
-
-			return ide_started;
-		}
-	}
-
-	memset(&args, 0, sizeof(args));
-	sectors = rq->nr_sectors;
-	/* Dispatch depending up on the drive access method. */
-	if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
-		/* LBA 48 bit */
-		/*
-		 * 268435455  == 137439 MB or 28bit limit
-		 * 320173056  == 163929 MB or 48bit addressing
-		 * 1073741822 == 549756 MB or 48bit addressing fake drive
-		 */
-		if (sectors == 65536)
-			sectors = 0;
-
-		if (blk_rq_tagged(rq)) {
-			args.taskfile.feature = sectors;
-			args.hobfile.feature = sectors >> 8;
-			args.taskfile.sector_count = rq->tag << 3;
-		} else {
-			args.taskfile.sector_count = sectors;
-			args.hobfile.sector_count = sectors >> 8;
-		}
-
-		args.taskfile.sector_number = block;		/* low lba */
-		args.taskfile.low_cylinder = (block >>= 8);	/* mid lba */
-		args.taskfile.high_cylinder = (block >>= 8);	/* hi  lba */
-		args.taskfile.device_head = drive->select.all;
-
-		args.hobfile.sector_number = (block >>= 8);	/* low lba */
-		args.hobfile.low_cylinder = (block >>= 8);	/* mid lba */
-		args.hobfile.high_cylinder = (block >>= 8);	/* hi  lba */
-	} else if (drive->select.b.lba) {
-		/* LBA 28 bit  */
-		if (sectors == 256)
-			sectors = 0;
-
-		if (blk_rq_tagged(rq)) {
-			args.taskfile.feature = sectors;
-			args.taskfile.sector_count = rq->tag << 3;
-		} else
-			args.taskfile.sector_count = sectors;
-
-		args.taskfile.sector_number = block;
-		args.taskfile.low_cylinder = (block >>= 8);
-		args.taskfile.high_cylinder = (block >>= 8);
-		args.taskfile.device_head = ((block >> 8) & 0x0f);
-	} else {
-		/* CHS */
-		unsigned int track	= (block / drive->sect);
-		unsigned int sect	= (block % drive->sect) + 1;
-		unsigned int head	= (track % drive->head);
-		unsigned int cyl	= (track / drive->head);
-
-		if (sectors == 256)
-			sectors = 0;
-
-		if (blk_rq_tagged(rq)) {
-			args.taskfile.feature = sectors;
-			args.taskfile.sector_count = rq->tag << 3;
-		} else
-			args.taskfile.sector_count = sectors;
-
-		args.taskfile.sector_number = sect;
-		args.taskfile.low_cylinder = cyl;
-		args.taskfile.high_cylinder = (cyl>>8);
-		args.taskfile.device_head = head;
-	}
-	args.taskfile.device_head |= drive->select.all;
-
-	/*
-	 * Decode with physical ATA command to use and setup associated data.
-	 */
+			printk(KERN_ERR "%s: unknown command %x\n",
+					__FUNCTION__, cmd);
 
-	if (rq_data_dir(rq) == READ) {
-		args.command_type = IDE_DRIVE_TASK_IN;
-		if (drive->addressing) {
-			if (drive->using_tcq) {
-				args.cmd = WIN_READDMA_QUEUED_EXT;
-			} else if (drive->using_dma) {
-				args.cmd = WIN_READDMA_EXT;
-			} else if (drive->mult_count) {
-				args.XXX_handler = task_mulin_intr;
-				args.cmd = WIN_MULTREAD_EXT;
-			} else {
-				args.XXX_handler = task_in_intr;
-				args.cmd = WIN_READ_EXT;
-			}
-		} else {
-			if (drive->using_tcq) {
-				args.cmd = WIN_READDMA_QUEUED;
-			} else if (drive->using_dma) {
-				args.cmd = WIN_READDMA;
-			} else if (drive->mult_count) {
-				/* FIXME : Shouldn't this be task_mulin_intr?! */
-				args.XXX_handler = task_in_intr;
-				args.cmd = WIN_MULTREAD;
-			} else {
-				args.XXX_handler = task_in_intr;
-				args.cmd = WIN_READ;
-			}
-		}
-	} else {
-		args.command_type = IDE_DRIVE_TASK_RAW_WRITE;
-		if (drive->addressing) {
-			if (drive->using_tcq) {
-				args.cmd = WIN_WRITEDMA_QUEUED_EXT;
-			} else if (drive->using_dma) {
-				args.cmd = WIN_WRITEDMA_EXT;
-			} else if (drive->mult_count) {
-				args.XXX_handler = task_mulout_intr;
-				args.cmd = WIN_MULTWRITE_EXT;
-			} else {
-				args.XXX_handler = task_out_intr;
-				args.cmd = WIN_WRITE_EXT;
-			}
-		} else {
-			if (drive->using_tcq) {
-				args.cmd = WIN_WRITEDMA_QUEUED;
-			} else if (drive->using_dma) {
-				args.cmd = WIN_WRITEDMA;
-			} else if (drive->mult_count) {
-				args.XXX_handler = task_mulout_intr;
-				args.cmd = WIN_MULTWRITE;
-			} else {
-				args.XXX_handler = task_out_intr;
-				args.cmd = WIN_WRITE;
-			}
+			return ATA_OP_FINISHED;
 		}
 	}
 
-
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name,
-			(rq_data_dir(rq)==READ) ? "read" : "writ");
-	if (lba)	printk("LBAsect=%lld, ", block);
-	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
-	printk("sectors=%ld, ", rq->nr_sectors);
-	printk("buffer=%p\n", rq->buffer);
-#endif
-	rq->special = &args;
-
-	return __do_request(drive, &args, rq);
+	/* not reached */
+	return ATA_OP_CONTINUES;
 }
 
 static int idedisk_open(struct inode *inode, struct file *__fp, struct ata_device *drive)
@@ -689,7 +669,7 @@
 
 			memset(&args, 0, sizeof(args));
 			args.cmd = WIN_DOORLOCK;
-			if (ide_raw_taskfile(drive, &args))
+			if (ide_raw_taskfile(drive, &args, NULL))
 				drive->doorlocking = 0;
 		}
 	}
@@ -708,7 +688,7 @@
 	else
 		args.cmd = WIN_FLUSH_CACHE;
 
-	return ide_raw_taskfile(drive, &args);
+	return ide_raw_taskfile(drive, &args, NULL);
 }
 
 static void idedisk_release(struct inode *inode, struct file *filp, struct ata_device *drive)
@@ -722,7 +702,7 @@
 
 			memset(&args, 0, sizeof(args));
 			args.cmd = WIN_DOORUNLOCK;
-			if (ide_raw_taskfile(drive, &args))
+			if (ide_raw_taskfile(drive, &args, NULL))
 				drive->doorlocking = 0;
 		}
 	}
@@ -769,7 +749,7 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.sector_count = arg;
 	args.cmd = WIN_SETMULT;
-	if (!ide_raw_taskfile(drive, &args)) {
+	if (!ide_raw_taskfile(drive, &args, NULL)) {
 		/* all went well track this setting as valid */
 		drive->mult_count = arg;
 
@@ -798,7 +778,7 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.feature	= (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
 	args.cmd = WIN_SETFEATURES;
-	ide_raw_taskfile(drive, &args);
+	ide_raw_taskfile(drive, &args, NULL);
 
 	drive->wcache = arg;
 
@@ -811,7 +791,7 @@
 
 	memset(&args, 0, sizeof(args));
 	args.cmd = WIN_STANDBYNOW1;
-	return ide_raw_taskfile(drive, &args);
+	return ide_raw_taskfile(drive, &args, NULL);
 }
 
 static int set_acoustic(struct ata_device *drive, int arg)
@@ -822,7 +802,7 @@
 	args.taskfile.feature = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
 	args.taskfile.sector_count = arg;
 	args.cmd = WIN_SETFEATURES;
-	ide_raw_taskfile(drive, &args);
+	ide_raw_taskfile(drive, &args, NULL);
 
 	drive->acoustic = arg;
 
@@ -942,7 +922,7 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.device_head = 0x40;
 	args.cmd = WIN_READ_NATIVE_MAX;
-	ide_raw_taskfile(drive, &args);
+	ide_raw_taskfile(drive, &args, NULL);
 
 	/* if OK, compute maximum address value */
 	if (!(drive->status & ERR_STAT)) {
@@ -964,10 +944,9 @@
 
 	/* Create IDE/ATA command request structure */
 	memset(&args, 0, sizeof(args));
-
 	args.taskfile.device_head = 0x40;
 	args.cmd = WIN_READ_NATIVE_MAX_EXT;
-        ide_raw_taskfile(drive, &args);
+        ide_raw_taskfile(drive, &args, NULL);
 
 	/* if OK, compute maximum address value */
 	if (!(drive->status & ERR_STAT)) {
@@ -1005,7 +984,7 @@
 
 	args.taskfile.device_head = ((addr_req >> 24) & 0x0f) | 0x40;
 	args.cmd = WIN_SET_MAX;
-	ide_raw_taskfile(drive, &args);
+	ide_raw_taskfile(drive, &args, NULL);
 
 	/* if OK, read new maximum address value */
 	if (!(drive->status & ERR_STAT)) {
@@ -1038,7 +1017,7 @@
 	args.hobfile.high_cylinder = (addr_req >>= 8);
 	args.hobfile.device_head = 0x40;
 
-	ide_raw_taskfile(drive, &args);
+	ide_raw_taskfile(drive, &args, NULL);
 
 	/* if OK, compute maximum address value */
 	if (!(drive->status & ERR_STAT)) {
@@ -1422,7 +1401,12 @@
 
 #ifdef CONFIG_BLK_DEV_IDE_TCQ
 		case HDIO_GET_QDMA: {
-			u8 val = drive->using_tcq;
+			/* Foolup hdparm 0 means off 1 on -alat */
+			/* FIXME: hdparm have only -Q do we need something like:
+			 * hdparm -q 1/0 - TCQ on/off
+			 * hdparm -Q 1-MAX - TCQ queue_depth ?
+			 */
+			u8 val = ( drive->using_tcq ?  drive->queue_depth : 0 );
 
 			if (put_user(val, (u8 *) arg))
 				return -EFAULT;
diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
--- a/drivers/ide/ide-floppy.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/ide-floppy.c	Tue Jul 16 16:49:42 2002
@@ -315,270 +315,6 @@
 #define	IDEFLOPPY_ERROR_GENERAL		101
 
 /*
- *	The ATAPI Status Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned check		:1;	/* Error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned dsc		:1;	/* Media access command finished */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned bsy		:1;	/* The device has access to the command block */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned bsy		:1;	/* The device has access to the command block */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned dsc		:1;	/* Media access command finished */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned check		:1;	/* Error occurred */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_status_reg_t;
-
-/*
- *	The ATAPI error register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned ili		:1;	/* Illegal Length Indication */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned ili		:1;	/* Illegal Length Indication */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_error_reg_t;
-
-/*
- *	ATAPI Feature Register
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned dma		:1;	/* Using DMA or PIO */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved7	:1;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved7	:1;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned dma		:1;	/* Using DMA or PIO */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_feature_reg_t;
-
-/*
- *	ATAPI Byte Count Register.
- */
-typedef union {
-	unsigned all			:16;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned low		:8;	/* LSB */
-		unsigned high		:8;	/* MSB */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned high		:8;	/* MSB */
-		unsigned low		:8;	/* LSB */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_bcount_reg_t;
-
-/*
- *	ATAPI Interrupt Reason Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned reserved	:6;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved	:6;	/* Reserved */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_ireason_reg_t;
-
-/*
- *	ATAPI floppy Drive Select Register
- */
-typedef union {	
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned sam_lun	:3;	/* Logical unit number */
-		unsigned reserved3	:1;	/* Reserved */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one7		:1;	/* Should be set to 1 */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned one7		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned reserved3	:1;	/* Reserved */
-		unsigned sam_lun	:3;	/* Logical unit number */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_drivesel_reg_t;
-
-/*
- *	ATAPI Device Control Register
- */
-typedef union {			
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned zero0		:1;	/* Should be set to zero */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned reserved4567	:4;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved4567	:4;	/* Reserved */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned zero0		:1;	/* Should be set to zero */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_control_reg_t;
-
-/*
- *	The following is used to format the general configuration word of
- *	the ATAPI IDENTIFY DEVICE command.
- */
-struct idefloppy_id_gcw {	
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	unsigned packet_size		:2;	/* Packet Size */
-	unsigned reserved234		:3;	/* Reserved */
-	unsigned drq_type		:2;	/* Command packet DRQ type */
-	unsigned removable		:1;	/* Removable media */
-	unsigned device_type		:5;	/* Device type */
-	unsigned reserved13		:1;	/* Reserved */
-	unsigned protocol		:2;	/* Protocol type */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	unsigned protocol		:2;	/* Protocol type */
-	unsigned reserved13		:1;	/* Reserved */
-	unsigned device_type		:5;	/* Device type */
-	unsigned removable		:1;	/* Removable media */
-	unsigned drq_type		:2;	/* Command packet DRQ type */
-	unsigned reserved234		:3;	/* Reserved */
-	unsigned packet_size		:2;	/* Packet Size */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-};
-
-/*
- *	INQUIRY packet command - Data Format
- */
-typedef struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	unsigned	device_type	:5;	/* Peripheral Device Type */
-	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
-	unsigned	reserved1_6t0	:7;	/* Reserved */
-	unsigned	rmb		:1;	/* Removable Medium Bit */
-	unsigned	ansi_version	:3;	/* ANSI Version */
-	unsigned	ecma_version	:3;	/* ECMA Version */
-	unsigned	iso_version	:2;	/* ISO Version */
-	unsigned	response_format :4;	/* Response Data Format */
-	unsigned	reserved3_45	:2;	/* Reserved */
-	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
-	unsigned	reserved3_7	:1;	/* AENC - Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
-	unsigned	device_type	:5;	/* Peripheral Device Type */
-	unsigned	rmb		:1;	/* Removable Medium Bit */
-	unsigned	reserved1_6t0	:7;	/* Reserved */
-	unsigned	iso_version	:2;	/* ISO Version */
-	unsigned	ecma_version	:3;	/* ECMA Version */
-	unsigned	ansi_version	:3;	/* ANSI Version */
-	unsigned	reserved3_7	:1;	/* AENC - Reserved */
-	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
-	unsigned	reserved3_45	:2;	/* Reserved */
-	unsigned	response_format :4;	/* Response Data Format */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	u8		additional_length;	/* Additional Length (total_length-4) */
-	u8		rsv5, rsv6, rsv7;	/* Reserved */
-	u8		vendor_id[8];		/* Vendor Identification */
-	u8		product_id[16];		/* Product Identification */
-	u8		revision_level[4];	/* Revision Level */
-	u8		vendor_specific[20];	/* Vendor Specific - Optional */
-	u8		reserved56t95[40];	/* Reserved - Optional */
-						/* Additional information may be returned */
-} idefloppy_inquiry_result_t;
-
-/*
- *	REQUEST SENSE packet command result - Data Format.
- */
-typedef struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	unsigned	error_code	:7;	/* Current error (0x70) */
-	unsigned	valid		:1;	/* The information field conforms to SFF-8070i */
-	u8		reserved1	:8;	/* Reserved */
-	unsigned	sense_key	:4;	/* Sense Key */
-	unsigned	reserved2_4	:1;	/* Reserved */
-	unsigned	ili		:1;	/* Incorrect Length Indicator */
-	unsigned	reserved2_67	:2;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	valid		:1;	/* The information field conforms to SFF-8070i */
-	unsigned	error_code	:7;	/* Current error (0x70) */
-	u8		reserved1	:8;	/* Reserved */
-	unsigned	reserved2_67	:2;
-	unsigned	ili		:1;	/* Incorrect Length Indicator */
-	unsigned	reserved2_4	:1;	/* Reserved */
-	unsigned	sense_key	:4;	/* Sense Key */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	u32		information __attribute__ ((packed));
-	u8		asl;			/* Additional sense length (n-7) */
-	u32		command_specific;	/* Additional command specific information */
-	u8		asc;			/* Additional Sense Code */
-	u8		ascq;			/* Additional Sense Code Qualifier */
-	u8		replaceable_unit_code;	/* Field Replaceable Unit Code */
-	u8		sksv[3];
-	u8		pad[2];			/* Padding to 20 bytes */
-} idefloppy_request_sense_result_t;
-
-/*
  *	Pages of the SELECT SENSE / MODE SENSE packet commands.
  */
 #define	IDEFLOPPY_CAPABILITIES_PAGE	0x1b
@@ -602,9 +338,6 @@
 	u8		reserved[4];
 } idefloppy_mode_parameter_header_t;
 
-#define IDEFLOPPY_MIN(a,b)	((a)<(b) ? (a):(b))
-#define	IDEFLOPPY_MAX(a,b)	((a)>(b) ? (a):(b))
-
 /*
  *	idefloppy_end_request is used to finish servicing a request.
  *
@@ -613,6 +346,8 @@
  */
 static int idefloppy_end_request(struct ata_device *drive, struct request *rq, int uptodate)
 {
+	unsigned long flags;
+	struct ata_channel *ch = drive->channel;
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	int error;
 
@@ -632,15 +367,19 @@
 		return 0;
 
 	if (!(rq->flags & REQ_SPECIAL)) {
-		ata_end_request(drive, rq, uptodate);
+		__ata_end_request(drive, rq, uptodate, 0);
 		return 0;
 	}
 
+	spin_lock_irqsave(ch->lock, flags);
+
 	rq->errors = error;
 	blkdev_dequeue_request(rq);
 	drive->rq = NULL;
 	end_that_request_last(rq);
 
+	spin_unlock_irqrestore(ch->lock, flags);
+
 	return 0;
 }
 
@@ -663,7 +402,7 @@
 			atapi_discard_data(drive, bcount);
 			return;
 		}
-		count = IDEFLOPPY_MIN(bio->bi_size - pc->b_count, bcount);
+		count = min_t(unsigned int, bio->bi_size - pc->b_count, bcount);
 		atapi_read(drive, bio_data(bio) + pc->b_count, count);
 		bcount -= count; pc->b_count += count;
 	}
@@ -690,7 +429,7 @@
 			atapi_write_zeros (drive, bcount);
 			return;
 		}
-		count = IDEFLOPPY_MIN(pc->b_count, bcount);
+		count = min_t(unsigned int, pc->b_count, bcount);
 		atapi_write(drive, pc->b_data, count);
 		bcount -= count; pc->b_data += count; pc->b_count -= count;
 	}
@@ -743,13 +482,13 @@
  *	idefloppy_analyze_error is called on each failed packet command retry
  *	to analyze the request sense.
  */
-static void idefloppy_analyze_error(struct ata_device *drive, idefloppy_request_sense_result_t *result)
+static void idefloppy_analyze_error(struct ata_device *drive, atapi_request_sense_result_t *result)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
 	floppy->sense_key = result->sense_key; floppy->asc = result->asc; floppy->ascq = result->ascq;
-	floppy->progress_indication= result->sksv[0] & 0x80 ?
-		(unsigned short)get_unaligned((u16 *)(result->sksv+1)):0x10000;
+	floppy->progress_indication= result->sksv ?
+		(unsigned short)get_unaligned((u16 *)(result->sk_specific)):0x10000;
 #if IDEFLOPPY_DEBUG_LOG
 	if (floppy->failed_pc)
 		printk (KERN_INFO "ide-floppy: pc = %x, sense key = %x, asc = %x, ascq = %x\n",floppy->failed_pc->c[0],result->sense_key,result->asc,result->ascq);
@@ -766,7 +505,7 @@
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_request_sense_callback\n");
 #endif
 	if (!floppy->pc->error) {
-		idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
+		idefloppy_analyze_error(drive,(atapi_request_sense_result_t *) floppy->pc->buffer);
 		idefloppy_end_request(drive, rq, 1);
 	} else {
 		printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
@@ -806,7 +545,7 @@
 {
 	struct atapi_packet_command *pc;
 	struct request *rq;
-	idefloppy_error_reg_t error;
+	atapi_error_reg_t error;
 
 	error.all = IN_BYTE(IDE_ERROR_REG);
 	pc = idefloppy_next_pc_storage(drive);
@@ -821,12 +560,10 @@
  */
 static ide_startstop_t idefloppy_pc_intr(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_status_reg_t status;
-	idefloppy_bcount_reg_t bcount;
-	idefloppy_ireason_reg_t ireason;
+	atapi_status_reg_t status;
+	atapi_bcount_reg_t bcount;
+	atapi_ireason_reg_t ireason;
 	struct atapi_packet_command *pc = floppy->pc;
 	unsigned int temp;
 
@@ -866,46 +603,40 @@
 			rq->errors++;
 			if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
 				printk (KERN_ERR "ide-floppy: I/O error in request sense command\n");
-				return ide_stopped;
+				return ATA_OP_FINISHED;
 			}
 			idefloppy_retry_pc (drive);				/* Retry operation */
-			return ide_stopped; /* queued, but not started */
+			return ATA_OP_FINISHED; /* queued, but not started */
 		}
 		pc->error = 0;
 		if (floppy->failed_pc == pc)
 			floppy->failed_pc=NULL;
 		pc->callback(drive, rq);    /* Command finished - Call the callback function */
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
 		udma_enable(drive, 0, 1);
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 #endif
-	/* FIXME: this locking should encompass the above register
-	 * file access too.
-	 */
 
-	spin_lock_irqsave(ch->lock, flags);
 	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
 	bcount.b.low=IN_BYTE (IDE_BCOUNTL_REG);			/* on this interrupt */
 	ireason.all=IN_BYTE (IDE_IREASON_REG);
 
 	if (ireason.b.cod) {
-		spin_unlock_irqrestore(ch->lock, flags);
-
 		printk (KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
-		return ide_stopped;
+
+		return ATA_OP_FINISHED;
 	}
 	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
-		spin_unlock_irqrestore(ch->lock, flags);
-
 		printk (KERN_ERR "ide-floppy: We wanted to %s, ", ireason.b.io ? "Write":"Read");
 		printk (KERN_ERR "but the floppy wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		return ide_stopped;
+
+		return ATA_OP_FINISHED;
 	}
 	if (!test_bit(PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
@@ -915,9 +646,8 @@
 
 				atapi_discard_data (drive,bcount.all);
 				ata_set_handler(drive, idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
-				spin_unlock_irqrestore(ch->lock, flags);
 
-				return ide_started;
+				return ATA_OP_CONTINUES;
 			}
 #if IDEFLOPPY_DEBUG_LOG
 			printk (KERN_NOTICE "ide-floppy: The floppy wants to send us more data than expected - allowing transfer\n");
@@ -939,9 +669,8 @@
 	pc->current_position+=bcount.all;
 
 	ata_set_handler(drive, idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
-	spin_unlock_irqrestore(ch->lock, flags);
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 /*
@@ -951,34 +680,27 @@
  */
 static ide_startstop_t idefloppy_transfer_pc(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
-	ide_startstop_t startstop;
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_ireason_reg_t ireason;
+	atapi_ireason_reg_t ireason;
 	int ret;
 
-	/* FIXME: Move this lock upwards.
-	 */
-	spin_lock_irqsave(ch->lock, flags);
-	if (ata_status_poll(drive, DRQ_STAT, BUSY_STAT,
-				WAIT_READY, rq, &startstop)) {
+	ret = ata_status_poll(drive, DRQ_STAT, BUSY_STAT, WAIT_READY, rq);
+	if (ret != ATA_OP_READY) {
 		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
 
-		ret = startstop;
-	} else {
-		ireason.all=IN_BYTE (IDE_IREASON_REG);
+		return ret;
+	}
 
-		if (!ireason.b.cod || ireason.b.io) {
-			printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
-			ret = ide_stopped;
-		} else {
-			ata_set_handler (drive, idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
-			atapi_write(drive, floppy->pc->c, 12); /* Send the actual packet */
-			ret = ide_started;
-		}
+	ireason.all = IN_BYTE(IDE_IREASON_REG);
+
+	if (!ireason.b.cod || ireason.b.io) {
+		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
+		ret = ATA_OP_FINISHED;
+	} else {
+		ata_set_handler(drive, idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
+		atapi_write(drive, floppy->pc->c, 12); /* Send the actual packet */
+		ret = ATA_OP_CONTINUES;
 	}
-	spin_unlock_irqrestore(ch->lock, flags);
 
 	return ret;
 }
@@ -996,39 +718,35 @@
  * packet, we schedule the packet transfer to occur about 2-3 ticks
  * later in transfer_pc2.
  */
-static int idefloppy_transfer_pc2(struct ata_device *drive, struct request *__rq)
+static ide_startstop_t idefloppy_transfer_pc2(struct ata_device *drive, struct request *__rq, unsigned long *wait)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
 	atapi_write(drive, floppy->pc->c, 12); /* Send the actual packet */
-	return IDEFLOPPY_WAIT_CMD;		/* Timeout for the packet command */
+	*wait = IDEFLOPPY_WAIT_CMD;	/* Timeout for the packet command */
+
+	return ATA_OP_CONTINUES;
 }
 
 static ide_startstop_t idefloppy_transfer_pc1(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	ide_startstop_t startstop;
-	idefloppy_ireason_reg_t ireason;
+	atapi_ireason_reg_t ireason;
 	int ret;
 
-	if (ata_status_poll(drive, DRQ_STAT, BUSY_STAT,
-				WAIT_READY, rq, &startstop)) {
+	ret = ata_status_poll(drive, DRQ_STAT, BUSY_STAT, WAIT_READY, rq);
+	if (ret != ATA_OP_READY) {
 		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
 
-		return startstop;
+		return ret;
 	}
 
-	/* FIXME: this locking should encompass the above register
-	 * file access too.
-	 */
+	ireason.all = IN_BYTE(IDE_IREASON_REG);
 
-	spin_lock_irqsave(ch->lock, flags);
-	ireason.all=IN_BYTE(IDE_IREASON_REG);
 	if (!ireason.b.cod || ireason.b.io) {
 		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ret = ide_stopped;
+		ret = ATA_OP_FINISHED;
 	} else {
 
 		/*
@@ -1043,9 +761,8 @@
 				idefloppy_pc_intr,	/* service routine for packet command */
 				floppy->ticks,		/* wait this long before "failing" */
 				idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
-		ret = ide_started;
+		ret = ATA_OP_CONTINUES;
 	}
-	spin_unlock_irqrestore(ch->lock, flags);
 
 	return ret;
 }
@@ -1057,7 +774,7 @@
 		struct atapi_packet_command *pc)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_bcount_reg_t bcount;
+	atapi_bcount_reg_t bcount;
 	int dma_ok = 0;
 	ata_handler_t *pkt_xfer_routine;
 
@@ -1086,7 +803,7 @@
 		}
 		floppy->failed_pc = NULL;
 		pc->callback(drive, rq);
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "Retry number - %d\n",pc->retries);
@@ -1126,19 +843,10 @@
 	}
 
 	if (test_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
-		unsigned long flags;
-		struct ata_channel *ch = drive->channel;
-
-		/* FIXME: this locking should encompass the above register
-		 * file access too.
-		 */
-
-		spin_lock_irqsave(ch->lock, flags);
 		ata_set_handler(drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
-		spin_unlock_irqrestore(ch->lock, flags);
 
-		return ide_started;
+		return ATA_OP_CONTINUES;
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
 		return pkt_xfer_routine(drive, rq);
@@ -1277,10 +985,8 @@
  */
 static ide_startstop_t idefloppy_do_request(struct ata_device *drive, struct request *rq, sector_t block)
 {
-	struct ata_channel *ch = drive->channel;
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	struct atapi_packet_command *pc;
-	int ret;
 
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "rq_status: %d, rq_dev: %u, flags: %lx, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->flags,rq->errors);
@@ -1294,22 +1000,17 @@
 		else
 			printk (KERN_ERR "ide-floppy: %s: I/O error\n", drive->name);
 
-		/* FIXME: make this unlocking go away*/
-		spin_unlock_irq(ch->lock);
 		idefloppy_end_request(drive, rq, 0);
-		spin_lock_irq(ch->lock);
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 	if (rq->flags & REQ_CMD) {
 		if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) {
 			printk ("%s: unsupported r/w request size\n", drive->name);
-			/* FIXME: make this unlocking go away*/
-			spin_unlock_irq(ch->lock);
+
 			idefloppy_end_request(drive, rq, 0);
-			spin_lock_irq(ch->lock);
 
-			return ide_stopped;
+			return ATA_OP_FINISHED;
 		}
 		pc = idefloppy_next_pc_storage(drive);
 		idefloppy_create_rw_cmd (floppy, pc, rq, block);
@@ -1318,20 +1019,13 @@
 		pc = (struct atapi_packet_command *) rq->buffer;
 	} else {
 		blk_dump_rq_flags(rq, "ide-floppy: unsupported command in queue");
-		/* FIXME: make this unlocking go away*/
-		spin_unlock_irq(ch->lock);
+
 		idefloppy_end_request(drive, rq, 0);
-		spin_lock_irq(ch->lock);
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
-	/* FIXME: make this unlocking go away*/
-	spin_unlock_irq(ch->lock);
-	ret = idefloppy_issue_pc(drive, rq, pc);
-	spin_lock_irq(ch->lock);
-
-	return ret;
+	return idefloppy_issue_pc(drive, rq, pc);
 }
 
 /*
@@ -1655,7 +1349,7 @@
 	}
 	else
 	{
-		idefloppy_status_reg_t status;
+		atapi_status_reg_t status;
 		unsigned long flags;
 
 		__save_flags(flags);
@@ -1861,7 +1555,7 @@
  */
 static int idefloppy_identify_device(struct ata_device *drive,struct hd_driveid *id)
 {
-	struct idefloppy_id_gcw gcw;
+	struct atapi_id_gcw gcw;
 #if IDEFLOPPY_DEBUG_INFO
 	unsigned short mask,i;
 	char buffer[80];
@@ -1976,7 +1670,7 @@
  */
 static void idefloppy_setup(struct ata_device *drive, idefloppy_floppy_t *floppy)
 {
-	struct idefloppy_id_gcw gcw;
+	struct atapi_id_gcw gcw;
 	int i;
 
 	*((unsigned short *) &gcw) = drive->id->config;
diff -Nru a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
--- a/drivers/ide/ide-pci.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ide/ide-pci.c	Tue Jul 16 16:49:43 2002
@@ -257,24 +257,13 @@
 	if (d->flags & ATA_F_NODMA)
 		goto no_dma;
 
-	/* Check whatever this interface is UDMA4 mode capable. */
-	if (ch->udma_four) {
+	if (ch->udma_four)
 		printk("%s: warning: ATA-66/100 forced bit set!\n", dev->name);
-	} else {
-		if (d->ata66_check)
-			ch->udma_four = d->ata66_check(ch);
-	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	/*
 	 * Setup DMA transfers on the channel.
 	 */
-	if (d->flags & ATA_F_NOADMA)
-		autodma = 0;
-
-	if (autodma)
-		ch->autodma = 1;
-
 	if (!((d->flags & ATA_F_DMA) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))))
 		goto no_dma;
 	/*
@@ -324,6 +313,10 @@
 	 * already enabled by the primary channel run.
 	 */
 	pci_set_master(dev);
+
+	if (autodma)
+		ch->autodma = 1;
+
 	if (d->init_dma)
 		d->init_dma(ch, dma_base);
 	else
@@ -334,6 +327,11 @@
 	/* Call chipset-specific routine for each enabled channel. */
 	if (d->init_channel)
 		d->init_channel(ch);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if ((d->flags & ATA_F_NOADMA) || noautodma)
+		ch->autodma = 0;
+#endif
 
 	return 0;
 }
diff -Nru a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
--- a/drivers/ide/ide-pmac.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ide/ide-pmac.c	Tue Jul 16 16:49:43 2002
@@ -256,11 +256,11 @@
 static void pmac_ide_setup_dma(struct device_node *np, int ix);
 
 static void pmac_udma_enable(struct ata_device *drive, int on, int verbose);
-static int pmac_udma_start(struct ata_device *drive, struct request *rq);
+static void pmac_udma_start(struct ata_device *drive, struct request *rq);
 static int pmac_udma_stop(struct ata_device *drive);
 static int pmac_udma_init(struct ata_device *drive, struct request *rq);
 static int pmac_udma_irq_status(struct ata_device *drive);
-static int pmac_udma_setup(struct ata_device *drive);
+static int pmac_udma_setup(struct ata_device *drive, int map);
 static int pmac_ide_build_dmatable(struct ata_device *drive, struct request *rq, int ix, int wr);
 static int pmac_ide_tune_chipset(struct ata_device *drive, byte speed);
 static void pmac_ide_tuneproc(struct ata_device *drive, byte pio);
@@ -1340,7 +1340,7 @@
 	ide_toggle_bounce(drive, 0);
 }
 
-static int pmac_udma_start(struct ata_device *drive, struct request *rq)
+static void pmac_udma_start(struct ata_device *drive, struct request *rq)
 {
 	int ix, ata4;
 	volatile struct dbdma_regs *dma;
@@ -1350,7 +1350,7 @@
 	 */
 	ix = pmac_ide_find(drive);
 	if (ix < 0)
-		return ide_stopped;
+		return;
 
 	dma = pmac_ide[ix].dma_regs;
 	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
@@ -1360,7 +1360,7 @@
 	/* Make sure it gets to the controller right now */
 	(void)in_le32(&dma->control);
 
-	return ide_started;
+	return;
 }
 
 static int pmac_udma_stop(struct ata_device *drive)
@@ -1397,7 +1397,7 @@
 	 */
 	ix = pmac_ide_find(drive);
 	if (ix < 0)
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 
 	if (rq_data_dir(rq) == READ)
 		reading = 1;
@@ -1409,7 +1409,7 @@
 		pmac_ide[ix].kind == controller_kl_ata4_80);
 
 	if (!pmac_ide_build_dmatable(drive, rq, ix, !reading))
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	/* Apple adds 60ns to wrDataSetup on reads */
 	if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
 		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
@@ -1419,7 +1419,7 @@
 	}
 
 	if (drive->type != ATA_DISK)
-		return ide_started;
+		return ATA_OP_CONTINUES;
 
 	ata_set_handler(drive, ide_dma_intr, WAIT_CMD, NULL);
 	if ((rq->flags & REQ_SPECIAL) &&
@@ -1435,7 +1435,7 @@
 
 	udma_start(drive, rq);
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 /*
@@ -1491,14 +1491,14 @@
 	set_bit(IDE_DMA, drive->channel->active);
 //	if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
 //		printk(KERN_WARNING "ide%d, timeout waiting \
-				for dbdma command stop\n", ix);
-		return 1;
-	}
+//				for dbdma command stop\n", ix);
+//		return 1;
+//	}
 	udelay(1);
 	return 0;
 }
 
-static int pmac_udma_setup(struct ata_device *drive)
+static int pmac_udma_setup(struct ata_device *drive, int map)
 {
 	/* Change this to better match ide-dma.c */
 	pmac_ide_check_dma(drive);
diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
--- a/drivers/ide/ide-tape.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ide/ide-tape.c	Tue Jul 16 16:49:41 2002
@@ -10,6 +10,10 @@
  */
 
 /*
+ * BIG FAT FIXME: clean tape->spinlock locking  --bzolnier
+ */
+
+/*
  * IDE ATAPI streaming tape driver.
  *
  * This driver is a part of the Linux ide driver and works in co-operation
@@ -771,32 +775,6 @@
 } idetape_stage_t;
 
 /*
- *	REQUEST SENSE packet command result - Data Format.
- */
-typedef struct {
-	unsigned	error_code	:7;	/* Current of deferred errors */
-	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
-	__u8		reserved1	:8;	/* Segment Number - Reserved */
-	unsigned	sense_key	:4;	/* Sense Key */
-	unsigned	reserved2_4	:1;	/* Reserved */
-	unsigned	ili		:1;	/* Incorrect Length Indicator */
-	unsigned	eom		:1;	/* End Of Medium */
-	unsigned	filemark 	:1;	/* Filemark */
-	__u32		information __attribute__ ((packed));
-	__u8		asl;			/* Additional sense length (n-7) */
-	__u32		command_specific;	/* Additional command specific information */
-	__u8		asc;			/* Additional Sense Code */
-	__u8		ascq;			/* Additional Sense Code Qualifier */
-	__u8		replaceable_unit_code;	/* Field Replaceable Unit Code */
-	unsigned	sk_specific1 	:7;	/* Sense Key Specific */
-	unsigned	sksv		:1;	/* Sense Key Specific information is valid */
-	__u8		sk_specific2;		/* Sense Key Specific */
-	__u8		sk_specific3;		/* Sense Key Specific */
-	__u8		pad[2];			/* Padding to 20 bytes */
-} idetape_request_sense_result_t;
-
-
-/*
  *	Most of our global data which we need to save even as we leave the
  *	driver due to an interrupt or a timer event is stored in a variable
  *	of type idetape_tape_t, defined below.
@@ -920,7 +898,7 @@
 	int avg_size;
 	int avg_speed;
 
-	idetape_request_sense_result_t sense;	/* last sense information */
+	atapi_request_sense_result_t sense;	/* last sense information */
 
 	char vendor_id[10];
 	char product_id[18];
@@ -1124,101 +1102,6 @@
 #define	IDETAPE_ERROR_EOD		103
 
 /*
- *	The ATAPI Status Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned check		:1;	/* Error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned dsc		:1;	/* Buffer availability / Media access command finished */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned bsy		:1;	/* The device has access to the command block */
-	} b;
-} idetape_status_reg_t;
-
-/*
- *	The ATAPI error register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned ili		:1;	/* Illegal Length Indication */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-	} b;
-} idetape_error_reg_t;
-
-/*
- *	ATAPI Feature Register
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned dma		:1;	/* Using DMA or PIO */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved7	:1;	/* Reserved */
-	} b;
-} idetape_feature_reg_t;
-
-/*
- *	ATAPI Byte Count Register.
- */
-typedef union {
-	unsigned all			:16;
-	struct {
-		unsigned low		:8;	/* LSB */
-		unsigned high		:8;	/* MSB */
-	} b;
-} idetape_bcount_reg_t;
-
-/*
- *	ATAPI Interrupt Reason Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned reserved	:6;	/* Reserved */
-	} b;
-} idetape_ireason_reg_t;
-
-/*
- *	ATAPI Drive Select Register
- */
-typedef union {	
-	unsigned all			:8;
-	struct {
-		unsigned sam_lun	:4;	/* Should be zero with ATAPI (not used) */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one7		:1;	/* Should be set to 1 */
-	} b;
-} idetape_drivesel_reg_t;
-
-/*
- *	ATAPI Device Control Register
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned zero0		:1;	/* Should be set to zero */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned reserved4567	:4;	/* Reserved */
-	} b;
-} idetape_control_reg_t;
-
-/*
  *	idetape_chrdev_t provides the link between out character device
  *	interface and our block device interface and the corresponding
  *	ata_device structure.
@@ -1228,45 +1111,6 @@
 } idetape_chrdev_t;
 
 /*
- *	The following is used to format the general configuration word of
- *	the ATAPI IDENTIFY DEVICE command.
- */
-struct idetape_id_gcw {	
-	unsigned packet_size		:2;	/* Packet Size */
-	unsigned reserved234		:3;	/* Reserved */
-	unsigned drq_type		:2;	/* Command packet DRQ type */
-	unsigned removable		:1;	/* Removable media */
-	unsigned device_type		:5;	/* Device type */
-	unsigned reserved13		:1;	/* Reserved */
-	unsigned protocol		:2;	/* Protocol type */
-};
-
-/*
- *	INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
- */
-typedef struct {
-	unsigned	device_type	:5;	/* Peripheral Device Type */
-	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
-	unsigned	reserved1_6t0	:7;	/* Reserved */
-	unsigned	rmb		:1;	/* Removable Medium Bit */
-	unsigned	ansi_version	:3;	/* ANSI Version */
-	unsigned	ecma_version	:3;	/* ECMA Version */
-	unsigned	iso_version	:2;	/* ISO Version */
-	unsigned	response_format :4;	/* Response Data Format */
-	unsigned	reserved3_45	:2;	/* Reserved */
-	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
-	unsigned	reserved3_7	:1;	/* AENC - Reserved */
-	__u8		additional_length;	/* Additional Length (total_length-4) */
-	__u8		rsv5, rsv6, rsv7;	/* Reserved */
-	__u8		vendor_id[8];		/* Vendor Identification */
-	__u8		product_id[16];		/* Product Identification */
-	__u8		revision_level[4];	/* Revision Level */
-	__u8		vendor_specific[20];	/* Vendor Specific - Optional */
-	__u8		reserved56t95[40];	/* Reserved - Optional */
-						/* Additional information may be returned */
-} idetape_inquiry_result_t;
-
-/*
  *	READ POSITION packet command - Data Format (From Table 6-57)
  */
 typedef struct {
@@ -1574,7 +1418,7 @@
  *	to analyze the request sense. We currently do not utilize this
  *	information.
  */
-static void idetape_analyze_error(struct ata_device *drive, idetape_request_sense_result_t *result)
+static void idetape_analyze_error(struct ata_device *drive, atapi_request_sense_result_t *result)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	struct atapi_packet_command *pc = tape->failed_pc;
@@ -1778,7 +1622,7 @@
 static int idetape_end_request(struct ata_device *drive, struct request *rq, int uptodate)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	unsigned long flags;
+	unsigned long flags, flags2;
 	int error;
 	int remove_stage = 0;
 #if ONSTREAM_DEBUG
@@ -1865,10 +1709,15 @@
 		}
 	}
 
+	/* FIXME: replace tape->spinlock with channel->spinlock  --bzolnier */
+	spin_lock_irqsave(drive->channel->lock, flags2);
+
 	blkdev_dequeue_request(rq);
 	drive->rq = NULL;
 	end_that_request_last(rq);
 
+	spin_unlock_irqrestore(drive->channel->lock, flags2);
+
 	if (remove_stage)
 		idetape_remove_stage_head(drive);
 	if (tape->active_data_request == NULL)
@@ -1887,7 +1736,7 @@
 		printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
 #endif
 	if (!tape->pc->error) {
-		idetape_analyze_error (drive, (idetape_request_sense_result_t *) tape->pc->buffer);
+		idetape_analyze_error (drive, (atapi_request_sense_result_t *) tape->pc->buffer);
 		idetape_end_request(drive, rq, 1);
 	} else {
 		printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
@@ -1941,7 +1790,7 @@
 	idetape_tape_t *tape = drive->driver_data;
 	struct atapi_packet_command *pc;
 	struct request *rq;
-	idetape_error_reg_t error;
+	atapi_error_reg_t error;
 
 	error.all = IN_BYTE (IDE_ERROR_REG);
 	pc = idetape_next_pc_storage (drive);
@@ -1978,12 +1827,10 @@
  */
 static ide_startstop_t idetape_pc_intr(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	idetape_tape_t *tape = drive->driver_data;
-	idetape_status_reg_t status;
-	idetape_bcount_reg_t bcount;
-	idetape_ireason_reg_t ireason;
+	atapi_status_reg_t status;
+	atapi_bcount_reg_t bcount;
+	atapi_ireason_reg_t ireason;
 	struct atapi_packet_command *pc = tape->pc;
 
 	unsigned int temp;
@@ -2052,14 +1899,14 @@
 #endif
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
 				printk (KERN_ERR "ide-tape: I/O error in request sense command\n");
-				return ide_stopped;
+				return ATA_OP_FINISHED;
 			}
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 1)
 				printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]);
 #endif
 			idetape_retry_pc(drive);				/* Retry operation */
-			return ide_stopped;
+			return ATA_OP_FINISHED;
 		}
 		pc->error = 0;
 		if (!tape->onstream && test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) {	/* Media access command */
@@ -2068,26 +1915,20 @@
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
 			idetape_postpone_request(drive, rq);		/* Allow ide.c to handle other requests */
 
-			return ide_stopped;
+			return ATA_OP_FINISHED;
 		}
 		if (tape->failed_pc == pc)
 			tape->failed_pc = NULL;
 		pc->callback(drive, rq);	/* Command finished - Call the callback function */
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
-	/* FIXME: this locking should encompass the above register
-	 * file access too.
-	 */
-
-	spin_lock_irqsave(ch->lock, flags);
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
 		printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
 		udma_enable(drive, 0, 1);
-		spin_unlock_irqrestore(ch->lock, flags);
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 #endif
 
@@ -2096,17 +1937,15 @@
 	ireason.all   = IN_BYTE (IDE_IREASON_REG);
 
 	if (ireason.b.cod) {
-		spin_unlock_irqrestore(ch->lock, flags);
-
 		printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
-		return ide_stopped;
+
+		return ATA_OP_FINISHED;
 	}
 	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
-		spin_unlock_irqrestore(ch->lock, flags);
-
 		printk (KERN_ERR "ide-tape: We wanted to %s, ", ireason.b.io ? "Write":"Read");
 		printk (KERN_ERR "ide-tape: but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		return ide_stopped;
+
+		return ATA_OP_FINISHED;
 	}
 	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
@@ -2115,9 +1954,8 @@
 				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
 				atapi_discard_data (drive, bcount.all);
 				ata_set_handler(drive, idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
-				spin_unlock_irqrestore(ch->lock, flags);
 
-				return ide_started;
+				return ATA_OP_CONTINUES;
 			}
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
@@ -2143,9 +1981,8 @@
 		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
 #endif
 	ata_set_handler(drive, idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
-	spin_unlock_irqrestore(ch->lock, flags);
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 /*
@@ -2192,46 +2029,41 @@
  */
 static ide_startstop_t idetape_transfer_pc(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	idetape_tape_t *tape = drive->driver_data;
 	struct atapi_packet_command *pc = tape->pc;
-	idetape_ireason_reg_t ireason;
+	atapi_ireason_reg_t ireason;
 	int retries = 100;
-	ide_startstop_t startstop;
 	int ret;
 
-	/* FIXME: Move this lock upwards.
-	 */
-	spin_lock_irqsave(ch->lock, flags);
-	if (ata_status_poll(drive, DRQ_STAT, BUSY_STAT,
-				WAIT_READY, rq, &startstop)) {
+	ret = ata_status_poll(drive, DRQ_STAT, BUSY_STAT, WAIT_READY, rq);
+	if (ret != ATA_OP_READY) {
 		printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
 
-		ret = startstop;
-	} else {
-		ireason.all = IN_BYTE (IDE_IREASON_REG);
-		while (retries-- && (!ireason.b.cod || ireason.b.io)) {
-			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, retrying\n");
-			udelay(100);
-			ireason.all = IN_BYTE(IDE_IREASON_REG);
-			if (retries == 0) {
-				printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, ignoring\n");
-				ireason.b.cod = 1;
-				ireason.b.io = 0;
-			}
-		}
-		if (!ireason.b.cod || ireason.b.io) {
-			printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
-			ret = ide_stopped;
-		} else {
-			tape->cmd_start_time = jiffies;
-			ata_set_handler(drive, idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
-			atapi_write(drive,pc->c,12);	/* Send the actual packet */
-			ret = ide_started;
+		return ret;
+	}
+
+	ireason.all = IN_BYTE (IDE_IREASON_REG);
+
+	while (retries-- && (!ireason.b.cod || ireason.b.io)) {
+		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, retrying\n");
+		udelay(100);
+		ireason.all = IN_BYTE(IDE_IREASON_REG);
+		if (retries == 0) {
+			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, ignoring\n");
+			ireason.b.cod = 1;
+			ireason.b.io = 0;
 		}
 	}
-	spin_unlock_irqrestore(ch->lock, flags);
+
+	if (!ireason.b.cod || ireason.b.io) {
+		printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
+		ret = ATA_OP_FINISHED;
+	} else {
+		tape->cmd_start_time = jiffies;
+		ata_set_handler(drive, idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
+		atapi_write(drive,pc->c,12);	/* Send the actual packet */
+		ret = ATA_OP_CONTINUES;
+	}
 
 	return ret;
 }
@@ -2240,7 +2072,7 @@
 		struct request *rq, struct atapi_packet_command *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	idetape_bcount_reg_t bcount;
+	atapi_bcount_reg_t bcount;
 	int dma_ok = 0;
 
 #if IDETAPE_DEBUG_BUGS
@@ -2272,7 +2104,7 @@
 		}
 		tape->failed_pc = NULL;
 		pc->callback(drive, rq);
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
@@ -2305,19 +2137,10 @@
 	}
 #endif
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-		unsigned long flags;
-		struct ata_channel *ch = drive->channel;
-
-		/* FIXME: this locking should encompass the above register
-		 * file access too.
-		 */
-
-		spin_lock_irqsave(ch->lock, flags);
 		ata_set_handler(drive, idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
 		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-		spin_unlock_irqrestore(ch->lock, flags);
 
-		return ide_started;
+		return ATA_OP_CONTINUES;
 	} else {
 		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return idetape_transfer_pc(drive, rq);
@@ -2451,7 +2274,7 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	struct atapi_packet_command *pc = tape->pc;
-	idetape_status_reg_t status;
+	atapi_status_reg_t status;
 
 	if (tape->onstream)
 		printk(KERN_INFO "ide-tape: bug: onstream, media_access_finished\n");
@@ -2605,12 +2428,10 @@
  */
 static ide_startstop_t idetape_do_request(struct ata_device *drive, struct request *rq, sector_t block)
 {
-	struct ata_channel *ch = drive->channel;
 	idetape_tape_t *tape = drive->driver_data;
 	struct atapi_packet_command *pc;
 	struct request *postponed_rq = tape->postponed_rq;
-	idetape_status_reg_t status;
-	int ret;
+	atapi_status_reg_t status;
 
 #if IDETAPE_DEBUG_LOG
 /*	if (tape->debug_level >= 5)
@@ -2625,32 +2446,24 @@
 		 */
 		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%ld)\n", drive->name, rq->flags);
 		__ata_end_request(drive, rq, 0, 0);			/* Let the common code handle it */
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	/*
 	 *	Retry a failed packet command
 	 */
 	if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		int ret;
-
-		/* FIXME: make this unlocking go away*/
-		spin_unlock_irq(ch->lock);
-		ret = idetape_issue_packet_command(drive, rq, tape->failed_pc);
-		spin_lock_irq(ch->lock);
 
-		return ret;
+		return idetape_issue_packet_command(drive, rq, tape->failed_pc);
 	}
 #if IDETAPE_DEBUG_BUGS
 	if (postponed_rq != NULL)
 		if (rq != postponed_rq) {
 			printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
-			/* FIXME: make this unlocking go away*/
-			spin_unlock_irq(ch->lock);
+
 			idetape_end_request(drive, rq, 0);
-			spin_lock_irq(ch->lock);
 
-			return ide_stopped;
+			return ATA_OP_FINISHED;
 		}
 #endif
 
@@ -2690,7 +2503,7 @@
 		idetape_queue_onstream_buffer_fill(drive);
 		if (jiffies > tape->insert_time)
 			tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 	if (jiffies > tape->insert_time)
 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
@@ -2726,20 +2539,16 @@
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
 		} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
 			printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
-			if (rq->flags == IDETAPE_PC_RQ2) {
-				/* FIXME: make this unlocking go away*/
-				spin_unlock_irq(ch->lock);
+
+			if (rq->flags == IDETAPE_PC_RQ2)
 				idetape_media_access_finished(drive, rq);
-				spin_lock_irq(ch->lock);
-				return ide_stopped;
-			} else {
-				return ide_stopped;
-			}
+
+			return ATA_OP_FINISHED;
 		} else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
 		idetape_postpone_request(drive, rq);
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 	switch (rq->flags) {
 		case IDETAPE_READ_RQ:
@@ -2783,7 +2592,7 @@
 		case IDETAPE_ABORTED_WRITE_RQ:
 			rq->flags = IDETAPE_WRITE_RQ;
 			idetape_end_request(drive, rq, IDETAPE_ERROR_EOD);
-			return ide_stopped;
+			return ATA_OP_FINISHED;
 		case IDETAPE_ABORTED_READ_RQ:
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
@@ -2791,32 +2600,25 @@
 #endif
 			rq->flags = IDETAPE_READ_RQ;
 			idetape_end_request(drive, rq, IDETAPE_ERROR_EOD);
-			return ide_stopped;
+			return ATA_OP_FINISHED;
 		case IDETAPE_PC_RQ1:
 			/* FIXME: --mdcki */
 			pc = (struct atapi_packet_command *) rq->buffer;
 			rq->flags = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
-			/* FIXME: make this unlocking go away*/
-			spin_unlock_irq(ch->lock);
 			idetape_media_access_finished(drive, rq);
-			spin_lock_irq(ch->lock);
-			return ide_stopped;
+
+			return ATA_OP_FINISHED;
 		default:
 			printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
-			/* FIXME: make this unlocking go away*/
-			spin_unlock_irq(ch->lock);
+
 			idetape_end_request(drive, rq, 0);
-			spin_lock_irq(ch->lock);
-			return ide_stopped;
+
+			return ATA_OP_FINISHED;
 	}
-	/* FIXME: make this unlocking go away*/
-	spin_unlock_irq(ch->lock);
-	ret = idetape_issue_packet_command(drive, rq, pc);
-	spin_lock_irq(ch->lock);
 
-	return ret;
+	return idetape_issue_packet_command(drive, rq, pc);
 }
 
 /*
@@ -5572,7 +5374,7 @@
  */
 static int idetape_identify_device(struct ata_device *drive,struct hd_driveid *id)
 {
-	struct idetape_id_gcw gcw;
+	struct atapi_id_gcw gcw;
 #if IDETAPE_DEBUG_INFO
 	unsigned short mask,i;
 #endif /* IDETAPE_DEBUG_INFO */
@@ -5791,14 +5593,14 @@
 	char *r;
 	idetape_tape_t *tape = drive->driver_data;
 	struct atapi_packet_command pc;
-	idetape_inquiry_result_t *inquiry;
+	atapi_inquiry_result_t *inquiry;
 
 	idetape_create_inquiry_cmd(&pc);
 	if (idetape_queue_pc_tail (drive, &pc)) {
 		printk (KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
 		return;
 	}
-	inquiry = (idetape_inquiry_result_t *) pc.buffer;
+	inquiry = (atapi_inquiry_result_t *) pc.buffer;
 	memcpy(tape->vendor_id, inquiry->vendor_id, 8);
 	memcpy(tape->product_id, inquiry->product_id, 16);
 	memcpy(tape->firmware_revision, inquiry->revision_level, 4);
@@ -5985,7 +5787,7 @@
 	unsigned long t1, tmid, tn;
 	unsigned long t;
 	int speed;
-	struct idetape_id_gcw gcw;
+	struct atapi_id_gcw gcw;
 	int stage_size;
 	struct sysinfo si;
 
diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/ide-taskfile.c	Tue Jul 16 16:49:42 2002
@@ -197,13 +197,14 @@
 int ide_do_drive_cmd(struct ata_device *drive, struct request *rq, ide_action_t action)
 {
 	unsigned long flags;
-	unsigned int major = drive->channel->major;
+	struct ata_channel *ch = drive->channel;
+	unsigned int major = ch->major;
 	request_queue_t *q = &drive->queue;
 	struct list_head *queue_head = &q->queue_head;
 	DECLARE_COMPLETION(wait);
 
 #ifdef CONFIG_BLK_DEV_PDC4030
-	if (drive->channel->chipset == ide_pdc4030 && rq->buffer != NULL)
+	if (ch->chipset == ide_pdc4030 && rq->buffer)
 		return -ENOSYS;  /* special drive cmds not supported */
 #endif
 	rq->errors = 0;
@@ -212,22 +213,18 @@
 	if (action == ide_wait)
 		rq->waiting = &wait;
 
-	spin_lock_irqsave(drive->channel->lock, flags);
+	spin_lock_irqsave(ch->lock, flags);
 
-	if (blk_queue_empty(&drive->queue) || action == ide_preempt) {
-		if (action == ide_preempt)
-			drive->rq = NULL;
-	} else {
-		if (action == ide_wait)
-			queue_head = queue_head->prev;
-		else
-			queue_head = queue_head->next;
-	}
-	q->elevator.elevator_add_req_fn(q, rq, queue_head);
+	if (action == ide_preempt)
+		drive->rq = NULL;
+	else if (!blk_queue_empty(&drive->queue))
+		queue_head = queue_head->prev;	/* ide_end and ide_wait */
+
+	__elv_add_request(q, rq, queue_head);
 
 	do_ide_request(q);
 
-	spin_unlock_irqrestore(drive->channel->lock, flags);
+	spin_unlock_irqrestore(ch->lock, flags);
 
 	if (action == ide_wait) {
 		wait_for_completion(&wait);	/* wait for it to be serviced */
@@ -235,23 +232,20 @@
 	}
 
 	return 0;
-
 }
 
 
 /*
  * Invoked on completion of a special REQ_SPECIAL command.
  */
-ide_startstop_t ata_special_intr(struct ata_device *drive, struct
+static ide_startstop_t special_intr(struct ata_device *drive, struct
 		request *rq) {
-
-	struct ata_taskfile *ar = rq->special;
-	ide_startstop_t ret = ide_stopped;
 	unsigned long flags;
+	struct ata_channel *ch =drive->channel;
+	struct ata_taskfile *ar = rq->special;
+	ide_startstop_t ret = ATA_OP_FINISHED;
 
-	ide__sti();	/* local CPU only */
-
-	spin_lock_irqsave(drive->channel->lock, flags);
+	ide__sti();
 
 	if (rq->buffer && ar->taskfile.sector_number) {
 		if (!ata_status(drive, 0, DRQ_STAT) && ar->taskfile.sector_number) {
@@ -283,24 +277,27 @@
 		ata_in_regfile(drive, &ar->hobfile);
 	}
 
+	spin_lock_irqsave(ch->lock, flags);
+
 	blkdev_dequeue_request(rq);
 	drive->rq = NULL;
 	end_that_request_last(rq);
 
-	spin_unlock_irqrestore(drive->channel->lock, flags);
+	spin_unlock_irqrestore(ch->lock, flags);
 
 	return ret;
 }
 
-int ide_raw_taskfile(struct ata_device *drive, struct ata_taskfile *ar)
+int ide_raw_taskfile(struct ata_device *drive, struct ata_taskfile *ar, char *buf)
 {
 	struct request req;
 
 	ar->command_type = IDE_DRIVE_TASK_NO_DATA;
-	ar->XXX_handler = ata_special_intr;
+	ar->XXX_handler = special_intr;
 
 	memset(&req, 0, sizeof(req));
 	req.flags = REQ_SPECIAL;
+	req.buffer = buf;
 	req.special = ar;
 
 	return ide_do_drive_cmd(drive, &req, ide_wait);
@@ -310,5 +307,4 @@
 EXPORT_SYMBOL(ide_do_drive_cmd);
 EXPORT_SYMBOL(ata_read);
 EXPORT_SYMBOL(ata_write);
-EXPORT_SYMBOL(ata_special_intr);
 EXPORT_SYMBOL(ide_raw_taskfile);
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ide/ide.c	Tue Jul 16 16:49:43 2002
@@ -106,15 +106,14 @@
 	return 0;
 }
 
-/*
- * Not locking variabt of the end_request method.
- *
- * Channel lock should be held.
- */
 int __ata_end_request(struct ata_device *drive, struct request *rq, int uptodate, unsigned int nr_secs)
 {
+	unsigned long flags;
+	struct ata_channel *ch = drive->channel;
 	int ret = 1;
 
+	spin_lock_irqsave(ch->lock, flags);
+
 	BUG_ON(!(rq->flags & REQ_STARTED));
 
 	/* FIXME: Make this "small" hack to eliminate locking from
@@ -143,22 +142,7 @@
 		ret = 0;
 	}
 
-
-	return ret;
-}
-
-/*
- * This is the default end request function as well
- */
-int ata_end_request(struct ata_device *drive, struct request *rq, int uptodate)
-{
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
-	int ret;
-
-	spin_lock_irqsave(ch->lock, flags);
-	ret = __ata_end_request(drive, rq, uptodate, 0);
-	spin_unlock_irqrestore(drive->channel->lock, flags);
+	spin_unlock_irqrestore(ch->lock, flags);
 
 	return ret;
 }
@@ -169,14 +153,16 @@
  * at the appropriate code to handle the next interrupt, and a
  * timer is started to prevent us from waiting forever in case
  * something goes wrong (see the ide_timer_expiry() handler later on).
- *
- * Channel lock should be held.
  */
 void ata_set_handler(struct ata_device *drive, ata_handler_t handler,
 		      unsigned long timeout, ata_expiry_t expiry)
 {
+	unsigned long flags;
 	struct ata_channel *ch = drive->channel;
 
+	spin_lock_irqsave(ch->lock, flags);
+
+	/* FIXME: change it later to BUG_ON(ch->handler)  --bzolnier */
 	if (ch->handler)
 		printk("%s: %s: handler not null; old=%p, new=%p, from %p\n",
 			drive->name, __FUNCTION__, ch->handler, handler, __builtin_return_address(0));
@@ -188,48 +174,35 @@
 
 	add_timer(&ch->timer);
 
+	spin_unlock_irqrestore(ch->lock, flags);
 }
 
 static void check_crc_errors(struct ata_device *drive)
 {
 	if (!drive->using_dma)
-	    return;
+		return;
 
 	/* check the DMA crc count */
 	if (drive->crc_count) {
 		udma_enable(drive, 0, 0);
 		if (drive->channel->speedproc) {
-			u8 pio = XFER_PIO_4;
+			u8 mode = drive->current_speed;
 			drive->crc_count = 0;
 
-			switch (drive->current_speed) {
-			case XFER_UDMA_7: pio = XFER_UDMA_6;
-				break;
-			case XFER_UDMA_6: pio = XFER_UDMA_5;
-				break;
-			case XFER_UDMA_5: pio = XFER_UDMA_4;
-				break;
-			case XFER_UDMA_4: pio = XFER_UDMA_3;
-				break;
-			case XFER_UDMA_3: pio = XFER_UDMA_2;
-				break;
-			case XFER_UDMA_2: pio = XFER_UDMA_1;
-				break;
-			case XFER_UDMA_1: pio = XFER_UDMA_0;
-				break;
+			if (mode > XFER_UDMA_0)
+				mode--;
+			else
 			/*
 			 * OOPS we do not goto non Ultra DMA modes
 			 * without iCRC's available we force
 			 * the system to PIO and make the user
 			 * invoke the ATA-1 ATA-2 DMA modes.
 			 */
-			case XFER_UDMA_0:
-			default:
-				pio = XFER_PIO_4;
-			}
-		        drive->channel->speedproc(drive, pio);
+				mode = XFER_PIO_4;
+
+			drive->channel->speedproc(drive, mode);
 		}
-		if (drive->current_speed >= XFER_SW_DMA_0)
+		if (drive->current_speed >= XFER_UDMA_0)
 			udma_enable(drive, 1, 1);
 	} else
 		udma_enable(drive, 0, 1);
@@ -262,19 +235,17 @@
  * Poll the interface for completion every 50ms during an ATAPI drive reset
  * operation. If the drive has not yet responded, and we have not yet hit our
  * maximum waiting time, then the timer is restarted for another 50ms.
- *
- * Channel lock should be held.
  */
 static ide_startstop_t atapi_reset_pollfunc(struct ata_device *drive, struct request *__rq)
 {
 	struct ata_channel *ch = drive->channel;
-	int ret = ide_stopped;
+	int ret = ATA_OP_FINISHED;
 
 	ata_select(drive, 10);
 	if (!ata_status(drive, 0, BUSY_STAT)) {
 		if (time_before(jiffies, ch->poll_timeout)) {
 			ata_set_handler(drive, atapi_reset_pollfunc, HZ/20, NULL);
-			ret = ide_started;	/* continue polling */
+			ret = ATA_OP_CONTINUES;	/* continue polling */
 		} else {
 			ch->poll_timeout = 0;	/* end of polling */
 			printk("%s: ATAPI reset timed out, status=0x%02x\n", drive->name, drive->status);
@@ -285,7 +256,7 @@
 		printk("%s: ATAPI reset complete\n", drive->name);
 		ch->poll_timeout = 0;	/* done polling */
 
-		ret = ide_stopped;
+		ret = ATA_OP_FINISHED;
 	}
 
 	return ret;
@@ -295,8 +266,6 @@
  * Poll the interface for completion every 50ms during an ata reset operation.
  * If the drives have not yet responded, and we have not yet hit our maximum
  * waiting time, then the timer is restarted for another 50ms.
- *
- * Channel lock should be held.
  */
 static ide_startstop_t reset_pollfunc(struct ata_device *drive, struct request *__rq)
 {
@@ -306,15 +275,17 @@
 	if (!ata_status(drive, 0, BUSY_STAT)) {
 		if (time_before(jiffies, ch->poll_timeout)) {
 			ata_set_handler(drive, reset_pollfunc, HZ/20, NULL);
-			ret = ide_started;	/* continue polling */
+			ret = ATA_OP_CONTINUES;	/* continue polling */
 		} else {
+			ch->poll_timeout = 0;	/* done polling */
 			printk("%s: reset timed out, status=0x%02x\n", ch->name, drive->status);
 			++drive->failures;
-			ret = ide_stopped;
+			ret = ATA_OP_FINISHED;
 		}
 	} else  {
 		u8 stat;
 
+		ch->poll_timeout = 0;	/* done polling */
 		printk("%s: reset: ", ch->name);
 		if ((stat = GET_ERR()) == 1) {
 			printk("success\n");
@@ -343,11 +314,10 @@
 			++drive->failures;
 		}
 
-		ret = ide_stopped;
+		ret = ATA_OP_FINISHED;
 	}
-	ch->poll_timeout = 0;	/* done polling */
 
-	return ide_stopped;
+	return ret;
 }
 
 /*
@@ -364,16 +334,14 @@
  * Equally poor, though, is the fact that this may a very long time to
  * complete, (up to 30 seconds worst case).  So, instead of busy-waiting here
  * for it, we set a timer to poll at 50ms intervals.
- *
- * Channel lock should be held.
  */
-
 static ide_startstop_t do_reset1(struct ata_device *drive, int try_atapi)
 {
 	unsigned int unit;
 	unsigned long flags;
 	struct ata_channel *ch = drive->channel;
 
+	/* FIXME:  --bzolnier */
 	__save_flags(flags);	/* local CPU only */
 	__cli();		/* local CPU only */
 
@@ -387,7 +355,7 @@
 			ata_set_handler(drive, atapi_reset_pollfunc, HZ/20, NULL);
 			__restore_flags(flags);	/* local CPU only */
 
-			return ide_started;
+			return ATA_OP_CONTINUES;
 		}
 	}
 
@@ -400,7 +368,7 @@
 
 	__restore_flags(flags);	/* local CPU only */
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 static inline u32 read_24(struct ata_device *drive)
@@ -467,6 +435,7 @@
 	unsigned long flags;
 	u8 err = 0;
 
+	/* FIXME:  --bzolnier */
 	__save_flags (flags);	/* local CPU only */
 	ide__sti();		/* local CPU only */
 
@@ -554,7 +523,7 @@
 {
 
 	if (drive->type != ATA_DISK)
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 
 	if (!IS_PDC4030_DRIVE) {
 		struct ata_taskfile args;
@@ -563,17 +532,15 @@
 		memset(&args, 0, sizeof(args));
 		args.taskfile.sector_count = drive->sect;
 		args.cmd = WIN_RESTORE;
-		ide_raw_taskfile(drive, &args);
+		ide_raw_taskfile(drive, &args, NULL);
 		printk(KERN_INFO "%s: done!\n", drive->name);
 	}
 
-	return IS_PDC4030_DRIVE ? ide_stopped : ide_started;
+	return IS_PDC4030_DRIVE ? ATA_OP_FINISHED : ATA_OP_CONTINUES;
 }
 
 /*
  * Take action based on the error returned by the drive.
- *
- * FIXME: Channel lock should be held.
  */
 ide_startstop_t ata_error(struct ata_device *drive, struct request *rq,	const char *msg)
 {
@@ -581,14 +548,16 @@
 	u8 stat = drive->status;
 
 	err = ata_dump(drive, rq, msg);
+
+	/* FIXME: at least !drive check is bogus  --bzolnier */
 	if (!drive || !rq)
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 
 	/* retry only "normal" I/O: */
 	if (!(rq->flags & REQ_CMD)) {
 		rq->errors = 1;
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	/* other bits are useless when BUSY */
@@ -599,7 +568,7 @@
 			/* err has different meaning on cdrom and tape */
 			if (err == ABRT_ERR) {
 				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
-					return ide_stopped; /* some newer drives don't support WIN_SPECIFY */
+					return ATA_OP_FINISHED; /* some newer drives don't support WIN_SPECIFY */
 			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR))
 				drive->crc_count++; /* UDMA crc error -- just retry the operation */
 			else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
@@ -617,7 +586,6 @@
 
 	if (rq->errors >= ERROR_MAX) {
 		printk(KERN_ERR "%s: max number of retries exceeded!\n", drive->name);
-		/* FIXME: make sure all end_request implementations are lock free */
 		if (ata_ops(drive) && ata_ops(drive)->end_request)
 			ata_ops(drive)->end_request(drive, rq, 0);
 		else
@@ -627,10 +595,11 @@
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET)
 			return do_reset1(drive, 1);
 		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			/* FIXME: tries to acquire the channel lock -Zwane */
 			return do_recalibrate(drive);
 	}
 
-	return ide_stopped;
+	return ATA_OP_FINISHED;
 }
 
 /*
@@ -674,8 +643,9 @@
 		block = 1;  /* redirect MBR access to EZ-Drive partn table */
 
 	ata_select(drive, 0);
-	if (ata_status_poll(drive, drive->ready_stat, BUSY_STAT | DRQ_STAT,
-				WAIT_READY, rq, &ret)) {
+	ret = ata_status_poll(drive, drive->ready_stat, BUSY_STAT | DRQ_STAT,
+				WAIT_READY, rq);
+	if (ret != ATA_OP_READY) {
 		printk(KERN_WARNING "%s: drive not ready for command\n", drive->name);
 
 		goto kill_rq;
@@ -695,38 +665,17 @@
 		ret = ata_ops(drive)->do_request(drive, rq, block);
 	} else {
 		__ata_end_request(drive, rq, 0, 0);
-		ret = ide_stopped;
+		ret = ATA_OP_FINISHED;
 	}
 	return ret;
 
 kill_rq:
-	if (ata_ops(drive)) {
-		if (ata_ops(drive)->end_request) {
-			spin_unlock_irq(ch->lock);
-			ata_ops(drive)->end_request(drive, rq, 0);
-			spin_lock_irq(ch->lock);
-		} else
-			__ata_end_request(drive, rq, 0, 0);
-	} else
+	if (ata_ops(drive) && ata_ops(drive)->end_request)
+		ata_ops(drive)->end_request(drive, rq, 0);
+	else
 		__ata_end_request(drive, rq, 0, 0);
 
-	return ide_stopped;
-}
-
-ide_startstop_t restart_request(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(ch->lock, flags);
-
-	ch->handler = NULL;
-	del_timer(&ch->timer);
-	ret = start_request(drive, drive->rq);
-	spin_unlock_irqrestore(ch->lock, flags);
-
-	return ret;
+	return ATA_OP_FINISHED;
 }
 
 /*
@@ -758,7 +707,7 @@
 		/* This device is sleeping and waiting to be serviced
 		 * later than any other device we checked thus far.
 		 */
-		if (drive->sleep && (!sleep || time_after(sleep, drive->sleep)))
+		if (drive->sleep && (!sleep || time_after(drive->sleep, sleep)))
 			sleep = drive->sleep;
 	}
 
@@ -784,7 +733,7 @@
 
 		/* There are no request pending for this device.
 		 */
-		if (list_empty(&drive->queue.queue_head))
+		if (blk_queue_empty(&drive->queue))
 			continue;
 
 		/* This device still wants to remain idle.
@@ -834,124 +783,119 @@
 	return NULL;
 }
 
-
 /*
- * Feed commands to a drive until it barfs.  Called with queue lock held and
- * busy channel.
+ * Issue a new request.
+ * Caller must have already done spin_lock_irqsave(channel->lock, ...)
  */
-static void queue_commands(struct ata_device *drive)
+static void do_request(struct ata_channel *channel)
 {
-	struct ata_channel *ch = drive->channel;
-	ide_startstop_t startstop = -1;
+	ide_get_lock(&ide_irq_lock, ata_irq_request, channel);/* for atari only: POSSIBLY BROKEN HERE(?) */
+	__cli();	/* necessary paranoia: ensure IRQs are masked on local CPU */
 
-	for (;;) {
+	while (!test_and_set_bit(IDE_BUSY, channel->active)) {
+		struct ata_channel *ch;
+		struct ata_device *drive;
 		struct request *rq = NULL;
+		ide_startstop_t startstop;
+		int i;
 
-		if (!test_bit(IDE_BUSY, ch->active))
-			printk(KERN_ERR "%s: error: not busy while queueing!\n", drive->name);
-
-		/* Abort early if we can't queue another command. for non
-		 * tcq, ata_can_queue is always 1 since we never get here
-		 * unless the drive is idle.
-		 */
-		if (!ata_can_queue(drive)) {
-			if (!ata_pending_commands(drive))
-				clear_bit(IDE_BUSY, ch->active);
-			break;
-		}
-
-		drive->sleep = 0;
+		/* this will clear IDE_BUSY, if appropriate */
+		drive = choose_urgent_device(channel);
 
-		if (test_bit(IDE_DMA, ch->active)) {
-			printk(KERN_ERR "%s: error: DMA in progress...\n", drive->name);
+		if (!drive)
 			break;
-		}
 
-		/* There's a small window between where the queue could be
-		 * replugged while we are in here when using tcq (in which
-		 * case the queue is probably empty anyways...), so check
-		 * and leave if appropriate. When not using tcq, this is
-		 * still a severe BUG!
+		/* Remember the last drive we where acting on.
 		 */
-		if (blk_queue_plugged(&drive->queue)) {
-			BUG_ON(!drive->using_tcq);
-			break;
-		}
-
-		if (!(rq = elv_next_request(&drive->queue))) {
-			if (!ata_pending_commands(drive))
-				clear_bit(IDE_BUSY, ch->active);
-			drive->rq = NULL;
-			break;
-		}
+		ch = drive->channel;
+		ch->drive = drive;
 
-		/* If there are queued commands, we can't start a non-fs
-		 * request (really, a non-queuable command) until the
-		 * queue is empty.
+		/* Make sure that all drives on channels sharing the IRQ line
+		 * with us won't generate IRQ's during our activity.
 		 */
-		if (!(rq->flags & REQ_CMD) && ata_pending_commands(drive))
-			break;
+		for (i = 0; i < MAX_HWIFS; ++i) {
+			struct ata_channel *tmp = &ide_hwifs[i];
+			int j;
 
-		drive->rq = rq;
+			if (!tmp->present)
+				continue;
 
-		ide__sti();	/* allow other IRQs while we start this request */
-		startstop = start_request(drive, rq);
+			if (ch->lock != tmp->lock)
+				continue;
 
-		/* command started, we are busy */
-		if (startstop == ide_started)
-			break;
+			/* Only care if there is any drive on the channel in
+			 * question.
+			 */
+			for (j = 0;  j < MAX_DRIVES; ++j) {
+				struct ata_device * other = &tmp->drives[j];
+
+				if (other->present)
+					ata_irq_enable(other, 0);
+			}
+		}
 
-		/* start_request() can return either ide_stopped (no command
-		 * was started), ide_started (command started, don't queue
-		 * more), or ide_released (command started, try and queue
-		 * more).
+		/*
+		 * Feed commands to a drive until it barfs.
 		 */
-#if 0
-		if (startstop == ide_stopped)
-			set_bit(IDE_BUSY, &hwgroup->flags);
-#endif
+		do {
+			if (!test_bit(IDE_BUSY, ch->active))
+				printk(KERN_ERR "%s: error: not busy while queueing!\n", drive->name);
+
+			/* Abort early if we can't queue another command. for
+			 * non tcq, ata_can_queue is always 1 since we never
+			 * get here unless the drive is idle.
+			 */
+			if (!ata_can_queue(drive)) {
+				if (!ata_pending_commands(drive))
+					clear_bit(IDE_BUSY, ch->active);
+				break;
+			}
 
-	}
-}
+			drive->sleep = 0;
 
-/*
- * Issue a new request.
- * Caller must have already done spin_lock_irqsave(channel->lock, ...)
- */
-static void do_request(struct ata_channel *channel)
-{
-	ide_get_lock(&ide_irq_lock, ata_irq_request, channel);/* for atari only: POSSIBLY BROKEN HERE(?) */
-//	__cli();	/* necessary paranoia: ensure IRQs are masked on local CPU */
-
-	while (!test_and_set_bit(IDE_BUSY, channel->active)) {
-		struct ata_channel *ch;
-		struct ata_device *drive;
+			if (test_bit(IDE_DMA, ch->active)) {
+				printk(KERN_ERR "%s: error: DMA in progress...\n", drive->name);
+				break;
+			}
 
-		/* this will clear IDE_BUSY, if appropriate */
-		drive = choose_urgent_device(channel);
+			/* There's a small window between where the queue could
+			 * be replugged while we are in here when using tcq (in
+			 * which case the queue is probably empty anyways...),
+			 * so check and leave if appropriate. When not using
+			 * tcq, this is still a severe BUG!
+			 */
+			if (blk_queue_plugged(&drive->queue)) {
+				BUG_ON(!drive->using_tcq);
+				break;
+			}
 
-		if (!drive)
-			break;
+			if (!(rq = elv_next_request(&drive->queue))) {
+				if (!ata_pending_commands(drive))
+					clear_bit(IDE_BUSY, ch->active);
+				drive->rq = NULL;
+				break;
+			}
 
-		ch = drive->channel;
+			/* If there are queued commands, we can't start a
+			 * non-fs request (really, a non-queuable command)
+			 * until the queue is empty.
+			 */
+			if (!(rq->flags & REQ_CMD) && ata_pending_commands(drive))
+				break;
 
-		/* Disable intrerrupts from the drive on the previous channel.
-		 *
-		 * FIXME: This should be only done if we are indeed sharing the same
-		 * interrupt line with it.
-		 *
-		 * FIXME: check this! It appears to act on the current channel!
-		 */
-		if (ch != channel && channel->sharing_irq && ch->irq == channel->irq)
-			ata_irq_enable(drive, 0);
+			drive->rq = rq;
 
-		/* Remember the last drive we where acting on.
-		 */
-		ch->drive = drive;
+			spin_unlock(ch->lock);
+			ide__sti();	/* allow other IRQs while we start this request */
+			startstop = start_request(drive, rq);
+			spin_lock_irq(ch->lock);
 
-		queue_commands(drive);
+			/* command started, we are busy */
+		} while (startstop != ATA_OP_CONTINUES);
+		/* make sure the BUSY bit is set */
+		/* FIXME: perhaps there is some place where we miss to set it? */
+//		set_bit(IDE_BUSY, ch->active);
 	}
-
 }
 
 void do_ide_request(request_queue_t *q)
@@ -975,7 +919,7 @@
 	del_timer(&ch->timer);
 
 	if (!ch->drive) {
-		printk(KERN_ERR "%s: IRQ handler was NULL\n", __FUNCTION__);
+		printk(KERN_ERR "%s: channel->drive was NULL\n", __FUNCTION__);
 		ch->handler = NULL;
 	} else if (!ch->handler) {
 
@@ -995,17 +939,20 @@
 
 		/* paranoia */
 		if (!test_and_set_bit(IDE_BUSY, ch->active))
-			printk(KERN_ERR "%s: %s: IRQ handler was not busy?!\n",
+			printk(KERN_ERR "%s: %s: channel was not busy?!\n",
 					drive->name, __FUNCTION__);
 
 		if (ch->expiry) {
 			unsigned long wait;
 
 			/* continue */
-			if ((wait = ch->expiry(drive, drive->rq)) != 0) {
+			ret = ch->expiry(drive, drive->rq, &wait);
+			if (ret == ATA_OP_CONTINUES) {
 				/* reengage timer */
-				ch->timer.expires  = jiffies + wait;
-				add_timer(&ch->timer);
+				if (wait) {
+					ch->timer.expires  = jiffies + wait;
+					add_timer(&ch->timer);
+				}
 
 				spin_unlock_irqrestore(ch->lock, flags);
 
@@ -1021,14 +968,14 @@
 
 		handler = ch->handler;
 		ch->handler = NULL;
-		spin_unlock(ch->lock);
 
-		ch = drive->channel;
+		spin_unlock(ch->lock);
 #if DISABLE_IRQ_NOSYNC
 		disable_irq_nosync(ch->irq);
 #else
 		disable_irq(ch->irq);	/* disable_irq_nosync ?? */
 #endif
+		/* FIXME: IRQs are already disabled by spin_lock_irqsave()  --bzolnier */
 		__cli();	/* local CPU only, as if we were handling an interrupt */
 		if (ch->poll_timeout) {
 			ret = handler(drive, drive->rq);
@@ -1072,18 +1019,16 @@
 				rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
 				rq->buffer = NULL;
 			}
-			ret = ide_stopped;
+			ret = ATA_OP_FINISHED;
 		} else
 			ret = ata_error(drive, drive->rq, "irq timeout");
 
 		enable_irq(ch->irq);
-
 		spin_lock_irq(ch->lock);
 
-		if (ret == ide_stopped)
+		if (ret == ATA_OP_FINISHED)
 			clear_bit(IDE_BUSY, ch->active);
 
-
 		/* Reenter the request handling engine */
 		do_request(ch);
 	}
@@ -1153,7 +1098,7 @@
 	struct ata_channel *ch = data;
 	unsigned long flags;
 	struct ata_device *drive;
-	ata_handler_t *handler = ch->handler;
+	ata_handler_t *handler;
 	ide_startstop_t startstop;
 
 	spin_lock_irqsave(ch->lock, flags);
@@ -1161,6 +1106,7 @@
 	if (!ide_ack_intr(ch))
 		goto out_lock;
 
+	handler = ch->handler;
 	if (handler == NULL || ch->poll_timeout != 0) {
 #if 0
 		printk(KERN_INFO "ide: unexpected interrupt %d %d\n", ch->unit, irq);
@@ -1214,10 +1160,11 @@
 	spin_unlock(ch->lock);
 
 	if (ch->unmask)
-		ide__sti();	/* local CPU only */
+		ide__sti();
 
 	/* service this interrupt, may set handler for next interrupt */
 	startstop = handler(drive, drive->rq);
+
 	spin_lock_irq(ch->lock);
 
 	/*
@@ -1227,15 +1174,14 @@
 	 * same irq as is currently being serviced here, and Linux
 	 * won't allow another of the same (on any CPU) until we return.
 	 */
-	if (startstop == ide_stopped) {
+	if (startstop == ATA_OP_FINISHED) {
 		if (!ch->handler) {	/* paranoia */
 			clear_bit(IDE_BUSY, ch->active);
 			do_request(ch);
 		} else {
 			printk("%s: %s: huh? expected NULL handler on exit\n", drive->name, __FUNCTION__);
 		}
-	} else if (startstop == ide_released)
-		queue_commands(drive);
+	}
 
 out_lock:
 	spin_unlock_irqrestore(ch->lock, flags);
@@ -1386,9 +1332,6 @@
 EXPORT_SYMBOL(ata_dump);
 EXPORT_SYMBOL(ata_error);
 
-/* FIXME: this is a trully bad name */
-EXPORT_SYMBOL(restart_request);
-EXPORT_SYMBOL(ata_end_request);
 EXPORT_SYMBOL(__ata_end_request);
 EXPORT_SYMBOL(ide_stall_queue);
 
diff -Nru a/drivers/ide/ioctl.c b/drivers/ide/ioctl.c
--- a/drivers/ide/ioctl.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/ioctl.c	Tue Jul 16 16:49:42 2002
@@ -47,7 +47,6 @@
 	u8 *argbuf = vals;
 	int argsize = 4;
 	struct ata_taskfile args;
-	struct request req;
 
 	/* Second phase.
 	 */
@@ -80,15 +79,7 @@
 
 	/* Issue ATA command and wait for completion.
 	 */
-	args.command_type = IDE_DRIVE_TASK_NO_DATA;
-	args.XXX_handler = ata_special_intr;
-
-	memset(&req, 0, sizeof(req));
-	req.flags = REQ_SPECIAL;
-	req.special = &args;
-
-	req.buffer = argbuf + 4;
-	err = ide_do_drive_cmd(drive, &req, ide_wait);
+	err = ide_raw_taskfile(drive, &args, argbuf + 4);
 
 	argbuf[0] = drive->status;
 	argbuf[1] = args.taskfile.feature;
@@ -131,9 +122,6 @@
 		case HDIO_GET_32BIT: {
 			unsigned long val = drive->channel->io_32bit;
 
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
 			if (put_user(val, (unsigned long *) arg))
 				return -EFAULT;
 			return 0;
@@ -181,9 +169,6 @@
 		case HDIO_GET_UNMASKINTR: {
 			unsigned long val = drive->channel->unmask;
 
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
 			if (put_user(val, (unsigned long *) arg))
 				return -EFAULT;
 
@@ -211,9 +196,6 @@
 		case HDIO_GET_DMA: {
 			unsigned long val = drive->using_dma;
 
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
 			if (put_user(val, (unsigned long *) arg))
 				return -EFAULT;
 
@@ -245,9 +227,6 @@
 			struct hd_geometry *loc = (struct hd_geometry *) arg;
 			unsigned short bios_cyl = drive->bios_cyl; /* truncate */
 
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
 			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
 				return -EINVAL;
 
@@ -270,9 +249,6 @@
 		case HDIO_GETGEO_BIG_RAW: {
 			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
 
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-
 			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
 				return -EINVAL;
 
@@ -293,8 +269,6 @@
 		}
 
 		case HDIO_GET_IDENTITY:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
 
 			if (minor(inode->i_rdev) & PARTN_MASK)
 				return -EINVAL;
@@ -308,8 +282,6 @@
 			return 0;
 
 		case HDIO_GET_NICE:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
 
 			return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP |
 					drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP,
@@ -332,8 +304,6 @@
 			return 0;
 
 		case HDIO_GET_BUSSTATE:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
 
 			if (put_user(drive->channel->bus_state, (long *)arg))
 				return -EFAULT;
diff -Nru a/drivers/ide/it8172.c b/drivers/ide/it8172.c
--- a/drivers/ide/it8172.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ide/it8172.c	Tue Jul 16 16:49:41 2002
@@ -179,14 +179,6 @@
 
 	return ide_config_drive_speed(drive, speed);
 }
-
-static int it8172_udma_setup(struct ata_device *drive)
-{
-	u8 speed = ata_timing_mode(drive, XFER_PIO | XFER_EPIO |
-				   XFER_SWDMA | XFER_MWDMA | XFER_UDMA);
-
-	return !it8172_tune_chipset(drive, speed);
-}
 #endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_IT8172_TUNING) */
 
 
@@ -216,15 +208,11 @@
     if (!hwif->dma_base)
 	return;
 
-#ifndef CONFIG_BLK_DEV_IDEDMA
-    hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
 # ifdef CONFIG_IT8172_TUNING
-    hwif->autodma = 1;
-    hwif->dmaproc = &it8172_dmaproc;
+	hwif->modes_map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA | XFER_UDMA;
+	hwif->udma_setup = udma_generic_setup;
     hwif->speedproc = &it8172_tune_chipset;
 # endif
-#endif
 
     cmdBase = dev->resource[0].start;
     ctrlBase = dev->resource[1].start;
diff -Nru a/drivers/ide/main.c b/drivers/ide/main.c
--- a/drivers/ide/main.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ide/main.c	Tue Jul 16 16:49:41 2002
@@ -1074,7 +1074,8 @@
 	spin_unlock_irqrestore(&ide_lock, flags);
 	/* Default autotune or requested autotune */
 	if (drive->autotune != 2) {
-		if (drive->channel->udma_setup) {
+		struct ata_channel *ch = drive->channel;
+		if (ch->udma_setup) {
 
 			/*
 			 * Force DMAing for the beginning of the check.  Some
@@ -1085,7 +1086,7 @@
 			 */
 
 			udma_enable(drive, 0, 0);
-			drive->channel->udma_setup(drive);
+			ch->udma_setup(drive, ch->modes_map);
 #ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
 			udma_tcq_enable(drive, 1);
 #endif
diff -Nru a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
--- a/drivers/ide/ns87415.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/ns87415.c	Tue Jul 16 16:49:42 2002
@@ -105,21 +105,21 @@
 	ns87415_prepare_drive(drive, 1);	/* select DMA xfer */
 
 	if (udma_pci_init(drive, rq))		/* use standard DMA stuff */
-		return ide_started;
+		return ATA_OP_CONTINUES;
 
 	ns87415_prepare_drive(drive, 0);	/* DMA failed: select PIO xfer */
 
-	return ide_stopped;
+	return ATA_OP_FINISHED;
 }
 
-static int ns87415_udma_setup(struct ata_device *drive)
+static int ns87415_udma_setup(struct ata_device *drive, int map)
 {
 	if (drive->type != ATA_DISK) {
 		udma_enable(drive, 0, 0);
 
 		return 0;
 	}
-	return udma_pci_setup(drive);
+	return udma_pci_setup(drive, map);
 }
 #endif
 
diff -Nru a/drivers/ide/pcidma.c b/drivers/ide/pcidma.c
--- a/drivers/ide/pcidma.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ide/pcidma.c	Tue Jul 16 16:49:41 2002
@@ -27,6 +27,8 @@
 #include <linux/ide.h>
 #include <linux/delay.h>
 
+#include "ata-timing.h"
+
 #include <asm/io.h>
 #include <asm/irq.h>
 
@@ -44,18 +46,9 @@
 
 	if (ata_status(drive, DRIVE_READY, drive->bad_wstat | DRQ_STAT)) {
 		if (!dma_stat) {
-			unsigned long flags;
-			struct ata_channel *ch = drive->channel;
-
-			/* FIXME: this locking should encompass the above register
-			 * file access too.
-			 */
-
-			spin_lock_irqsave(ch->lock, flags);
 			__ata_end_request(drive, rq, 1, rq->nr_sectors);
-			spin_unlock_irqrestore(ch->lock, flags);
 
-			return ide_stopped;
+			return ATA_OP_FINISHED;
 		}
 		printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n",
 		       drive->name, dma_stat);
@@ -128,7 +121,7 @@
 /*
  * 1 dma-ing, 2 error, 4 intr
  */
-static int dma_timer_expiry(struct ata_device *drive, struct request *rq)
+static ide_startstop_t dma_timer_expiry(struct ata_device *drive, struct request *rq, unsigned long *wait)
 {
 	/* FIXME: What's that? */
 	u8 dma_stat = inb(drive->channel->dma_base + 2);
@@ -140,15 +133,17 @@
 #if 0
 	drive->expiry = NULL;	/* one free ride for now */
 #endif
-
+	*wait = 0;
 	if (dma_stat & 2) {	/* ERROR */
 		ata_status(drive, 0, 0);
 		return ata_error(drive, rq, __FUNCTION__);
 	}
-	if (dma_stat & 1)	/* DMAing */
-		return WAIT_CMD;
+	if (dma_stat & 1) {	/* DMAing */
+		*wait = WAIT_CMD;
+		return ATA_OP_CONTINUES;
+	}
 
-	return 0;
+	return ATA_OP_FINISHED;
 }
 
 int ata_start_dma(struct ata_device *drive, struct request *rq)
@@ -171,10 +166,73 @@
 	return 0;
 }
 
+/* generic udma_setup() function for drivers having ->speedproc/tuneproc */
+int udma_generic_setup(struct ata_device *drive, int map)
+{
+	struct hd_driveid *id = drive->id;
+	struct ata_channel *ch = drive->channel;
+	int on = 0;
+	u8 mode;
+
+	if (!id || (drive->type != ATA_DISK && ch->no_atapi_autodma))
+		return 0;
+
+	if ((map & XFER_UDMA_80W) && !eighty_ninty_three(drive))
+		map &= ~XFER_UDMA_80W;
+
+	if ((id->capability & 1) && ch->autodma && ch->speedproc) {
+
+		/* Consult the list of known "bad" devices. */
+		if (udma_black_list(drive))
+			goto set_dma;
+
+		mode = ata_timing_mode(drive, map);
+
+		/* Device is UltraDMA capable. */
+		if (mode & XFER_UDMA) {
+			if((on = !ch->speedproc(drive, mode)))
+				goto set_dma;
+
+			printk(KERN_WARNING "%s: UDMA auto-tune failed.\n", drive->name);
+
+			map &= ~XFER_UDMA_ALL;
+			mode = ata_timing_mode(drive, map);
+		}
+
+		/* Device is regular DMA capable. */
+		if (mode & (XFER_SWDMA | XFER_MWDMA)) {
+			if((on = !ch->speedproc(drive, mode)))
+				goto set_dma;
+
+			printk(KERN_WARNING "%s: DMA auto-tune failed.\n", drive->name);
+		}
+
+		/* FIXME: this seems non-functional  --bkz */
+		/* Consult the list of known "good" devices. */
+		if (udma_white_list(drive)) {
+
+			if (id->eide_dma_time > 150)
+				goto set_dma;
+
+			printk(KERN_INFO "%s: device is on DMA whitelist.\n", drive->name);
+//			on = 1;
+		}
+
+		/* Revert to PIO. */
+		if (!on && ch->tuneproc)
+			ch->tuneproc(drive, 255);
+	}
+
+set_dma:
+	udma_enable(drive, on, !on);
+
+	return 0;
+}
+
 /*
  * Configure a device for DMA operation.
  */
-int udma_pci_setup(struct ata_device *drive)
+int udma_pci_setup(struct ata_device *drive, int map)
 {
 	int config_allows_dma = 1;
 	struct hd_driveid *id = drive->id;
@@ -399,8 +457,6 @@
 
 /*
  * Teardown mappings after DMA has completed.
- *
- * Channel lock should be held.
  */
 void udma_destroy_table(struct ata_channel *ch)
 {
@@ -411,8 +467,6 @@
  * Prepare the channel for a DMA startfer. Please note that only the broken
  * Pacific Digital host chip needs the reques to be passed there to decide
  * about addressing modes.
- *
- * Channel lock should be held.
  */
 void udma_pci_start(struct ata_device *drive, struct request *rq)
 {
@@ -426,9 +480,6 @@
 	outb(inb(dma_base) | 1, dma_base);	/* start DMA */
 }
 
-/*
- * Channel lock should be held.
- */
 int udma_pci_stop(struct ata_device *drive)
 {
 	struct ata_channel *ch = drive->channel;
@@ -445,8 +496,6 @@
 
 /*
  * FIXME: This should be attached to a channel as we can see now!
- *
- * Channel lock should be held.
  */
 int udma_pci_irq_status(struct ata_device *drive)
 {
@@ -533,19 +582,17 @@
  *
  * It's exported only for host chips which use it for fallback or (too) late
  * capability checking.
- *
- * Channel lock should be held.
  */
 int udma_pci_init(struct ata_device *drive, struct request *rq)
 {
 	u8 cmd;
 
 	if (ata_start_dma(drive, rq))
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 
 	/* No DMA transfers on ATAPI devices. */
 	if (drive->type != ATA_DISK)
-		return ide_started;
+		return ATA_OP_CONTINUES;
 
 	if (rq_data_dir(rq) == READ)
 		cmd = 0x08;
@@ -560,7 +607,7 @@
 
 	udma_start(drive, rq);
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 EXPORT_SYMBOL(ide_dma_intr);
diff -Nru a/drivers/ide/pcihost.h b/drivers/ide/pcihost.h
--- a/drivers/ide/pcihost.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/ide/pcihost.h	Tue Jul 16 16:49:41 2002
@@ -117,7 +117,6 @@
 	unsigned short		vendor;
 	unsigned short		device;
 	unsigned int		(*init_chipset)(struct pci_dev *);
-	unsigned int		(*ata66_check)(struct ata_channel *);
 	void			(*init_channel)(struct ata_channel *);
 	void			(*init_dma)(struct ata_channel *, unsigned long);
 	ide_pci_enablebit_t	enablebits[2];
diff -Nru a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c
--- a/drivers/ide/pdc202xx.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ide/pdc202xx.c	Tue Jul 16 16:49:43 2002
@@ -129,29 +129,30 @@
 	return 0;
 }
 
-static int pdc202xx_ratemask(struct ata_device *drive)
+static int __init pdc202xx_modes_map(struct ata_channel *ch)
 {
-	struct pci_dev *dev = drive->channel->pci_dev;
-	int map = 0;
-
-	if (!eighty_ninty_three(drive))
-		return XFER_UDMA;
+	int map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA | XFER_UDMA;
 
-	switch(dev->device) {
+	switch(ch->pci_dev->device) {
 		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20275:
 		case PCI_DEVICE_ID_PROMISE_20269:
 			map |= XFER_UDMA_133;
 		case PCI_DEVICE_ID_PROMISE_20268R:
 		case PCI_DEVICE_ID_PROMISE_20268:
+			map &= ~XFER_SWDMA;
 		case PCI_DEVICE_ID_PROMISE_20267:
 		case PCI_DEVICE_ID_PROMISE_20265:
 			map |= XFER_UDMA_100;
 		case PCI_DEVICE_ID_PROMISE_20262:
 			map |= XFER_UDMA_66;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			map |= XFER_UDMA;
+
+			if (!ch->udma_four) {
+				printk(KERN_WARNING "%s: 40-pin cable, speed reduced to UDMA(33) mode.\n", ch->name);
+				map &= ~XFER_UDMA_80W;
+			}
 	}
+
 	return map;
 }
 
@@ -164,9 +165,6 @@
 	u8 DP;
 #endif
 
-	if (drive->dn > 3) /* FIXME: remove this --bkz */
-		return -1;
-
 	drive_pci = 0x60 + (drive->dn << 2);
 
 	if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0))
@@ -372,48 +370,34 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-/* FIXME: split this for old & new chipsets (jumpbit) --bkz */
-static int config_chipset_for_dma(struct ata_device *drive, byte udma)
+static int pdc202xx_tx_udma_setup(struct ata_device *drive, int map)
+{
+	struct hd_driveid *id = drive->id;
+	struct ata_channel *ch = drive->channel;
+	u32 indexreg = ch->dma_base + 1;
+	u32 datareg = indexreg + 2;
+	u8 adj = (drive->dn % 2) ? 0x08 : 0x00;
+
+	if (drive->type != ATA_DISK)
+		return 0;
+
+	/* IORDY_EN & PREFETCH_EN */
+	if (id->capability & 4)
+		set_2regs(0x13, (IN_BYTE(datareg)|0x03));
+
+	return udma_generic_setup(drive, map);
+}
+
+static int pdc202xx_udma_setup(struct ata_device *drive, int map)
 {
-	struct hd_driveid *id	= drive->id;
+	struct hd_driveid *id = drive->id;
 	struct ata_channel *hwif = drive->channel;
 	struct hd_driveid *mate_id = hwif->drives[!(drive->dn%2)].id;
-	struct pci_dev *dev	= hwif->pci_dev;
+	struct pci_dev *dev = hwif->pci_dev;
 	u32 high_16 = pci_resource_start(dev, 4);
-	u32 dma_base = hwif->dma_base;
-	u32 indexreg = dma_base + 1;
-	u32 datareg = dma_base + 3;
-	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
-	u8 jumpbit;
 	u32 drive_conf;
 	u8 drive_pci = 0, AP, tmp, mode = -1;
 	u8 CLKSPD, mask = hwif->unit ? 0x08 : 0x02;
-	int map;
-
-	/* UDMA 3, 4, 5 and 6 */
-	u8 needs_80w = (id->dma_ultra & 0x0078);
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20262:
-		case PCI_DEVICE_ID_PROMISE_20246:
-			jumpbit = 0;
-			break;
-		default: /* chipsets newer then 20267 */
-			jumpbit = 1;
-			break;
-	}
-
-	/* FIXME: this check is wrong for 20246  --bkz */
-	/* */
-	if (needs_80w && !hwif->udma_four) {
-		printk(KERN_WARNING "%s: channel requires an 80-pin cable.\n", hwif->name);
-		printk(KERN_INFO "%s: reduced to UDMA(33) mode.\n", drive->name);
-	}
-
-	if (jumpbit)
-		goto chipset_is_set;
 
 	/*
 	 * Set the control register to use the 66Mhz system
@@ -427,7 +411,7 @@
 	 * FIXME: move this to pdc202xx_tuneproc()
 	 *        right now you can't downgrade from U66 to U33  --bkz
 	 */
-	if (needs_80w) {
+	if (id->dma_ultra & 0x0078) {	/* UDMA 3, 4, 5 and 6 */
 		CLKSPD = IN_BYTE(high_16 + PDC_CLK);
 		/* check cable and mate (must be at least udma3 capable) */
 		if (!hwif->udma_four ||
@@ -449,12 +433,11 @@
 	/* FIXME: what if SYNC_ERRDY is enabled for slave
 		  and disabled for master? --bkz */
 	pci_read_config_byte(dev, drive_pci, &AP);
+	/* enable SYNC_ERRDY for master and slave (if enabled for master) */
 	if (!(AP & SYNC_ERRDY_EN)) {
-		if (drive->dn == 0 || drive->dn == 2) {
-			/* enable SYNC_ERRDY for master */
+		if (!(drive->dn % 2)) {
 			pci_write_config_byte(dev, drive_pci, AP|SYNC_ERRDY_EN);
 		} else {
-			/* enable SYNC_ERRDY for slave if enabled for master */
 			pci_read_config_byte(dev, drive_pci - 4, &tmp);
 			if (tmp & SYNC_ERRDY_EN)
 				pci_write_config_byte(dev, drive_pci, AP|SYNC_ERRDY_EN);
@@ -466,85 +449,26 @@
 	if (drive->type != ATA_DISK)
 		return 0;
 
-	if (jumpbit) {
-		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
-			set_2regs(0x13, (IN_BYTE(datareg)|0x03));
-		}
-	} else {
-		pci_read_config_byte(dev, drive_pci, &AP);
-		if (id->capability & 4)		/* IORDY_EN */
-			pci_write_config_byte(dev, drive_pci, AP|IORDY_EN);
-		pci_read_config_byte(dev, drive_pci, &AP);
-		if (drive->type == ATA_DISK)	/* PREFETCH_EN */
-			pci_write_config_byte(dev, drive_pci, AP|PREFETCH_EN);
-	}
+	pci_read_config_byte(dev, drive_pci, &AP);
+	if (id->capability & 4)		/* IORDY_EN */
+		pci_write_config_byte(dev, drive_pci, AP|IORDY_EN);
+	pci_read_config_byte(dev, drive_pci, &AP);
+	if (drive->type == ATA_DISK)	/* PREFETCH_EN */
+		pci_write_config_byte(dev, drive_pci, AP|PREFETCH_EN);
 
-	if (udma) {
-		map = pdc202xx_ratemask(drive);
-	} else {
-		if (!jumpbit)
-			map = XFER_SWDMA | XFER_MWDMA;
-		else
-			map = XFER_MWDMA;
-	}
+	map = hwif->modes_map;
+
+	if (!eighty_ninty_three(drive))
+		map &= ~XFER_UDMA_80W;
 
 	mode = ata_timing_mode(drive, map);
 	if (mode < XFER_SW_DMA_0) {
 		/* restore original pci-config space */
-		if (!jumpbit)
-			pci_write_config_dword(dev, drive_pci, drive_conf);
+		pci_write_config_dword(dev, drive_pci, drive_conf);
 		return 0;
 	}
 
-	return !hwif->speedproc(drive, mode);
-}
-
-static int pdc202xx_udma_setup(struct ata_device *drive)
-{
-	struct hd_driveid *id = drive->id;
-	struct ata_channel *hwif = drive->channel;
-	int on = 0;
-	int verbose = 1;
-
-	if (id && (id->capability & 1) && hwif->autodma) {
-		/* Consult the list of known "bad" drives */
-		verbose = 0;
-		if (udma_black_list(drive))
-			goto no_dma_set;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				on = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (!on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				on = config_chipset_for_dma(drive, 0);
-				if (!on)
-					goto no_dma_set;
-			}
-		} else if (udma_white_list(drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			on = config_chipset_for_dma(drive, 0);
-			if (!on)
-				goto no_dma_set;
-		} else goto no_dma_set;
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-no_dma_set:
-		pdc202xx_tune_drive(drive, 255);
-	}
-
-	udma_enable(drive, on, verbose);
-
-	return 0;
+	return udma_generic_setup(drive, map);
 }
 
 static void pdc202xx_udma_start(struct ata_device *drive, struct request *rq)
@@ -725,12 +649,20 @@
 		case PCI_DEVICE_ID_PROMISE_20269:
 		case PCI_DEVICE_ID_PROMISE_20268:
 		case PCI_DEVICE_ID_PROMISE_20268R:
+			hwif->udma_four = pdc202xx_tx_ata66_check(hwif);
+
 			hwif->speedproc = &pdc202xx_new_tune_chipset;
 			hwif->resetproc = &pdc202xx_new_reset;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+			if (hwif->dma_base)
+				hwif->udma_setup = pdc202xx_tx_udma_setup;
+#endif
 			break;
 		case PCI_DEVICE_ID_PROMISE_20267:
 		case PCI_DEVICE_ID_PROMISE_20265:
 		case PCI_DEVICE_ID_PROMISE_20262:
+			hwif->udma_four = pdc202xx_ata66_check(hwif);
+
 			hwif->resetproc	= &pdc202xx_reset;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 			/* we need special functions for lba48 */
@@ -741,6 +673,10 @@
 #endif
 		/* FIXME: check whether 20246 works with lba48 --bkz */
 		case PCI_DEVICE_ID_PROMISE_20246:
+#ifdef CONFIG_BLK_DEV_IDEDMA
+			if (hwif->dma_base)
+				hwif->udma_setup = pdc202xx_udma_setup;
+#endif
 			hwif->speedproc = &pdc202xx_tune_chipset;
 		default:
 			break;
@@ -748,18 +684,15 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
+		hwif->modes_map = pdc202xx_modes_map(hwif);
 		hwif->udma_irq_lost = pdc202xx_bug;
 		hwif->udma_timeout = pdc202xx_bug;
-		hwif->udma_setup = pdc202xx_udma_setup;
 		hwif->highmem = 1;
-		if (!noautodma)
-			hwif->autodma = 1;
 	} else
 #endif
 	{
 		hwif->drives[0].autotune = 1;
 		hwif->drives[1].autotune = 1;
-		hwif->autodma = 0;
 	}
 }
 
@@ -770,7 +703,6 @@
 		vendor: PCI_VENDOR_ID_PROMISE,
 		device: PCI_DEVICE_ID_PROMISE_20246,
 		init_chipset: pdc202xx_init_chipset,
-		ata66_check: NULL,
 		init_channel: ide_init_pdc202xx,
 #ifndef CONFIG_PDC202XX_FORCE
 		enablebits: {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
@@ -783,7 +715,6 @@
 		vendor: PCI_VENDOR_ID_PROMISE,
 		device: PCI_DEVICE_ID_PROMISE_20262,
 		init_chipset: pdc202xx_init_chipset,
-		ata66_check: pdc202xx_ata66_check,
 		init_channel: ide_init_pdc202xx,
 #ifndef CONFIG_PDC202XX_FORCE
 		enablebits: {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
@@ -796,7 +727,6 @@
 		vendor: PCI_VENDOR_ID_PROMISE,
 		device: PCI_DEVICE_ID_PROMISE_20265,
 		init_chipset: pdc202xx_init_chipset,
-		ata66_check: pdc202xx_ata66_check,
 		init_channel: ide_init_pdc202xx,
 #ifndef CONFIG_PDC202XX_FORCE
 		enablebits: {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
@@ -811,7 +741,6 @@
 		vendor: PCI_VENDOR_ID_PROMISE,
 		device: PCI_DEVICE_ID_PROMISE_20267,
 		init_chipset: pdc202xx_init_chipset,
-		ata66_check: pdc202xx_ata66_check,
 		init_channel: ide_init_pdc202xx,
 #ifndef CONFIG_PDC202XX_FORCE
 		enablebits: {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
@@ -824,7 +753,6 @@
 		vendor: PCI_VENDOR_ID_PROMISE,
 		device: PCI_DEVICE_ID_PROMISE_20268,
 		init_chipset: pdc202xx_tx_init_chipset,
-		ata66_check: pdc202xx_tx_ata66_check,
 		init_channel: ide_init_pdc202xx,
 		bootable: OFF_BOARD,
 		flags: ATA_F_IRQ | ATA_F_DMA
@@ -837,7 +765,6 @@
 		vendor: PCI_VENDOR_ID_PROMISE,
 		device: PCI_DEVICE_ID_PROMISE_20268R,
 		init_chipset: pdc202xx_tx_init_chipset,
-		ata66_check: pdc202xx_tx_ata66_check,
 		init_channel: ide_init_pdc202xx,
 		bootable: OFF_BOARD,
 		flags: ATA_F_IRQ  | ATA_F_DMA
@@ -846,7 +773,6 @@
 		vendor: PCI_VENDOR_ID_PROMISE,
 		device: PCI_DEVICE_ID_PROMISE_20269,
 		init_chipset: pdc202xx_tx_init_chipset,
-		ata66_check: pdc202xx_tx_ata66_check,
 		init_channel: ide_init_pdc202xx,
 		bootable: OFF_BOARD,
 		flags: ATA_F_IRQ | ATA_F_DMA
@@ -855,7 +781,6 @@
 		vendor: PCI_VENDOR_ID_PROMISE,
 		device: PCI_DEVICE_ID_PROMISE_20275,
 		init_chipset: pdc202xx_tx_init_chipset,
-		ata66_check: pdc202xx_tx_ata66_check,
 		init_channel: ide_init_pdc202xx,
 		bootable: OFF_BOARD,
 		flags: ATA_F_IRQ | ATA_F_DMA
@@ -864,7 +789,6 @@
 		vendor: PCI_VENDOR_ID_PROMISE,
 		device: PCI_DEVICE_ID_PROMISE_20276,
 		init_chipset: pdc202xx_tx_init_chipset,
-		ata66_check: pdc202xx_tx_ata66_check,
 		init_channel: ide_init_pdc202xx,
 		bootable: OFF_BOARD,
 		flags: ATA_F_IRQ | ATA_F_DMA
diff -Nru a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c
--- a/drivers/ide/pdc4030.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ide/pdc4030.c	Tue Jul 16 16:49:41 2002
@@ -230,7 +230,7 @@
 	struct ata_channel *hwif2;
 	struct dc_ident ident;
 	int i;
-	ide_startstop_t startstop;
+	ide_startstop_t ret;
 
 	if (!hwif)
 		return 0;
@@ -250,8 +250,8 @@
 
 	/* FIXME: Make this go away. */
 	spin_lock_irq(hwif->lock);
-	if (ata_status_poll(drive, DATA_READY, BAD_W_STAT,
-				WAIT_DRQ, NULL, &startstop)) {
+	ret = ata_status_poll(drive, DATA_READY, BAD_W_STAT, WAIT_DRQ, NULL);
+	if (ret != ATA_OP_READY) {
 		printk(KERN_INFO
 			"%s: Failed Promise read config!\n",hwif->name);
 		spin_unlock_irq(hwif->lock);
@@ -414,10 +414,8 @@
 	rq->errors = 0;
 	rq->nr_sectors -= nsect;
 	total_remaining = rq->nr_sectors;
-	if ((rq->current_nr_sectors -= nsect) <= 0) {
-		/* FIXME: no queue locking above! */
-		ata_end_request(drive, rq, 1);
-	}
+	if ((rq->current_nr_sectors -= nsect) <= 0)
+		__ata_end_request(drive, rq, 1, 0);
 
 	/*
 	 * Now the data has been read in, do the following:
@@ -437,27 +435,18 @@
 		if (drive->status & DRQ_STAT)
 			goto read_again;
 		if (drive->status & BUSY_STAT) {
-			unsigned long flags;
-			struct ata_channel *ch = drive->channel;
-
-			/* FIXME: this locking should encompass the above register
-			 * file access too.
-			 */
-
-			spin_lock_irqsave(ch->lock, flags);
 			ata_set_handler(drive, promise_read_intr, WAIT_CMD, NULL);
-			spin_unlock_irqrestore(ch->lock, flags);
 #ifdef DEBUG_READ
 			printk(KERN_DEBUG "%s: promise_read: waiting for"
 			       "interrupt\n", drive->name);
 #endif
-			return ide_started;
+			return ATA_OP_CONTINUES;
 		}
 		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
 		       "!DRQ !BUSY\n", drive->name);
 		return ata_error(drive, rq, "promise read intr");
 	}
-	return ide_stopped;
+	return ATA_OP_FINISHED;
 }
 
 /*
@@ -470,20 +459,13 @@
  */
 static ide_startstop_t promise_complete_pollfunc(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
 	struct ata_channel *ch = drive->channel;
 
 	if (!ata_status(drive, 0, BUSY_STAT)) {
 		if (time_before(jiffies, ch->poll_timeout)) {
-			/* FIXME: this locking should encompass the above
-			 * register file access too.
-			 */
-
-			spin_lock_irqsave(ch->lock, flags);
 			ata_set_handler(drive, promise_complete_pollfunc, HZ/100, NULL);
-			spin_unlock_irqrestore(ch->lock, flags);
 
-			return ide_started; /* continue polling... */
+			return ATA_OP_CONTINUES; /* continue polling... */
 		}
 		ch->poll_timeout = 0;
 		printk(KERN_ERR "%s: completion timeout - still busy!\n",
@@ -495,15 +477,9 @@
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
 #endif
-	/* FIXME: this locking should encompass the above
-	 * register file access too.
-	 */
-
-	spin_lock_irqsave(ch->lock, flags);
 	__ata_end_request(drive, rq, 1, rq->nr_sectors);
-	spin_unlock_irqrestore(ch->lock, flags);
 
-	return ide_stopped;
+	return ATA_OP_FINISHED;
 }
 
 /*
@@ -563,21 +539,17 @@
  */
 static ide_startstop_t promise_write_pollfunc(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
 	struct ata_channel *ch = drive->channel;
 
-	spin_lock_irqsave(ch->lock, flags);
 	if (inb(IDE_NSECTOR_REG) != 0) {
 		if (time_before(jiffies, ch->poll_timeout)) {
 			ata_set_handler(drive, promise_write_pollfunc, HZ/100, NULL);
-			spin_unlock_irqrestore(ch->lock, flags);
 
-			return ide_started; /* continue polling... */
+			return ATA_OP_CONTINUES; /* continue polling... */
 		}
 		ch->poll_timeout = 0;
 		printk(KERN_ERR "%s: write timed out!\n", drive->name);
 		ata_status(drive, 0, 0);
-		spin_unlock_irqrestore(ch->lock, flags);
 
 		return ata_error(drive, rq, "write timeout");
 	}
@@ -592,8 +564,8 @@
 	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
 		drive->name, drive->status);
 #endif
-	spin_unlock_irqrestore(ch->lock, flags);
-	return ide_started;
+
+	return ATA_OP_CONTINUES;
 }
 
 /*
@@ -605,7 +577,6 @@
  */
 static ide_startstop_t promise_do_write(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
 	struct ata_channel *ch = drive->channel;
 
 #ifdef DEBUG_WRITE
@@ -613,43 +584,35 @@
 	       "buffer=%p\n", drive->name, rq->sector,
 	       rq->sector + rq->nr_sectors - 1, rq->buffer);
 #endif
-	/* FIXME: this locking should encompass the above register
-	 * file access too.
-	 */
-
-	spin_lock_irqsave(ch->lock, flags);
 	/*
 	 * If there are more than 4 sectors to transfer, do n-4 then go into
 	 * the polling strategy as defined above.
 	 */
 	if (rq->nr_sectors > 4) {
 		if (promise_multwrite(drive, rq, rq->nr_sectors - 4)) {
-			spin_unlock_irqrestore(ch->lock, flags);
-			return ide_stopped;
+
+			return ATA_OP_FINISHED;
 		}
 		ch->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ata_set_handler(drive, promise_write_pollfunc, HZ/100, NULL);
-		spin_unlock_irqrestore(ch->lock, flags);
 
-		return ide_started;
+		return ATA_OP_CONTINUES;
 	} else {
 	/*
 	 * There are 4 or fewer sectors to transfer, do them all in one go
 	 * and wait for NOT BUSY.
 	 */
-		if (promise_multwrite(drive, rq, rq->nr_sectors)) {
-			spin_unlock_irqrestore(ch->lock, flags);
-			return ide_stopped;
-		}
+		if (promise_multwrite(drive, rq, rq->nr_sectors))
+			return ATA_OP_FINISHED;
+
 		ch->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ata_set_handler(drive, promise_complete_pollfunc, HZ/100, NULL);
-		spin_unlock_irqrestore(ch->lock, flags);
 
 #ifdef DEBUG_WRITE
 		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
 			"status = %02x\n", drive->name, drive->status);
 #endif
-		return ide_started;
+		return ATA_OP_CONTINUES;
 	}
 }
 
@@ -666,9 +629,9 @@
 	/* Check that it's a regular command. If not, bomb out early. */
 	if (!(rq->flags & REQ_CMD)) {
 		blk_dump_rq_flags(rq, "pdc4030 bad flags");
-		ata_end_request(drive, rq, 0);
+		__ata_end_request(drive, rq, 0, 0);
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	ata_irq_enable(drive, 1);
@@ -701,34 +664,23 @@
 				return promise_read_intr(drive, rq);
 			}
 			if (inb(IDE_SELECT_REG) & 0x01) {
-				unsigned long flags;
-				struct ata_channel *ch = drive->channel;
-
-				/* FIXME: this locking should encompass the above register
-				 * file access too.
-				 */
-
-				spin_lock_irqsave(ch->lock, flags);
 #ifdef DEBUG_READ
 				printk(KERN_DEBUG "%s: read: waiting for "
 				                  "interrupt\n", drive->name);
 #endif
 				ata_set_handler(drive, promise_read_intr, WAIT_CMD, NULL);
-				spin_unlock_irqrestore(ch->lock, flags);
 
-				return ide_started;
+				return ATA_OP_CONTINUES;
 			}
 			udelay(1);
 		} while (time_before(jiffies, timeout));
 
 		printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n",
 			drive->name);
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 
 	case WRITE: {
-		ide_startstop_t startstop;
-		unsigned long flags;
-		struct ata_channel *ch = drive->channel;
+		ide_startstop_t ret;
 
 		/*
 		 * Strategy on write is: look for the DRQ that should have been
@@ -740,29 +692,25 @@
 		 * completion must be polled
 		 */
 
-		/* FIXME: Move this lock upwards.
-		 */
-		spin_lock_irqsave(ch->lock, flags);
-		if (ata_status_poll(drive, DATA_READY, drive->bad_wstat,
-					WAIT_DRQ, rq, &startstop )) {
+		ret = ata_status_poll(drive, DATA_READY, drive->bad_wstat,
+					WAIT_DRQ, rq);
+		if (ret != ATA_OP_READY) {
 			printk(KERN_ERR "%s: no DRQ after issuing "
 			       "PROMISE_WRITE\n", drive->name);
-			spin_unlock_irqrestore(ch->lock, flags);
 
-			return startstop;
+			return ret;
 		}
 		if (!drive->channel->unmask)
 			__cli();	/* local CPU only */
-		spin_unlock_irqrestore(ch->lock, flags);
 
 		return promise_do_write(drive, rq);
 	}
 
 	default:
 		printk(KERN_ERR "pdc4030: command not READ or WRITE! Huh?\n");
-		/* FIXME: This should already run under the lock. */
-		ata_end_request(drive, rq, 0);
-		return ide_stopped;
+
+		__ata_end_request(drive, rq, 0, 0);
+		return ATA_OP_FINISHED;
 	}
 }
 
diff -Nru a/drivers/ide/piix.c b/drivers/ide/piix.c
--- a/drivers/ide/piix.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ide/piix.c	Tue Jul 16 16:49:43 2002
@@ -244,26 +244,18 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-
-static int piix_udma_setup(struct ata_device *drive)
+static int __init piix_modes_map(struct ata_channel *ch)
 {
-	short w80 = drive->channel->udma_four;
-
-	short speed = ata_timing_mode(drive,
-			XFER_PIO | XFER_EPIO |
-			(piix_config->flags & PIIX_NODMA ? 0 : (XFER_SWDMA | XFER_MWDMA |
-			(piix_config->flags & PIIX_UDMA ? XFER_UDMA : 0) |
-			(w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_66 ? XFER_UDMA_66 : 0) |
-			(w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100 ? XFER_UDMA_100 : 0) |
-			(w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_133 ? XFER_UDMA_133 : 0))));
-
-	piix_set_drive(drive, speed);
-
-	udma_enable(drive, drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO, 0);
+	short w80 = ch->udma_four;
+	int map = XFER_EPIO |
+		  (piix_config->flags & PIIX_NODMA ? 0 : (XFER_SWDMA | XFER_MWDMA |
+		  (piix_config->flags & PIIX_UDMA ? XFER_UDMA : 0) |
+		  (w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_66 ? XFER_UDMA_66 : 0) |
+		  (w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100 ? XFER_UDMA_100 : 0) |
+		  (w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_133 ? XFER_UDMA_133 : 0)));
 
-	return 0;
+	return map;
 }
-
 #endif
 
 /*
@@ -360,9 +352,10 @@
 {
 	int i;
 
+	ch->udma_four = piix_ata66_check(ch);
+
 	ch->tuneproc = &piix_tune_drive;
 	ch->speedproc = &piix_set_drive;
-	ch->autodma = 0;
 	ch->io_32bit = 1;
 	ch->unmask = 1;
 	for (i = 0; i < 2; i++) {
@@ -373,11 +366,8 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (ch->dma_base) {
 		ch->highmem = 1;
-		ch->udma_setup = piix_udma_setup;
-# ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			ch->autodma = 1;
-# endif
+		ch->modes_map = piix_modes_map(ch);
+		ch->udma_setup = udma_generic_setup;
 	}
 #endif
 }
@@ -401,7 +391,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82371FB_1,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -411,7 +400,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82371SB_1,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -421,7 +409,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82371AB,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -431,7 +418,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82443MX_1,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -441,7 +427,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82372FB_1,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -451,7 +436,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82801AA_1,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -461,7 +445,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82801AB_1,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -471,7 +454,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82801BA_9,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -481,7 +463,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82801BA_8,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -491,7 +472,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82801E_9,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -501,7 +481,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82801CA_10,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -511,7 +490,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82801CA_11,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -521,7 +499,6 @@
 		vendor: PCI_VENDOR_ID_INTEL,
 		device: PCI_DEVICE_ID_INTEL_82801DB_9,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
@@ -531,7 +508,6 @@
 		vendor: PCI_VENDOR_ID_EFAR,
 		device: PCI_DEVICE_ID_EFAR_SLC90E66_1,
 		init_chipset: piix_init_chipset,
-		ata66_check: piix_ata66_check,
 		init_channel: piix_init_channel,
 		init_dma: piix_init_dma,
 		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
diff -Nru a/drivers/ide/probe.c b/drivers/ide/probe.c
--- a/drivers/ide/probe.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ide/probe.c	Tue Jul 16 16:49:41 2002
@@ -312,8 +312,7 @@
 int ide_config_drive_speed(struct ata_device *drive, byte speed)
 {
 	struct ata_channel *ch = drive->channel;
-	int i;
-	int error = 1;
+	int ret;
 
 #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(__CRIS__)
 	u8 unit = (drive->select.b.unit & 0x01);
@@ -338,33 +337,14 @@
 	if (drive->quirk_list == 2)
 		ata_irq_enable(drive, 1);
 	udelay(1);
-
-	/* FIXME: use ata_status_poll()  --bkz */
-
-	ata_busy_poll(drive, WAIT_CMD);
-
-	/*
-	 * Allow status to settle, then read it again.
-	 * A few rare drives vastly violate the 400ns spec here,
-	 * so we'll wait up to 10usec for a "good" status
-	 * rather than expensively fail things immediately.
-	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
-	 */
-	for (i = 0; i < 10; i++) {
-		udelay(1);
-		if (ata_status(drive, DRIVE_READY, BUSY_STAT | DRQ_STAT | ERR_STAT)) {
-			error = 0;
-			break;
-		}
-	}
-
+	ret = ata_status_poll(drive, 0, BUSY_STAT, WAIT_CMD, NULL);
 	ata_mask(drive);
 
 	enable_irq(ch->irq);
 
-	if (error) {
+	if (ret != ATA_OP_READY) {
 		ata_dump(drive, NULL, "set drive speed");
-		return error;
+		return 1;
 	}
 
 	drive->id->dma_ultra &= ~0xFF00;
@@ -399,7 +379,7 @@
 
 	drive->current_speed = speed;
 
-	return error;
+	return 0;
 }
 
 static inline void do_identify(struct ata_device *drive, u8 cmd)
diff -Nru a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
--- a/drivers/ide/serverworks.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/serverworks.c	Tue Jul 16 16:49:42 2002
@@ -103,15 +103,11 @@
 
 static struct pci_dev *isa_dev;
 
-static int svwks_ratemask(struct ata_device *drive)
+static int __init svwks_modes_map(struct ata_channel *ch)
 {
-	struct pci_dev *dev = drive->channel->pci_dev;
-	int map = 0;
+	int map = XFER_EPIO | XFER_MWDMA;
 
-	if (!eighty_ninty_three(drive))
-		return XFER_UDMA;
-
-	switch(dev->device) {
+	switch(ch->pci_dev->device) {
 		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
 			if (svwks_revision >= SVWKS_CSB5_REVISION_NEW)
 				map |= XFER_UDMA_100;
@@ -120,6 +116,7 @@
 			map |= XFER_UDMA;
 			break;
 	}
+
 	return map;
 }
 
@@ -176,6 +173,7 @@
 			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
 			break;
 
+		/* FIXME: check SWDMA modes  --bkz */
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
@@ -224,79 +222,13 @@
 	return ide_config_drive_speed(drive, speed);
 }
 
+/* FIXME: pio == 255 -> ata_best_pio_mode(drive)  --bkz */
 static void svwks_tune_drive(struct ata_device *drive, u8 pio)
 {
 	(void) svwks_tune_chipset(drive, XFER_PIO_0 + min_t(u8, pio, 4));
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma(struct ata_device *drive)
-{
-	int map;
-	u8 mode;
-
-	/* FIXME: check SWDMA modes --bkz */
-	map = XFER_MWDMA | svwks_ratemask(drive);
-	mode = ata_timing_mode(drive, map);
-
-	return !svwks_tune_chipset(drive, mode);
-}
-
-static int svwks_udma_setup(struct ata_device *drive)
-{
-	struct hd_driveid *id = drive->id;
-	int on = 1;
-	int verbose = 1;
-
-	if (id && (id->capability & 1) && drive->channel->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (udma_black_list(drive)) {
-			on = 0;
-			goto fast_ata_pio;
-		}
-		on = 0;
-		verbose = 0;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				on = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (!on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x007)) {
-				/* Force if Capable regular DMA modes */
-				on = config_chipset_for_dma(drive);
-				if (!on)
-					goto no_dma_set;
-			}
-		} else if (udma_white_list(drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			on = config_chipset_for_dma(drive);
-			if (!on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		on = 0;
-		verbose = 0;
-no_dma_set:
-		svwks_tune_chipset(drive, ata_best_pio_mode(drive));
-	}
-
-	udma_enable(drive, on, verbose);
-
-	return 0;
-}
-
 static int svwks_udma_stop(struct ata_device *drive)
 {
 	struct ata_channel *ch = drive->channel;
@@ -437,24 +369,21 @@
 	if (!hwif->irq)
 		hwif->irq = hwif->unit ? 15 : 14;
 
+	hwif->udma_four = svwks_ata66_check(hwif);
+
 	hwif->tuneproc = &svwks_tune_drive;
 	hwif->speedproc = &svwks_tune_chipset;
 
 #ifndef CONFIG_BLK_DEV_IDEDMA
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
 #else
 	if (hwif->dma_base) {
-#ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-#endif
+		hwif->modes_map = svwks_modes_map(hwif);
+		hwif->udma_setup = udma_generic_setup;
 		hwif->udma_stop = svwks_udma_stop;
-		hwif->udma_setup = svwks_udma_setup;
 		hwif->highmem = 1;
 	} else {
-		hwif->autodma = 0;
 		hwif->drives[0].autotune = 1;
 		hwif->drives[1].autotune = 1;
 	}
@@ -468,7 +397,6 @@
 		vendor: PCI_VENDOR_ID_SERVERWORKS,
 		device: PCI_DEVICE_ID_SERVERWORKS_OSB4IDE,
 		init_chipset: svwks_init_chipset,
-		ata66_check: svwks_ata66_check,
 		init_channel: ide_init_svwks,
 		bootable: ON_BOARD,
 		flags: ATA_F_DMA
@@ -477,7 +405,6 @@
 		vendor: PCI_VENDOR_ID_SERVERWORKS,
 		device: PCI_DEVICE_ID_SERVERWORKS_CSB5IDE,
 		init_chipset: svwks_init_chipset,
-		ata66_check: svwks_ata66_check,
 		init_channel: ide_init_svwks,
 		bootable: ON_BOARD,
 		flags: ATA_F_SIMPLEX
diff -Nru a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
--- a/drivers/ide/sis5513.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/sis5513.c	Tue Jul 16 16:49:42 2002
@@ -207,9 +207,9 @@
 
 static struct pci_dev *host_dev = NULL;
 
-static int sis5513_ratemask(struct ata_device *drive)
+static int __init sis5513_modes_map(struct ata_channel *ch)
 {
-	int map = 0;
+	int map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA;
 
 	switch(chipset_family) {
 		case ATA_133:	/* map |= XFER_UDMA_133; */
@@ -221,15 +221,8 @@
 		case ATA_33:
 			map |= XFER_UDMA;
 			break;
-		case ATA_16:
-		case ATA_00:
-		default:
-			return 0;
 	}
 
-	if (!eighty_ninty_three(drive))
-		return XFER_UDMA;
-
 	return map;
 }
 
@@ -280,9 +273,6 @@
 	       drive->dn, pio, timing);
 #endif
 
-	if (drive->dn > 3)	/* FIXME: remove this  --bkz */
-		return 1;
-
 	drive_pci = 0x40 + (drive->dn << 1);
 
 	/* register layout changed with newer ATA100 chips */
@@ -404,86 +394,6 @@
 	(void)config_art_rwp_pio(drive, min_t(u8, pio, 4));
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma(struct ata_device *drive, u8 udma)
-{
-	int map;
-	u8 mode;
-
-#ifdef DEBUG
-	printk("SIS5513: config_chipset_for_dma, drive %d, udma %d\n",
-	       drive->dn, udma);
-#endif
-
-	if (udma)
-		map = sis5513_ratemask(drive);
-	else
-		map = XFER_SWDMA | XFER_MWDMA;
-
-	mode = ata_timing_mode(drive, map);
-	if (mode < XFER_SW_DMA_0)
-		return 0;
-
-	return !sis5513_tune_chipset(drive, mode);
-}
-
-static int sis5513_udma_setup(struct ata_device *drive)
-{
-	struct hd_driveid *id = drive->id;
-	int on = 0;
-	int verbose = 1;
-
-	config_drive_art_rwp(drive);
-	sis5513_tune_drive(drive, 255);
-
-	if (id && (id->capability & 1) && drive->channel->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (udma_black_list(drive)) {
-			on = 0;
-			goto fast_ata_pio;
-		}
-		on = 0;
-		verbose = 0;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				on = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (!on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				on = config_chipset_for_dma(drive, 0);
-				if (!on)
-					goto no_dma_set;
-			}
-		} else if ((udma_white_list(drive)) &&
-			   (id->eide_dma_time > 150)) {
-			/* Consult the list of known "good" drives */
-			on = config_chipset_for_dma(drive, 0);
-			if (!on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		on = 0;
-		verbose = 0;
-no_dma_set:
-		sis5513_tune_drive(drive, 255);
-	}
-
-	udma_enable(drive, on, verbose);
-
-	return 0;
-}
-#endif
-
 /* Chip detection and general config */
 static unsigned int __init pci_init_sis5513(struct pci_dev *dev)
 {
@@ -576,25 +486,19 @@
 
 	hwif->irq = hwif->unit ? 15 : 14;
 
+	hwif->udma_four = ata66_sis5513(hwif);
+
 	hwif->tuneproc = &sis5513_tune_drive;
 	hwif->speedproc = &sis5513_tune_chipset;
 
-	if (!(hwif->dma_base))
-		return;
-
-	if (host_dev) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (chipset_family > ATA_16) {
-			hwif->autodma = noautodma ? 0 : 1;
-			hwif->highmem = 1;
-			hwif->udma_setup = sis5513_udma_setup;
-		} else {
-#endif
-			hwif->autodma = 0;
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		}
-#endif
+	if (hwif->dma_base && host_dev && chipset_family > ATA_16) {
+		hwif->highmem = 1;
+		hwif->modes_map = sis5513_modes_map(hwif);
+		hwif->udma_setup = udma_generic_setup;
 	}
+#endif
+
 	return;
 }
 
@@ -604,11 +508,9 @@
 	vendor: PCI_VENDOR_ID_SI,
 	device: PCI_DEVICE_ID_SI_5513,
 	init_chipset: pci_init_sis5513,
-	ata66_check: ata66_sis5513,
 	init_channel: ide_init_sis5513,
 	enablebits: {{0x4a,0x02,0x02}, {0x4a,0x04,0x04} },
 	bootable: ON_BOARD,
-	flags: ATA_F_NOADMA
 };
 
 int __init init_sis5513(void)
diff -Nru a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
--- a/drivers/ide/sl82c105.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ide/sl82c105.c	Tue Jul 16 16:49:42 2002
@@ -130,7 +130,7 @@
  * Check to see if the drive and
  * chipset is capable of DMA mode
  */
-static int sl82c105_dma_setup(struct ata_device *drive)
+static int sl82c105_dma_setup(struct ata_device *drive, int map)
 {
 	int on = 0;
 
@@ -333,7 +333,6 @@
 		dma_state &= ~0x60;
 	} else {
 		dma_state |= 0x60;
-		ch->autodma = 1;
 	}
 	outb(dma_state, dma_base + 2);
 
diff -Nru a/drivers/ide/tcq.c b/drivers/ide/tcq.c
--- a/drivers/ide/tcq.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ide/tcq.c	Tue Jul 16 16:49:43 2002
@@ -57,22 +57,23 @@
 
 static ide_startstop_t tcq_nop_handler(struct ata_device *drive, struct request *rq)
 {
-	struct ata_taskfile *args = rq->special;
 	unsigned long flags;
+	struct ata_taskfile *args = rq->special;
+	struct ata_channel *ch = drive->channel;
 
 	ide__sti();
 
-	spin_lock_irqsave(drive->channel->lock, flags);
+	spin_lock_irqsave(ch->lock, flags);
 
 	blkdev_dequeue_request(rq);
 	drive->rq = NULL;
 	end_that_request_last(rq);
 
-	spin_unlock_irqrestore(drive->channel->lock, flags);
+	spin_unlock_irqrestore(ch->lock, flags);
 
 	kfree(args);
 
-	return ide_stopped;
+	return ATA_OP_FINISHED;
 }
 
 /*
@@ -116,9 +117,9 @@
 		goto out;
 	}
 
-	rq = blk_get_request(&drive->queue, READ, GFP_ATOMIC);
+	rq = __blk_get_request(&drive->queue, READ);
 	if (!rq)
-		rq = blk_get_request(&drive->queue, WRITE, GFP_ATOMIC);
+		rq = __blk_get_request(&drive->queue, WRITE);
 
 	/*
 	 * blk_queue_invalidate_tags() just added back at least one command
@@ -126,6 +127,8 @@
 	 */
 	BUG_ON(!rq);
 
+	/* WIN_NOP is a special request so set it's flags ?? */
+	rq->flags = REQ_SPECIAL;
 	rq->special = ar;
 	ar->cmd = WIN_NOP;
 	ar->XXX_handler = tcq_nop_handler;
@@ -168,7 +171,7 @@
 	 * if pending commands, try service before giving up
 	 */
 	if (ata_pending_commands(drive) && !ata_status(drive, 0, SERVICE_STAT))
-		if (service(drive, drive->rq) == ide_started)
+		if (service(drive, drive->rq) == ATA_OP_CONTINUES)
 			return;
 
 	if (drive)
@@ -228,13 +231,10 @@
  * and it must have reported a need for service (status has SERVICE_STAT set)
  *
  * Also, nIEN must be set as not to need protection against ide_dmaq_intr
- *
- * Channel lock should be held.
  */
 static ide_startstop_t service(struct ata_device *drive, struct request *rq)
 {
 	struct ata_channel *ch = drive->channel;
-	ide_startstop_t ret;
 	unsigned long flags;
 	u8 feat, stat;
 	int tag;
@@ -246,7 +246,7 @@
 	 * handler, refuse to do anything.
 	 */
 	if (test_bit(IDE_DMA, drive->channel->active))
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 
 	/*
 	 * need to select the right drive first...
@@ -266,7 +266,7 @@
 		ata_dump(drive, rq, "BUSY clear took too long");
 		tcq_invalidate_queue(drive);
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 #ifdef IDE_TCQ_NIEN
@@ -280,7 +280,7 @@
 		ata_dump(drive, rq, "ERR condition");
 		tcq_invalidate_queue(drive);
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	/*
@@ -289,7 +289,7 @@
 	if ((feat = GET_FEAT()) & NSEC_REL) {
 		drive->rq = NULL;
 		printk("%s: release in service\n", drive->name);
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	tag = feat >> 3;
@@ -302,20 +302,19 @@
 	if (!rq) {
 		printk(KERN_ERR"%s: missing request for tag %d\n", __FUNCTION__, tag);
 		spin_unlock_irqrestore(ch->lock, flags);
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	drive->rq = rq;
 
+	spin_unlock_irqrestore(ch->lock, flags);
 	/*
 	 * we'll start a dma read or write, device will trigger
 	 * interrupt to indicate end of transfer, release is not allowed
 	 */
 	TCQ_PRINTK("%s: starting command %x\n", __FUNCTION__, stat);
 
-	ret = udma_tcq_start(drive, rq);
-	spin_unlock_irqrestore(ch->lock, flags);
-	return ret;
+	return udma_tcq_start(drive, rq);
 }
 
 static ide_startstop_t check_service(struct ata_device *drive, struct request *rq)
@@ -323,7 +322,7 @@
 	TCQ_PRINTK("%s: %s\n", drive->name, __FUNCTION__);
 
 	if (!ata_pending_commands(drive))
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 
 	if (!ata_status(drive, 0, SERVICE_STAT))
 		return service(drive, rq);
@@ -333,13 +332,11 @@
 	 */
 	set_irq(drive, ide_dmaq_intr);
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 static ide_startstop_t dmaq_complete(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	u8 dma_stat;
 
 	/*
@@ -354,7 +351,7 @@
 		ata_dump(drive, rq, __FUNCTION__);
 		tcq_invalidate_queue(drive);
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	if (dma_stat)
@@ -362,13 +359,7 @@
 
 	TCQ_PRINTK("%s: ending %p, tag %d\n", __FUNCTION__, rq, rq->tag);
 
-	/* FIXME: this locking should encompass the above register
-	 * file access too.
-	 */
-
-	spin_lock_irqsave(ch->lock, flags);
 	__ata_end_request(drive, rq, !dma_stat, rq->nr_sectors);
-	spin_unlock_irqrestore(ch->lock, flags);
 
 	/*
 	 * we completed this command, check if we can service a new command
@@ -441,7 +432,7 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.feature = 0x01;
 	args.cmd = WIN_NOP;
-	ide_raw_taskfile(drive, &args);
+	ide_raw_taskfile(drive, &args, NULL);
 	if (args.taskfile.feature & ABRT_ERR)
 		return 1;
 
@@ -469,7 +460,7 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.feature = SETFEATURES_EN_WCACHE;
 	args.cmd = WIN_SETFEATURES;
-	if (ide_raw_taskfile(drive, &args)) {
+	if (ide_raw_taskfile(drive, &args, NULL)) {
 		printk("%s: failed to enable write cache\n", drive->name);
 		return 1;
 	}
@@ -481,7 +472,7 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.feature = SETFEATURES_DIS_RI;
 	args.cmd = WIN_SETFEATURES;
-	if (ide_raw_taskfile(drive, &args)) {
+	if (ide_raw_taskfile(drive, &args, NULL)) {
 		printk("%s: disabling release interrupt fail\n", drive->name);
 		return 1;
 	}
@@ -493,7 +484,7 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.feature = SETFEATURES_EN_SI;
 	args.cmd = WIN_SETFEATURES;
-	if (ide_raw_taskfile(drive, &args)) {
+	if (ide_raw_taskfile(drive, &args, NULL)) {
 		printk("%s: enabling service interrupt fail\n", drive->name);
 		return 1;
 	}
@@ -532,8 +523,6 @@
 /*
  * Invoked from a SERVICE interrupt, command etc already known.  Just need to
  * start the dma engine for this tag.
- *
- * Channel lock should be held.
  */
 static ide_startstop_t udma_tcq_start(struct ata_device *drive, struct request *rq)
 {
@@ -544,21 +533,19 @@
 		printk("queued_rw: IDE_BUSY not set\n");
 
 	if (tcq_wait_dataphase(drive))
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 
 	if (ata_start_dma(drive, rq))
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 
 	__set_irq(ch, ide_dmaq_intr);
 	udma_start(drive, rq);
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 /*
  * Start a queued command from scratch.
- *
- * Channel lock should be held.
  */
 ide_startstop_t udma_tcq_init(struct ata_device *drive, struct request *rq)
 {
@@ -582,7 +569,7 @@
 	if (wait_altstat(drive, &stat, BUSY_STAT)) {
 		ata_dump(drive, rq, "queued start");
 		tcq_invalidate_queue(drive);
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 #ifdef IDE_TCQ_NIEN
@@ -591,7 +578,7 @@
 
 	if (stat & ERR_STAT) {
 		ata_dump(drive, rq, "tcq_start");
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 
 	/*
@@ -601,14 +588,14 @@
 	if ((feat = GET_FEAT()) & NSEC_REL) {
 		drive->immed_rel++;
 		drive->rq = NULL;
-		__set_irq(drive->channel, ide_dmaq_intr);
+		set_irq(drive, ide_dmaq_intr);
 
 		TCQ_PRINTK("REL in queued_start\n");
 
 		if (!ata_status(drive, 0, SERVICE_STAT))
 			return service(drive, rq);
 
-		return ide_released;
+		return ATA_OP_RELEASED;
 	}
 
 	TCQ_PRINTK("IMMED in queued_start\n");
diff -Nru a/drivers/ide/trm290.c b/drivers/ide/trm290.c
--- a/drivers/ide/trm290.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ide/trm290.c	Tue Jul 16 16:49:41 2002
@@ -209,7 +209,7 @@
 #ifdef TRM290_NO_DMA_WRITES
 		trm290_prepare_drive(drive, 0);	/* select PIO xfer */
 
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 #endif
 	} else {
 		reading = 2;
@@ -218,7 +218,7 @@
 
 	if (!(count = udma_new_table(drive, rq))) {
 		trm290_prepare_drive(drive, 0);	/* select PIO xfer */
-		return ide_stopped;	/* try PIO instead of DMA */
+		return ATA_OP_FINISHED;	/* try PIO instead of DMA */
 	}
 
 	trm290_prepare_drive(drive, 1);	/* select DMA xfer */
@@ -231,7 +231,7 @@
 		outb(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 	}
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 static int trm290_udma_irq_status(struct ata_device *drive)
@@ -239,9 +239,9 @@
 	return (inw(drive->channel->dma_base + 2) == 0x00ff);
 }
 
-static int trm290_udma_setup(struct ata_device *drive)
+static int trm290_udma_setup(struct ata_device *drive, int map)
 {
-	return udma_pci_setup(drive);
+	return udma_pci_setup(drive, map);
 }
 #endif
 
@@ -303,7 +303,6 @@
 #endif
 
 	hwif->selectproc = &trm290_selectproc;
-	hwif->autodma = 0;				/* play it safe for now */
 #if 1
 	{
 		/*
diff -Nru a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
--- a/drivers/ide/via82cxxx.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ide/via82cxxx.c	Tue Jul 16 16:49:43 2002
@@ -221,22 +221,16 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int via82cxxx_udma_setup(struct ata_device *drive)
+static int __init via_modes_map(struct ata_channel *ch)
 {
-	short w80 = drive->channel->udma_four;
+	short w80 = ch->udma_four;
+	int map = XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
+		  (via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
+		  (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
+		  (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
+		  (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0);
 
-	short speed = ata_timing_mode(drive,
-			XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
-			(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
-
-	via_set_drive(drive, speed);
-
-	udma_enable(drive, drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO, 0);
-
-	return 0;
+	return map;
 }
 #endif
 
@@ -352,9 +346,10 @@
 {
 	int i;
 
+	hwif->udma_four = via82cxxx_ata66_check(hwif);
+
 	hwif->tuneproc = &via82cxxx_tune_drive;
 	hwif->speedproc = &via_set_drive;
-	hwif->autodma = 0;
 	hwif->io_32bit = 1;
 
 	hwif->unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
@@ -366,11 +361,8 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
 		hwif->highmem = 1;
-		hwif->udma_setup = via82cxxx_udma_setup;
-# ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-# endif
+		hwif->modes_map = via_modes_map(hwif);
+		hwif->udma_setup = udma_generic_setup;
 	}
 #endif
 }
@@ -391,23 +383,19 @@
 		vendor: PCI_VENDOR_ID_VIA,
 		device:	PCI_DEVICE_ID_VIA_82C576_1,
 		init_chipset: via82cxxx_init_chipset,
-		ata66_check: via82cxxx_ata66_check,
 		init_channel: via82cxxx_init_channel,
 		init_dma: via82cxxx_init_dma,
 		enablebits: {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
 		bootable: ON_BOARD,
-		flags: ATA_F_NOADMA
 	},
 	{
 		vendor:	PCI_VENDOR_ID_VIA,
 		device:	PCI_DEVICE_ID_VIA_82C586_1,
 		init_chipset: via82cxxx_init_chipset,
-		ata66_check: via82cxxx_ata66_check,
 		init_channel: via82cxxx_init_channel,
 		init_dma: via82cxxx_init_dma,
 		enablebits: {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
 		bootable: ON_BOARD,
-		flags: ATA_F_NOADMA
 	},
 };
 
diff -Nru a/drivers/ieee1394/Config.in b/drivers/ieee1394/Config.in
--- a/drivers/ieee1394/Config.in	Tue Jul 16 16:49:43 2002
+++ b/drivers/ieee1394/Config.in	Tue Jul 16 16:49:43 2002
@@ -9,22 +9,33 @@
     if [ "$CONFIG_IEEE1394" != "n" ]; then
 
 	comment "Device Drivers"
-	dep_tristate '  Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394
-	if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
-	    bool '    Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM
-	    bool '    Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS
+
+	if [ "$CONFIG_I2C" = "n" -o "$CONFIG_I2C_ALGOBIT" = "n" ]; then
+	    comment '  Texas Instruments PCILynx requires I2C bit-banging'
+	else
+	    dep_tristate '  Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394 $CONFIG_I2C $CONFIG_I2C_ALGOBIT
 	fi
+
+	# Non-maintained pcilynx options
+	# if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
+	#     bool '    Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM
+	#     bool '    Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS
+	# fi
+
 	dep_tristate '  OHCI-1394 support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394
 
 	comment "Protocol Drivers"
 	dep_tristate '  OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394
 	dep_tristate '  SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394
+	if [ "$CONFIG_IEEE1394_SBP2" != "n" ]; then
+	    bool '    Enable Phys DMA support for SBP2 (Debug)' CONFIG_IEEE1394_SBP2_PHYS_DMA
+	fi
 	dep_tristate '  Ethernet over 1394' CONFIG_IEEE1394_ETH1394 $CONFIG_IEEE1394
 	dep_tristate '  OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394
 	dep_tristate '  Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
 	dep_tristate '  IEC61883-1 Plug support' CONFIG_IEEE1394_CMP $CONFIG_IEEE1394
 
-	if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
+	if [ "$CONFIG_IEEE1394_CMP" != "n" ]; then
 	    dep_tristate '    IEC61883-6 (Audio transmission) support' CONFIG_IEEE1394_AMDTP $CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394_CMP
 	fi
 
diff -Nru a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
--- a/drivers/ieee1394/Makefile	Tue Jul 16 16:49:43 2002
+++ b/drivers/ieee1394/Makefile	Tue Jul 16 16:49:43 2002
@@ -2,8 +2,11 @@
 # Makefile for the Linux IEEE 1394 implementation
 #
 
+O_TARGET := ieee1394drv.o
+
 export-objs := ieee1394_core.o ohci1394.o cmp.o
 
+list-multi := ieee1394.o
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
 		 highlevel.o csr.o nodemgr.o
 
@@ -19,3 +22,6 @@
 obj-$(CONFIG_IEEE1394_CMP) += cmp.o
 
 include $(TOPDIR)/Rules.make
+
+ieee1394.o: $(ieee1394-objs)
+	$(LD) -r -o $@ $(ieee1394-objs)
diff -Nru a/drivers/ieee1394/amdtp.c b/drivers/ieee1394/amdtp.c
--- a/drivers/ieee1394/amdtp.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ieee1394/amdtp.c	Tue Jul 16 16:49:43 2002
@@ -1110,7 +1110,7 @@
 
 static int __init amdtp_init_module (void)
 {
-	if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL,
+	if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_AMDTP,
 				      THIS_MODULE, &amdtp_fops)) {
 		HPSB_ERR("amdtp: unable to get minor device block");
  		return -EIO;
@@ -1120,7 +1120,7 @@
 						   &amdtp_highlevel_ops);
 	if (amdtp_highlevel == NULL) {
 		HPSB_ERR("amdtp: unable to register highlevel ops");
-		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL);
+		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
 		return -EIO;
 	}
 
@@ -1132,7 +1132,7 @@
 static void __exit amdtp_exit_module (void)
 {
         hpsb_unregister_highlevel(amdtp_highlevel);
-        ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL);
+        ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
 
 	HPSB_INFO("Unloaded AMDTP driver");
 }
diff -Nru a/drivers/ieee1394/dv1394-private.h b/drivers/ieee1394/dv1394-private.h
--- a/drivers/ieee1394/dv1394-private.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/ieee1394/dv1394-private.h	Tue Jul 16 16:49:41 2002
@@ -460,7 +460,7 @@
 	   This is a regular int, but use test_and_set_bit() (on bit zero) 
 	   for atomicity.
 	 */
-	int open;
+	unsigned long open;
 
 	/* 
 	   2) the spinlock - this provides mutual exclusion between the interrupt
diff -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
--- a/drivers/ieee1394/dv1394.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ieee1394/dv1394.c	Tue Jul 16 16:49:43 2002
@@ -53,6 +53,7 @@
     via pci_alloc_consistent()
     
   DONE:
+  - restart IT DMA after a bus reset
   - safely obtain and release ISO Tx channels in cooperation with OHCI driver
   - map received DIF blocks to their proper location in DV frame (ensure
     recovery if dropped packet)
@@ -192,71 +193,19 @@
 /* Memory management functions */
 /*******************************/
 
-#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
-
-/* [DaveM] I've recoded most of this so that:
- * 1) It's easier to tell what is happening
- * 2) It's more portable, especially for translating things
- *    out of vmalloc mapped areas in the kernel.
- * 3) Less unnecessary translations happen.
- *
- * The code used to assume that the kernel vmalloc mappings
- * existed in the page tables of every process, this is simply
- * not guarenteed.  We now use pgd_offset_k which is the
- * defined way to get at the kernel page tables.
- */
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline struct page *uvirt_to_page(pgd_t *pgd, unsigned long adr)
-{
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-	struct page *ret = NULL;
-	
-	if (!pgd_none(*pgd)) {
-                pmd = pmd_offset(pgd, adr);
-                if (!pmd_none(*pmd)) {
-                        ptep = pte_offset_kernel(pmd, adr);
-                        pte = *ptep;
-                        if(pte_present(pte))
-				ret = pte_page(pte);
-                }
-        }
-	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, and for
- * handling page faults on the rvmalloc()ed buffer
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr) 
-{
-        unsigned long va, kva, ret;
-
-        va = VMALLOC_VMADDR(adr);
-	kva = (unsigned long) page_address(uvirt_to_page(pgd_offset_k(va), va));
-	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
-	ret = __pa(kva);
-        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
-        return ret;
-}
-
 static void * rvmalloc(unsigned long size)
 {
 	void * mem;
-	unsigned long adr, page;
-        
+	unsigned long adr;
+
+	size = PAGE_ALIGN(size);
 	mem=vmalloc_32(size);
 	if (mem) {
 		memset(mem, 0, size); /* Clear the ram out, 
 					 no junk to the user */
 	        adr=(unsigned long) mem;
 		while (size > 0) {
-	                page = kvirt_to_pa(adr);
-			mem_map_reserve(virt_to_page(__va(page)));
+			mem_map_reserve(vmalloc_to_page((void *)adr));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -266,13 +215,12 @@
 
 static void rvfree(void * mem, unsigned long size)
 {
-        unsigned long adr, page;
-        
+        unsigned long adr;
+
 	if (mem) {
 	        adr=(unsigned long) mem;
 		while (size > 0) {
-	                page = kvirt_to_pa(adr);
-			mem_map_unreserve(virt_to_page(__va(page)));
+			mem_map_unreserve(vmalloc_to_page((void *)adr));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -1166,9 +1114,9 @@
 		
 		/* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */
 		for(i = 0; i < video->user_dma.n_pages; i++) {
-			unsigned long va = VMALLOC_VMADDR( (unsigned long) video->user_buf + i * PAGE_SIZE );
+			unsigned long va = (unsigned long) video->user_buf + i * PAGE_SIZE;
 			
-			video->user_dma.sglist[i].page = uvirt_to_page(pgd_offset_k(va), va);
+			video->user_dma.sglist[i].page = vmalloc_to_page((void *)va);
 			video->user_dma.sglist[i].length = PAGE_SIZE;
 		}
 		
@@ -1492,7 +1440,7 @@
 static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access)
 {
 	unsigned long offset;
-	unsigned long page, kernel_virt_addr;
+	unsigned long kernel_virt_addr;
 	struct page *ret = NOPAGE_SIGBUS;
 
 	struct video_card *video = (struct video_card*) area->vm_private_data;
@@ -1510,10 +1458,7 @@
 
 	offset = address - area->vm_start;
 	kernel_virt_addr = (unsigned long) video->user_buf + offset;
-
-	page = kvirt_to_pa(kernel_virt_addr);
-	
-	ret = virt_to_page(__va(page));
+	ret = vmalloc_to_page((void *)kernel_virt_addr);
 	get_page(ret);
 
  out:
@@ -2936,9 +2881,129 @@
 	dv1394_init(ohci, DV1394_PAL, MODE_TRANSMIT);
 }
 
+
+/* Bus reset handler. In the event of a bus reset, we may need to
+   re-start the DMA contexts - otherwise the user program would
+   end up waiting forever.
+*/
+
+static void dv1394_host_reset(struct hpsb_host *host)
+{
+	struct ti_ohci *ohci;
+	struct video_card *video = NULL;
+	unsigned long flags;
+	struct list_head *lh;
+	
+	/* We only work with the OHCI-1394 driver */
+	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
+		return;
+
+	ohci = (struct ti_ohci *)host->hostdata;
+
+
+	/* find the corresponding video_cards */
+	spin_lock_irqsave(&dv1394_cards_lock, flags);
+	if(!list_empty(&dv1394_cards)) {
+		list_for_each(lh, &dv1394_cards) {
+			video = list_entry(lh, struct video_card, list);
+			if((video->id >> 2) == ohci->id)
+				break;
+		}
+	}
+	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+
+	if(!video)
+		return;
+
+	/* check IT context */
+	if(video->ohci_it_ctx != -1) {
+		u32 ctx;
+		
+		spin_lock_irqsave(&video->spinlock, flags);
+		
+		ctx = reg_read(video->ohci, video->ohci_IsoXmitContextControlSet);
+
+		/* if(RUN but not ACTIVE) */
+		if( (ctx & (1<<15)) &&
+		    !(ctx & (1<<10)) ) {
+
+			debug_printk("dv1394: IT context stopped due to bus reset; waking it up\n");
+
+			/* to be safe, assume a frame has been dropped. User-space programs
+			   should handle this condition like an underflow. */
+			video->dropped_frames++;
+			
+			/* for some reason you must clear, then re-set the RUN bit to restart DMA */
+			
+			/* clear RUN */
+			reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
+			flush_pci_write(video->ohci);
+			
+			/* set RUN */
+			reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 15));
+			flush_pci_write(video->ohci);
+			
+			/* set the WAKE bit (just in case; this isn't strictly necessary) */
+			reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 12));
+			flush_pci_write(video->ohci);
+
+			irq_printk("dv1394: AFTER IT restart ctx 0x%08x ptr 0x%08x\n",
+				   reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
+				   reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
+		}
+
+		spin_unlock_irqrestore(&video->spinlock, flags);
+	}
+	
+	/* check IR context */
+	if(video->ohci_ir_ctx != -1) {
+		u32 ctx;
+		
+		spin_lock_irqsave(&video->spinlock, flags);
+		
+		ctx = reg_read(video->ohci, video->ohci_IsoRcvContextControlSet);
+
+		/* if(RUN but not ACTIVE) */
+		if( (ctx & (1<<15)) &&
+		    !(ctx & (1<<10)) ) {
+
+			debug_printk("dv1394: IR context stopped due to bus reset; waking it up\n");
+
+			/* to be safe, assume a frame has been dropped. User-space programs
+			   should handle this condition like an overflow. */
+			video->dropped_frames++;
+
+			/* for some reason you must clear, then re-set the RUN bit to restart DMA */
+			/* XXX this doesn't work for me, I can't get IR DMA to restart :[ */
+			
+			/* clear RUN */
+			reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
+			flush_pci_write(video->ohci);
+			
+			/* set RUN */
+			reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 15));
+			flush_pci_write(video->ohci);
+			
+			/* set the WAKE bit (just in case; this isn't strictly necessary) */
+			reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
+			flush_pci_write(video->ohci);
+
+			irq_printk("dv1394: AFTER IR restart ctx 0x%08x ptr 0x%08x\n",
+				   reg_read(video->ohci, video->ohci_IsoRcvContextControlSet),
+				   reg_read(video->ohci, video->ohci_IsoRcvCommandPtr));
+		}
+
+		spin_unlock_irqrestore(&video->spinlock, flags);
+	}
+
+	/* wake readers/writers/ioctl'ers */
+	wake_up_interruptible(&video->waitq);
+}
+
 static struct hpsb_highlevel_ops hl_ops = {
 	add_host:	dv1394_add_host,
 	remove_host:	dv1394_remove_host,
+	host_reset:     dv1394_host_reset,
 };
 
 
diff -Nru a/drivers/ieee1394/dv1394.h b/drivers/ieee1394/dv1394.h
--- a/drivers/ieee1394/dv1394.h	Tue Jul 16 16:49:43 2002
+++ b/drivers/ieee1394/dv1394.h	Tue Jul 16 16:49:43 2002
@@ -123,6 +123,67 @@
    frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that
    it may transmit the new frames.
 
+   ERROR HANDLING
+
+   An error (buffer underflow/overflow or a break in the DV stream due
+   to a 1394 bus reset) can be detected by checking the dropped_frames
+   field of struct dv1394_status (obtained through the
+   DV1394_GET_STATUS ioctl).
+
+   The best way to recover from such an error is to re-initialize
+   dv1394, either by using the DV1394_INIT ioctl call, or closing the
+   file descriptor and opening it again. (note that you must unmap all
+   ringbuffer mappings when closing the file descriptor, or else
+   dv1394 will still be considered 'in use').
+
+   MAIN LOOP
+
+   For maximum efficiency and robustness against bus errors, you are
+   advised to model the main loop of your application after the
+   following pseudo-code example:
+
+   (checks of system call return values omitted for brevity; always
+   check return values in your code!)
+   
+   while( frames left ) {
+   
+    struct pollfd *pfd = ...;
+
+    pfd->fd = dv1394_fd;
+    pfd->revents = 0;
+    pfd->events = POLLOUT | POLLIN; (OUT for transmit, IN for receive)
+
+    (add other sources of I/O here)
+    
+    poll(pfd, 1, -1); (or select(); add a timeout if you want)
+
+    if(pfd->revents) {
+         struct dv1394_status status;
+	 
+         ioctl(dv1394_fd, DV1394_GET_STATUS, &status);
+
+	 if(status.dropped_frames > 0) {
+	      reset_dv1394();
+         } else {
+              for(int i = 0; i < status.n_clear_frames; i++) {
+	          copy_DV_frame();
+              }
+         }
+    }
+   }
+
+   where copy_DV_frame() reads or writes on the dv1394 file descriptor
+   (read/write mode) or copies data to/from the mmap ringbuffer and
+   then calls ioctl(DV1394_SUBMIT_FRAMES) to notify dv1394 that new
+   frames are availble (mmap mode).
+
+   reset_dv1394() is called in the event of a buffer
+   underflow/overflow or a halt in the DV stream (e.g. due to a 1394
+   bus reset). To guarantee recovery from the error, this function
+   should close the dv1394 file descriptor (and munmap() all
+   ringbuffer mappings, if you are using them), then re-open the
+   dv1394 device (and re-map the ringbuffer).
+   
 */
 
 
@@ -218,6 +279,13 @@
 	unsigned int syt_offset;
 };
 
+/* NOTE: you may only allocate the DV frame ringbuffer once each time
+   you open the dv1394 device. DV1394_INIT will fail if you call it a
+   second time with different 'n_frames' or 'format' arguments (which
+   would imply a different size for the ringbuffer). If you need a
+   different buffer size, simply close and re-open the device, then
+   initialize it with your new settings. */
+   
 /* Q: What are cip_n and cip_d? */
 
 /*
@@ -262,8 +330,9 @@
 	   ready to be filled with data */
 	unsigned int n_clear_frames;
 
-	/* how many times the DV output has underflowed
-	   since the last call to DV1394_GET_STATUS */
+	/* how many times the DV stream has underflowed, overflowed,
+	   or otherwise encountered an error, since the previous call
+	   to DV1394_GET_STATUS */
 	unsigned int dropped_frames;
 
 	/* N.B. The dropped_frames counter is only a lower bound on the actual
diff -Nru a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
--- a/drivers/ieee1394/hosts.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ieee1394/hosts.c	Tue Jul 16 16:49:42 2002
@@ -124,7 +124,7 @@
 
         h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL);
         if (!h) return NULL;
-        memset(h, 0, sizeof(struct hpsb_host));
+        memset(h, 0, sizeof(struct hpsb_host) + extra);
 
 	h->hostdata = h + 1;
         h->driver = drv;
diff -Nru a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
--- a/drivers/ieee1394/hosts.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/ieee1394/hosts.h	Tue Jul 16 16:49:41 2002
@@ -31,6 +31,7 @@
         u32 tlabel_pool[2];
         struct semaphore tlabel_count;
         spinlock_t tlabel_lock;
+	u32 tlabel_current;
 
         unsigned char iso_listen_count[64];
 
diff -Nru a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
--- a/drivers/ieee1394/ieee1394_core.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ieee1394/ieee1394_core.c	Tue Jul 16 16:49:42 2002
@@ -740,7 +740,8 @@
         host->ops->devctl(host, CANCEL_REQUESTS, 0);
 
         spin_lock_irqsave(&host->pending_pkt_lock, flags);
-        list_splice_init(&host->pending_packets, &llist);
+        list_splice(&host->pending_packets, &llist);
+        INIT_LIST_HEAD(&host->pending_packets);
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
         list_for_each(lh, &llist) {
@@ -905,17 +906,16 @@
 
 	/* printk("ieee1394_dispatch_open(%d)", blocknum); */
 
-	/* lock the whole kernel here, to prevent a driver from
-	   being unloaded between the file_ops lookup and the open */
-
-	lock_kernel();
-
 	read_lock(&ieee1394_chardevs_lock);
-	file_ops = ieee1394_chardevs[blocknum].file_ops;
 	module = ieee1394_chardevs[blocknum].module;
+	/* bump the reference count of the driver that
+	   will receive the open() */
+	INCREF(module);
+	file_ops = ieee1394_chardevs[blocknum].file_ops;
 	read_unlock(&ieee1394_chardevs_lock);
 
 	if(file_ops == NULL) {
+		DECREF(module);
 		goto out_fail;
 	}
 
@@ -923,10 +923,6 @@
 	   own file_operations */
 	file->f_op = file_ops;
 
-	/* bump the reference count of the driver that
-	   will receive the open() */
-	INCREF(module);
-	
 	/* at this point BOTH ieee1394 and the task-specific driver have
 	   an extra reference */
 
@@ -955,7 +951,6 @@
 		   and will be dropped by the VFS when the file is
 		   released. */
 		
-		unlock_kernel();
 		return 0;
 	}
 	       
@@ -965,7 +960,6 @@
 	   function returns. */
 	
 	file->f_op = &ieee1394_chardev_ops;
-	unlock_kernel();
 	return retval;
 
 #undef INCREF
diff -Nru a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
--- a/drivers/ieee1394/ieee1394_core.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/ieee1394/ieee1394_core.h	Tue Jul 16 16:49:41 2002
@@ -182,6 +182,7 @@
 #define IEEE1394_MINOR_BLOCK_RAW1394       0
 #define IEEE1394_MINOR_BLOCK_VIDEO1394     1
 #define IEEE1394_MINOR_BLOCK_DV1394        2
+#define IEEE1394_MINOR_BLOCK_AMDTP         3
 #define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
 
 /* return the index (within a minor number block) of a file */
diff -Nru a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
--- a/drivers/ieee1394/ieee1394_transactions.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ieee1394/ieee1394_transactions.c	Tue Jul 16 16:49:42 2002
@@ -169,8 +169,9 @@
  */
 int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait)
 {
-	int tlabel;
+	int tlabel = 0;
 	unsigned long flags;
+	int found_tlabel = 0;
 
 	if (wait) {
 		down(&host->tlabel_count);
@@ -180,15 +181,18 @@
 
 	spin_lock_irqsave(&host->tlabel_lock, flags);
 
-	if (host->tlabel_pool[0] != ~0) {
-		tlabel = ffz(host->tlabel_pool[0]);
-		host->tlabel_pool[0] |= 1 << tlabel;
-	} else {
-		tlabel = ffz(host->tlabel_pool[1]);
-		host->tlabel_pool[1] |= 1 << tlabel;
-		tlabel += 32;
+	while (!found_tlabel) {
+		tlabel = host->tlabel_current;
+		if (tlabel < 32 && !(host->tlabel_pool[0] & 1 << tlabel)) {
+			host->tlabel_pool[0] |= 1 << tlabel;
+			found_tlabel = 1;
+		} else if (!(host->tlabel_pool[1] & 1 << (tlabel - 32))) {
+			host->tlabel_pool[1] |= 1 << (tlabel - 32);
+			found_tlabel = 1;
+		}
+		host->tlabel_current = (host->tlabel_current + 1) % 64;
 	}
-
+	
 	spin_unlock_irqrestore(&host->tlabel_lock, flags);
 
 	return tlabel;
diff -Nru a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
--- a/drivers/ieee1394/ieee1394_types.h	Tue Jul 16 16:49:43 2002
+++ b/drivers/ieee1394/ieee1394_types.h	Tue Jul 16 16:49:43 2002
@@ -7,7 +7,6 @@
 #include <linux/version.h>
 #include <linux/list.h>
 #include <linux/init.h>
-#include <linux/string.h>
 #include <asm/byteorder.h>
 
 
diff -Nru a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
--- a/drivers/ieee1394/nodemgr.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ieee1394/nodemgr.c	Tue Jul 16 16:49:43 2002
@@ -177,7 +177,7 @@
 
 	for (i = 0; i < 3; i++) {
 		ret = hpsb_read(host, nodeid, generation, address, quad, 4);
-		if (ret != -EAGAIN)
+		if (!ret)
 			break;
 	}
 	*quad = be32_to_cpu(*quad);
@@ -985,12 +985,26 @@
 	HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT,
 		  NODE_BUS_ARGS(nodeid));
 #endif
+	/* 
+	 * Must retry a few times if config rom read returns zero (how long?). Will
+	 * not normally occur, but we should do the right thing. For example, with
+	 * some sbp2 devices, the bridge chipset cannot return valid config rom reads
+	 * immediately after power-on, since they need to detect the type of 
+	 * device attached (disk or CD-ROM).
+	 */
+	for (i = 0; i < 4; i++) {
+		if (nodemgr_read_quadlet(host, nodeid, generation,
+					 addr, &buffer[0]) < 0) {
+			HPSB_ERR("ConfigROM quadlet transaction error for node "
+				 NODE_BUS_FMT, NODE_BUS_ARGS(nodeid));
+			return -1;
+		}
+		if (buffer[0])
+			break;
 
-	if (nodemgr_read_quadlet(host, nodeid, generation,
-				 addr, &buffer[0]) < 0) {
-		HPSB_ERR("ConfigROM quadlet transaction error for node "
-			 NODE_BUS_FMT, NODE_BUS_ARGS(nodeid));
-		return -1;
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (schedule_timeout (HZ/4))
+			return -1;
 	}
 
 	header_size = buffer[0] >> 24;
@@ -1051,10 +1065,15 @@
 		return;
 
 	if (buffer[1] != IEEE1394_BUSID_MAGIC) {
-		/* This isn't a 1394 device */
-		HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device",
-			 NODE_BUS_ARGS(nodeid));
-		return;
+		/* This isn't a 1394 device, but we let it slide. There
+		 * was a report of a device with broken firmware which
+		 * reported '2394' instead of '1394', which is obviously a
+		 * mistake. One would hope that a non-1394 device never
+		 * gets connected to Firewire bus. If someone does, we
+		 * shouldn't be held responsible, so we'll allow it with a
+		 * warning.  */
+		HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]",
+			 NODE_BUS_ARGS(nodeid), buffer[1]);
 	}
 
 	guid = ((u64)buffer[3] << 32) | buffer[4];
@@ -1103,11 +1122,11 @@
 	nodeid_t nodeid = LOCAL_BUS;
 	unsigned int generation;
 
-	/* Pause for 1 second, to make sure things settle down. If
+	/* Pause for 1/4 second, to make sure things settle down. If
 	 * schedule_timeout returns non-zero, it means we caught a signal
 	 * and need to return. */
 	set_current_state(TASK_INTERRUPTIBLE);
-	if (schedule_timeout (HZ))
+	if (schedule_timeout (HZ/4))
 		return;
 
 	/* Now get the generation in which the node ID's we collect
diff -Nru a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
--- a/drivers/ieee1394/ohci1394.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/ieee1394/ohci1394.c	Tue Jul 16 16:49:43 2002
@@ -37,7 +37,7 @@
  * . DMA error recovery
  *
  * Known bugs:
- * . Apple PowerBook detected but not working yet (still true?)
+ * . devctl BUS_RESET arg confusion (reset type or root holdoff?)
  */
 
 /* 
@@ -77,12 +77,6 @@
  *  . Config ROM generation
  */
 
-/* Issues:
- *
- * - devctl BUS_RESET should treat arg as reset type
- *
- */
-
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -160,17 +154,21 @@
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 static char version[] __devinitdata =
-	"$Revision: 1.101 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 504 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
-MODULE_PARM_DESC(attempt_root, "Attempt to make the host root.");
+MODULE_PARM_DESC(attempt_root, "Attempt to make the host root (default = 0).");
 static int attempt_root = 0;
 
+MODULE_PARM(phys_dma,"i");
+MODULE_PARM_DESC(phys_dma, "Enable physical dma (default = 1).");
+static int phys_dma = 1;
+
 static void dma_trm_tasklet(unsigned long data);
 static void dma_trm_reset(struct dma_trm_ctx *d);
 
-static void __devexit ohci1394_pci_remove(struct pci_dev *pdev);
+static void ohci1394_pci_remove(struct pci_dev *pdev);
 
 static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci,
 					  quadlet_t isoRecvEvent, 
@@ -224,7 +222,7 @@
 
 	spin_lock_irqsave (&ohci->phy_reg_lock, flags);
 
-	reg_write(ohci, OHCI1394_PhyControl, (((u16)addr << 8) & 0x00000f00) | 0x00008000);
+	reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
 
 	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
 		if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
@@ -252,7 +250,7 @@
 
 	spin_lock_irqsave (&ohci->phy_reg_lock, flags);
 
-	reg_write(ohci, OHCI1394_PhyControl, 0x00004000 | (((u16)addr << 8) & 0x00000f00) | data);
+	reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
 
 	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
 		r = reg_read(ohci, OHCI1394_PhyControl);
@@ -291,8 +289,6 @@
 	size_t size;
 	quadlet_t q0, q1;
 
-	mdelay(10);
-
 	/* Check status of self-id reception */
 
 	if (ohci->selfid_swap)
@@ -363,13 +359,6 @@
 			break;
 		mdelay(1);
 	}
-
-	/* Now reenable LPS, since that's usually what we want after a
-	 * softreset anyway. Wait 50msec to make sure we have full link
-	 * enabled.  */
-	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
-	mdelay(50);
-
 	DBGMSG (ohci->id, "Soft reset finished");
 }
 
@@ -488,14 +477,42 @@
 {
 	quadlet_t buf;
 
+	/* Start off with a soft reset, to clear everything to a sane
+	 * state. */
+	ohci_soft_reset(ohci);
+
+	/* Now enable LPS, which we need in order to start accessing
+	 * most of the registers.  In fact, on some cards (ALI M5251),
+	 * accessing registers in the SClk domain without LPS enabled
+	 * will lock up the machine.  Wait 50msec to make sure we have
+	 * full link enabled.  */
+	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
+	mdelay(50);
+
+	/* Determine the number of available IR and IT contexts. */
+	ohci->nb_iso_rcv_ctx =
+		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
+	DBGMSG(ohci->id, "%d iso receive contexts available",
+	       ohci->nb_iso_rcv_ctx);
+
+	ohci->nb_iso_xmit_ctx = 
+		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
+	DBGMSG(ohci->id, "%d iso transmit contexts available",
+	       ohci->nb_iso_xmit_ctx);
+
+	/* Set the usage bits for non-existent contexts so they can't
+	 * be allocated */
+	ohci->ir_ctx_usage |= ~0 << ohci->nb_iso_rcv_ctx;
+	ohci->it_ctx_usage |= ~0 << ohci->nb_iso_xmit_ctx;
+	
 	spin_lock_init(&ohci->phy_reg_lock);
 	spin_lock_init(&ohci->event_lock);
   
 	/* Put some defaults to these undefined bus options */
 	buf = reg_read(ohci, OHCI1394_BusOptions);
-	buf |=  0x60000000; /* Enable CMC and ISC */
+	buf |=  0xE0000000; /* Enable IRMC, CMC and ISC */
 	buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
-	buf &= ~0x98000000; /* Disable PMC, IRMC and BMC */
+	buf &= ~0x18000000; /* Disable PMC and BMC */
 	reg_write(ohci, OHCI1394_BusOptions, buf);
 
 	/* Set the bus number */
@@ -507,8 +524,10 @@
 	/* Clear link control register */
 	reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
   
-	/* Enable cycle timer and cycle master */
+	/* Enable cycle timer and cycle master and set the IRM
+	 * contender bit in our self ID packets. */
 	reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000);
+	set_phy_reg_mask(ohci, 4, 0xc0);
 
 	/* Clear interrupt registers */
 	reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
@@ -610,7 +629,7 @@
 	      ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
 	      ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,
 	      pci_resource_start(ohci->dev, 0),
-	      pci_resource_start(ohci->dev, 0) + pci_resource_len(ohci->dev, 0),
+	      pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE,
 	      ohci->max_packet_size);
 }
 
@@ -1242,15 +1261,6 @@
 				  0xffffffff);
 			reg_write(ohci,OHCI1394_AsReqFilterLoSet, 
 				  0xffffffff);
-			/* Turn on phys dma reception. We should
-			 * probably manage the filtering somehow, 
-			 * instead of blindly turning it on.  */
-			reg_write(ohci,OHCI1394_PhyReqFilterHiSet,
-				  0xffffffff);
-			reg_write(ohci,OHCI1394_PhyReqFilterLoSet,
-				  0xffffffff);
-                       	reg_write(ohci,OHCI1394_PhyUpperBound,
-				  0xffff0000);
 		} else
 			PRINT(KERN_ERR, ohci->id, 
 			      "SelfID received outside of bus reset sequence");
@@ -1262,6 +1272,31 @@
 		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); 
 		spin_unlock_irqrestore(&ohci->event_lock, flags);
 		event &= ~OHCI1394_selfIDComplete;	
+
+		/* Turn on phys dma reception. We should
+		 * probably manage the filtering somehow, 
+		 * instead of blindly turning it on.  */
+
+		/*
+		 * CAUTION!
+		 * Some chips (TI TSB43AB22) won't take a value in
+		 * the PhyReqFilter register until after the IntEvent
+		 * is cleared for bus reset, and even then a short
+		 * delay is required.
+		 */
+		if (phys_dma) {
+			mdelay(1);
+			reg_write(ohci,OHCI1394_PhyReqFilterHiSet,
+				  0xffffffff);
+			reg_write(ohci,OHCI1394_PhyReqFilterLoSet,
+				  0xffffffff);
+			reg_write(ohci,OHCI1394_PhyUpperBound,
+				  0xffff0000);
+		}
+
+		DBGMSG(ohci->id, "PhyReqFilter=%08x%08x\n",
+		       reg_read(ohci,OHCI1394_PhyReqFilterHiSet),
+		       reg_read(ohci,OHCI1394_PhyReqFilterLoSet));
 	}
 
 	/* Make sure we handle everything, just in case we accidentally
@@ -1831,7 +1866,7 @@
 
 	crc = 0;
 	for (; length > 0; length--) {
-		data = *ptr++;
+		data = be32_to_cpu(*ptr++);
 		for (shift = 28; shift >= 0; shift -= 4) {
 			sum = ((crc >> 12) ^ (data >> shift)) & 0x000f;
 			crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;
@@ -2023,7 +2058,7 @@
 
 	struct hpsb_host *host;
 	struct ti_ohci *ohci;	/* shortcut to currently handled device */
-	unsigned long ohci_base, ohci_len;
+	unsigned long ohci_base;
 	int i;
 	
 	if (version_printed++ == 0)
@@ -2041,6 +2076,7 @@
 	ohci->id = card_id_counter++;
 	ohci->dev = dev;
 	ohci->host = host;
+	ohci->init_state = OHCI_INIT_ALLOC_HOST;
 	host->pdev = dev;
 	pci_set_drvdata(dev, ohci);
 
@@ -2056,76 +2092,54 @@
 	 * zero. Should this work? Obviously it's not defined what these
 	 * registers will read when they aren't supported. Bleh! */
 	if (dev->vendor == PCI_VENDOR_ID_APPLE && 
-		dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {
-			ohci->no_swap_incoming = 1;
-			ohci->selfid_swap = 0;
+	    dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {
+		ohci->no_swap_incoming = 1;
+		ohci->selfid_swap = 0;
 	} else
 		ohci->selfid_swap = 1;
 #endif
 
-	/* csr_config rom allocation */
-	ohci->csr_config_rom_cpu = 
-		pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
-				     &ohci->csr_config_rom_bus);
-	OHCI_DMA_ALLOC("consistent csr_config_rom");
-	if (ohci->csr_config_rom_cpu == NULL)
-		FAIL(-ENOMEM, "Failed to allocate buffer config rom");
-
-
+	/* We hardwire the MMIO length, since some CardBus adaptors
+	 * fail to report the right length.  Anyway, the ohci spec
+	 * clearly says it's 2kb, so this shouldn't be a problem. */ 
 	ohci_base = pci_resource_start(dev, 0);
-	ohci_len = pci_resource_len(dev, 0);
-
-	if (!request_mem_region (ohci_base, ohci_len, OHCI1394_DRIVER_NAME))
-		FAIL(-ENOMEM, "MMIO resource (0x%lx@0x%lx) unavailable, aborting.",
-		     ohci_base, ohci_len);
-
-	ohci->registers = ioremap(ohci_base, ohci_len);
+	if (pci_resource_len(dev, 0) != OHCI1394_REGISTER_SIZE)
+		PRINT(KERN_WARNING, ohci->id, "Unexpected PCI resource length of %lx!",
+		      pci_resource_len(dev, 0));
+
+	/* Seems PCMCIA handles this internally. Not sure why. Seems
+	 * pretty bogus to force a driver to special case this.  */
+#ifndef PCMCIA
+	if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME))
+		FAIL(-ENOMEM, "MMIO resource (0x%lx - 0x%lx) unavailable",
+		     ohci_base, ohci_base + OHCI1394_REGISTER_SIZE);
+#endif
+	ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
 
+	ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE);
 	if (ohci->registers == NULL)
 		FAIL(-ENXIO, "Failed to remap registers - card not accessible");
-
+	ohci->init_state = OHCI_INIT_HAVE_IOMAPPING;
 	DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p", ohci->registers);
 
+	/* csr_config rom allocation */
+	ohci->csr_config_rom_cpu =
+		pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
+				     &ohci->csr_config_rom_bus);
+	OHCI_DMA_ALLOC("consistent csr_config_rom");
+	if (ohci->csr_config_rom_cpu == NULL)
+		FAIL(-ENOMEM, "Failed to allocate buffer config rom");
+	ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER;
 
-	/* Start off with a softreset, to clear everything to a sane
-	 * state.  This will also set Link Power State (LPS), which we
-	 * need in order to start accessing most of the registers.  */
-	ohci_soft_reset(ohci);
-
-	/* determinte the number of available IR and IT contexts right away,
-	   because they need to be known for alloc_dma_*_ctx() */
-	ohci->nb_iso_rcv_ctx = 
-		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
-	DBGMSG(ohci->id, "%d iso receive contexts available",
-	       ohci->nb_iso_rcv_ctx);
-
-	ohci->ir_ctx_usage = 0;
-	
-	/* set the usage bits for non-existent contexts so they can't be allocated */
-	for(i = ohci->nb_iso_rcv_ctx; i < sizeof(ohci->ir_ctx_usage)*8; i++)
-		__set_bit(i, &ohci->ir_ctx_usage);
-	
-	ohci->nb_iso_xmit_ctx = 
-		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
-	DBGMSG(ohci->id, "%d iso transmit contexts available",
-	       ohci->nb_iso_xmit_ctx);
-
-	ohci->it_ctx_usage = 0;
-	
-	/* set the usage bits for non-existent contexts so they can't be allocated */
-	for(i = ohci->nb_iso_xmit_ctx; i < sizeof(ohci->it_ctx_usage)*8; i++)
-		__set_bit(i, &ohci->it_ctx_usage);
-
-	
-	/* 
-	 * self-id dma buffer allocation
-	 */
+	/* self-id dma buffer allocation */
 	ohci->selfid_buf_cpu = 
 		pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
                       &ohci->selfid_buf_bus);
 	OHCI_DMA_ALLOC("consistent selfid_buf");
+	
 	if (ohci->selfid_buf_cpu == NULL)
 		FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets");
+	ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER;
 
 	if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff)
 		PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on "
@@ -2135,6 +2149,7 @@
 	/* No self-id errors at startup */
 	ohci->self_id_errors = 0;
 
+	ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE;
 	/* AR DMA request context allocation */
 	ohci->ar_req_context = 
 		alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC,
@@ -2169,6 +2184,9 @@
 	if (ohci->at_resp_context == NULL)
 		FAIL(-ENOMEM, "Failed to allocate AT Resp context");
 
+	ohci->ir_ctx_usage = 0;
+	ohci->it_ctx_usage = 0;
+	
 	/* IR DMA context */
 	ohci->ir_context =
 		alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, 0, IR_NUM_DESC,
@@ -2199,85 +2217,76 @@
 			 OHCI1394_DRIVER_NAME, ohci))
 		FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq);
 
+	ohci->init_state = OHCI_INIT_HAVE_IRQ;
 	ohci_initialize(ohci);
 
 	/* Tell the highlevel this host is ready */
 	hpsb_add_host(host);
+	ohci->init_state = OHCI_INIT_DONE;
 
 	return 0;
 #undef FAIL
 }
 
-static void __devexit ohci1394_pci_remove(struct pci_dev *pdev)
+static void ohci1394_pci_remove(struct pci_dev *pdev)
 {
 	struct ti_ohci *ohci;
-	quadlet_t buf;
 
 	ohci = pci_get_drvdata(pdev);
 	if (!ohci)
 		return;
 
-	if (ohci->host)
+	switch (ohci->init_state) {
+	case OHCI_INIT_DONE:
 		hpsb_remove_host(ohci->host);
 
-	/* Soft reset before we start */
-	ohci_soft_reset(ohci);
-
-	/* Free AR dma */
-	free_dma_rcv_ctx(&ohci->ar_req_context);
-	free_dma_rcv_ctx(&ohci->ar_resp_context);
-
-	/* Free AT dma */
-	free_dma_trm_ctx(&ohci->at_req_context);
-	free_dma_trm_ctx(&ohci->at_resp_context);
-
-	/* Free IR dma */
-	free_dma_rcv_ctx(&ohci->ir_context);
-
-        /* Free IT dma */
-        free_dma_trm_ctx(&ohci->it_context);
-
-	/* Disable all interrupts */
-	reg_write(ohci, OHCI1394_IntMaskClear, 0x80000000);
-	free_irq(ohci->dev->irq, ohci);
+	case OHCI_INIT_HAVE_IRQ:
+		/* Soft reset before we start - this disables
+		 * interrupts and clears linkEnable and LPS. */
+		ohci_soft_reset(ohci);
+		free_irq(ohci->dev->irq, ohci);
+
+	case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE:
+		/* Free AR dma */
+		free_dma_rcv_ctx(&ohci->ar_req_context);
+		free_dma_rcv_ctx(&ohci->ar_resp_context);
+
+		/* Free AT dma */
+		free_dma_trm_ctx(&ohci->at_req_context);
+		free_dma_trm_ctx(&ohci->at_resp_context);
 
-	/* Free self-id buffer */
-	if (ohci->selfid_buf_cpu) {
+		/* Free IR dma */
+		free_dma_rcv_ctx(&ohci->ir_context);
+		
+		/* Free IT dma */
+		free_dma_trm_ctx(&ohci->it_context);
+	
+	case OHCI_INIT_HAVE_SELFID_BUFFER:
 		pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, 
 				    ohci->selfid_buf_cpu,
 				    ohci->selfid_buf_bus);
 		OHCI_DMA_FREE("consistent selfid_buf");
-	}
-	
-	/* Free config rom */
-	if (ohci->csr_config_rom_cpu) {
+		
+	case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER:
 		pci_free_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
-				    ohci->csr_config_rom_cpu, 
+				    ohci->csr_config_rom_cpu,
 				    ohci->csr_config_rom_bus);
 		OHCI_DMA_FREE("consistent csr_config_rom");
-	}
-
-	/* Disable our bus options */
-	buf = reg_read(ohci, OHCI1394_BusOptions);
-	buf &= ~0xf8000000;
-	buf |=  0x00ff0000;
-	reg_write(ohci, OHCI1394_BusOptions, buf);
-
-	/* Clear LinkEnable and LPS */
-	reg_write(ohci, OHCI1394_HCControlClear, 0x000a0000);
 
-	if (ohci->registers)
+	case OHCI_INIT_HAVE_IOMAPPING:
 		iounmap(ohci->registers);
 
-	release_mem_region (pci_resource_start(ohci->dev, 0),
-			    pci_resource_len(ohci->dev, 0));
+	case OHCI_INIT_HAVE_MEM_REGION:
+#ifndef PCMCIA
+		release_mem_region(pci_resource_start(ohci->dev, 0),
+				   OHCI1394_REGISTER_SIZE);
+#endif
 
 #ifdef CONFIG_ALL_PPC
-	/* On UniNorth, power down the cable and turn off the
-	 * chip clock when the module is removed to save power
-	 * on laptops. Turning it back ON is done by the arch
-	 * code when pci_enable_device() is called
-	 */
+	/* On UniNorth, power down the cable and turn off the chip
+	 * clock when the module is removed to save power on
+	 * laptops. Turning it back ON is done by the arch code when
+	 * pci_enable_device() is called */
 	{
 		struct device_node* of_node;
 
@@ -2289,8 +2298,10 @@
 	}
 #endif /* CONFIG_ALL_PPC */
 
-	pci_set_drvdata(ohci->dev, NULL);
-	hpsb_unref_host(ohci->host);
+	case OHCI_INIT_ALLOC_HOST:
+		pci_set_drvdata(ohci->dev, NULL);
+		hpsb_unref_host(ohci->host);
+	}
 }
 
 #define PCI_CLASS_FIREWIRE_OHCI     ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
@@ -2313,7 +2324,7 @@
 	name:		OHCI1394_DRIVER_NAME,
 	id_table:	ohci1394_pci_tbl,
 	probe:		ohci1394_pci_probe,
-	remove:		__devexit_p(ohci1394_pci_remove),
+	remove:		ohci1394_pci_remove,
 };
 
 
diff -Nru a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
--- a/drivers/ieee1394/ohci1394.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/ieee1394/ohci1394.h	Tue Jul 16 16:49:41 2002
@@ -21,6 +21,8 @@
 #ifndef _OHCI1394_H
 #define _OHCI1394_H
 
+#include <asm/io.h>
+
 #include "ieee1394_types.h"
 #include <asm/io.h>
 
@@ -144,7 +146,16 @@
 
         struct pci_dev *dev;
 
-        u32 state;
+	enum { 
+		OHCI_INIT_ALLOC_HOST,
+		OHCI_INIT_HAVE_MEM_REGION,
+		OHCI_INIT_HAVE_IOMAPPING,
+		OHCI_INIT_HAVE_CONFIG_ROM_BUFFER,
+		OHCI_INIT_HAVE_SELFID_BUFFER,
+		OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE,
+		OHCI_INIT_HAVE_IRQ,
+		OHCI_INIT_DONE,
+	} init_state;
         
         /* remapped memory spaces */
         void *registers; 
diff -Nru a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
--- a/drivers/ieee1394/pcilynx.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/ieee1394/pcilynx.c	Tue Jul 16 16:49:42 2002
@@ -2,6 +2,7 @@
  * ti_pcilynx.c - Texas Instruments PCILynx driver
  * Copyright (C) 1999,2000 Andreas Bombe <andreas.bombe@munich.netsurf.de>,
  *                         Stephan Linz <linz@mazet.de>
+ *                         Manfred Weihs <weihs@ict.tuwien.ac.at>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -41,6 +42,8 @@
 #include "highlevel.h"
 #include "pcilynx.h"
 
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
 
 /* print general (card independent) information */
 #define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
@@ -56,9 +59,85 @@
 #endif
 
 
+/* Module Parameters */
+MODULE_PARM(skip_eeprom,"i");
+MODULE_PARM_DESC(skip_eeprom, "Do not try to read bus info block from serial eeprom, but user generic one (default = 0).");
+static int skip_eeprom = 0;
+
+
 static struct hpsb_host_driver *lynx_driver;
 static unsigned int card_id;
 
+
+
+/*
+ * I2C stuff
+ */
+
+/* the i2c stuff was inspired by i2c-philips-par.c */
+
+static void bit_setscl(void *data, int state)
+{
+	if (state) {
+		  ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000040;
+	} else {
+		  ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000040;
+	}
+	reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);
+}
+
+static void bit_setsda(void *data, int state)
+{
+	if (state) {
+		  ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000010;
+	} else {
+		  ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000010;
+	}
+	reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);
+}
+
+static int bit_getscl(void *data)
+{
+	return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000040;
+}
+
+static int bit_getsda(void *data)
+{
+	return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000010;
+}
+
+static int bit_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int bit_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static struct i2c_algo_bit_data bit_data = {
+	NULL,
+	bit_setsda,
+	bit_setscl,
+	bit_getsda,
+	bit_getscl,
+	5, 5, 100,		/*	waits, timeout */
+}; 
+
+static struct i2c_adapter bit_ops = {
+	"PCILynx I2C adapter",
+	0xAA, //FIXME: probably we should get an id in i2c-id.h
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	bit_reg,
+	bit_unreg,
+};
+
+
+
 /*
  * PCL handling functions.
  */
@@ -880,7 +959,7 @@
         retval = copy_to_user(buffer, md->lynx->mem_dma_buffer, count);
         up(&md->lynx->mem_dma_mutex);
 
-        if (retval) return -EFAULT;
+        if (retval < 0) return retval;
         *offset += count;
         return count;
 }
@@ -1232,6 +1311,11 @@
         int i;
         int error;
 
+        /* needed for i2c communication with serial eeprom */
+        struct i2c_adapter i2c_adapter;
+        struct i2c_algo_bit_data i2c_adapter_data;
+
+        int got_valid_bus_info_block = 0; /* set to 1, if we were able to get a valid bus info block from serial eeprom */
 
         error = -ENXIO;
 
@@ -1492,6 +1576,94 @@
                 if (i != -1) set_phy_reg(lynx, 4, i | 0x40);
         }
 
+
+        if (!skip_eeprom)
+        {
+                i2c_adapter = bit_ops;
+                i2c_adapter_data = bit_data;
+                i2c_adapter.algo_data = &i2c_adapter_data;
+                i2c_adapter_data.data = lynx;
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+                PRINT(KERN_DEBUG, lynx->id,"original eeprom control: %d",reg_read(lynx,SERIAL_EEPROM_CONTROL));
+#endif
+
+        	/* reset hardware to sane state */
+        	lynx->i2c_driven_state = 0x00000070;
+        	reg_write(lynx, SERIAL_EEPROM_CONTROL, lynx->i2c_driven_state);
+
+        	if (i2c_bit_add_bus(&i2c_adapter) < 0)
+        	{
+	        	PRINT(KERN_ERR, lynx->id,  "unable to register i2c");
+        	}
+        	else
+        	{
+                        /* do i2c stuff */
+                        unsigned char i2c_cmd = 0x10;
+                        struct i2c_msg msg[2] = { { 0x50, 0, 1, &i2c_cmd }, 
+                                                  { 0x50, I2C_M_RD, 20, (unsigned char*) lynx->config_rom }
+                                                };
+
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+                        union i2c_smbus_data data;
+
+                        if (i2c_smbus_xfer(&i2c_adapter, 80, 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE,NULL))
+                                PRINT(KERN_ERR, lynx->id,"eeprom read start has failed");
+                        else
+                        {
+                                u16 addr;
+                                for (addr=0x00; addr < 0x100; addr++) {
+                                        if (i2c_smbus_xfer(&i2c_adapter, 80, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE,& data)) {
+                                                PRINT(KERN_ERR, lynx->id, "unable to read i2c %x", addr);
+                                                break;
+                                        }
+                                        else
+                                                PRINT(KERN_DEBUG, lynx->id,"got serial eeprom data at %x: %x",addr, data.byte);
+                                }
+                        }
+#endif
+
+                        /* we use i2c_transfer, because i2c_smbus_read_block_data does not work properly and we
+                           do it more efficiently in one transaction rather then using several reads */
+                        if (i2c_transfer(&i2c_adapter, msg, 2) < 0) {
+                                PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c");
+                        } else {
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+                                int i;
+#endif
+                                PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom");
+                                /* FIXME: probably we shoud rewrite the max_rec, max_ROM(1394a), generation(1394a) and link_spd(1394a) field
+                                   and recalculate the CRC */
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+                                for (i=0; i < 5 ; i++)
+                                        PRINT(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x",i, be32_to_cpu(lynx->config_rom[i]));
+#endif
+
+                                /* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */
+                                if (((be32_to_cpu(lynx->config_rom[0]) & 0xffff0000) == 0x04040000) &&
+                                    (lynx->config_rom[1] == __constant_cpu_to_be32(0x31333934)))
+                                {
+                                        PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from");
+                                        got_valid_bus_info_block = 1;
+                                } else {
+                                        PRINT(KERN_WARNING, lynx->id, "read something from serial eeprom, but it does not seem to be a valid bus info block");
+                                }
+
+                        }
+
+                        i2c_bit_del_bus(&i2c_adapter);
+                }
+        }
+
+        if (got_valid_bus_info_block) {
+                memcpy(lynx->config_rom+5,lynx_csr_rom+5,sizeof(lynx_csr_rom)-20);
+        } else {
+                PRINT(KERN_INFO, lynx->id, "since we did not get a bus info block from serial eeprom, we use a generic one with a hard coded GUID");
+                memcpy(lynx->config_rom,lynx_csr_rom,sizeof(lynx_csr_rom));
+        }
+
         hpsb_add_host(host);
         lynx->state = is_host;
 
@@ -1503,7 +1675,8 @@
 
 static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
 {
-        *ptr = lynx_csr_rom;
+        struct ti_lynx *lynx = host->hostdata;
+        *ptr = lynx->config_rom;
         return sizeof(lynx_csr_rom);
 }
 
diff -Nru a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
--- a/drivers/ieee1394/pcilynx.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/ieee1394/pcilynx.h	Tue Jul 16 16:49:41 2002
@@ -25,6 +25,8 @@
 #define CHANNEL_ASYNC_SEND       3
 #define CHANNEL_ISO_SEND         4
 
+#define PCILYNX_CONFIG_ROM_LENGTH   1024
+
 typedef int pcl_t;
 
 struct ti_lynx {
@@ -48,7 +50,7 @@
         void *local_rom;
         void *local_ram;
         void *aux_port;
-
+        quadlet_t config_rom[PCILYNX_CONFIG_ROM_LENGTH/4];
 
 #ifdef CONFIG_IEEE1394_PCILYNX_PORTS
         atomic_t aux_intr_seen;
@@ -109,6 +111,8 @@
                 struct tasklet_struct tq;
                 spinlock_t lock;
         } iso_rcv;
+
+	u32 i2c_driven_state; /* the state we currently drive the Serial EEPROM Control register */
 };
 
 /* the per-file data structure for mem space access */
@@ -155,6 +159,8 @@
 
 #define MISC_CONTROL                      0x40
 #define MISC_CONTROL_SWRESET              (1<<0)
+
+#define SERIAL_EEPROM_CONTROL             0x44
 
 #define PCI_INT_STATUS                    0x48
 #define PCI_INT_ENABLE                    0x4c               
diff -Nru a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
--- a/drivers/ieee1394/raw1394.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ieee1394/raw1394.c	Tue Jul 16 16:49:41 2002
@@ -189,6 +189,8 @@
         }
 
         kfree(hi);
+
+        atomic_inc(&internal_generation);
 }
 
 static void host_reset(struct hpsb_host *host)
@@ -223,8 +225,6 @@
                 }
         }
         spin_unlock_irqrestore(&host_info_lock, flags);
-
-        atomic_inc(&internal_generation);
 }
 
 static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
diff -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
--- a/drivers/ieee1394/sbp2.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ieee1394/sbp2.c	Tue Jul 16 16:49:41 2002
@@ -86,6 +86,9 @@
  * sbp2_max_sectors, 		- Change max sectors per I/O supported (default = 255)
  * sbp2_max_outstanding_cmds	- Change max outstanding concurrent commands (default = 8)
  * sbp2_max_cmds_per_lun	- Change max concurrent commands per sbp2 device (default = 1)
+ * sbp2_exclusive_login		- Set to zero if you'd like to allow multiple hosts the ability
+ *				  to log in at the same time. Sbp2 device must support this,
+ *				  and you must know what you're doing (default = 1)
  *
  * (e.g. insmod sbp2 sbp2_serialize_io = 1)
  *
@@ -135,11 +138,14 @@
  *	- Error Handling: SCSI aborts and bus reset requests are handled somewhat
  *	  but the code needs additional debugging.
  *
- *	- The SBP-2 driver is currently only supported as a module. It would not take
+ *	- Module: The SBP-2 driver is currently only supported as a module. It would not take
  *	  much work to allow it to be compiled into the kernel, but you'd have to 
  *	  add some init code to the kernel to support this... and modules are much
  *	  more flexible anyway.   ;-)
  *
+ *	- Hot-plugging: Interaction with the SCSI stack and support for hot-plugging could
+ *	  stand some improvement.
+ *
  *
  * History:
  *
@@ -265,7 +271,7 @@
  *		     which do not support requests of 128KB or greater. Now use 
  *		     max_sectors scsi host entry to limit transfer sizes.
  *		   * Change status fifo address from a single address to a set of addresses,
- *		     with each sbp2 device having it's own status fifo address. This makes
+ *		     with each sbp2 device having its own status fifo address. This makes
  *		     it easier to match the status write to the sbp2 device instance.
  *		   * Minor change to use lun when logging into sbp2 devices. First step in
  *		     supporting multi-lun devices such as CD/DVD changer devices.
@@ -278,7 +284,20 @@
  *	02/20/02 - Added a couple additional module load options. 
  *		   Needed to bump down max commands per lun because of the !%@&*^# QPS CDRW 
  *		   drive I have, which doesn't seem to get along with other sbp2 devices 
- *		   (or handle linked commands well).  
+ *		   (or handle linked commands well).
+ *	04/21/02 - Added some additional debug capabilities:
+ *		   * Able to handle phys dma requests directly, if host controller has phys
+ *		     dma disabled (e.g. insmod ohci1394 phys_dma=0). Undefine CONFIG_IEEE1394_SBP2_PHYS_DMA
+ *		     if you'd like to disable sbp2 driver from registering for phys address range. 
+ *		   * New packet dump debug define (CONFIG_IEEE1394_SBP2_PACKET_DUMP) which allows
+ *		     dumping of all sbp2 related packets sent and received. Especially effective
+ *		     when phys dma is disabled on ohci controller (e.g. insmod ohci1394 phys_dma=0).
+ *		   * Added new sbp2 module load option (sbp2_exclusive_login) for allowing
+ *		     non-exclusive login to sbp2 device, for special multi-host applications.
+ *	04/23/02 - Fix for Sony CD-ROM drives. Only send fetch agent reset to sbp2 device if it
+ *		   returns the dead bit in status. Thanks to Chandan (chandan@toad.net) for this one.
+ *	04/27/02 - Fix sbp2 login problem on SMP systems, enable real spinlocks by default. (JSG)
+ *	06/09/02 - Don't force 36-bute SCSI inquiry, but leave in a define for badly behaved devices. (JSG)   
  */
 
 
@@ -305,6 +324,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
+#include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/scatterlist.h>
@@ -329,6 +349,9 @@
 #include "ieee1394_hotplug.h"
 #include "sbp2.h"
 
+static char version[] __devinitdata =
+	"$Rev: 507 $ James Goodwin <jamesg@filanet.com>";
+
 /*
  * Module load parameter definitions
  */
@@ -387,6 +410,18 @@
 MODULE_PARM_DESC(sbp2_max_cmds_per_lun, "Change max concurrent commands per sbp2 device (default = 1)");
 static int sbp2_max_cmds_per_lun = SBP2SCSI_MAX_CMDS_PER_LUN;
 
+/*
+ * Exclusive login to sbp2 device? In most cases, the sbp2 driver should do an exclusive login, as it's
+ * generally unsafe to have two hosts talking to a single sbp2 device at the same time (filesystem
+ * coherency, etc.). If you're running an sbp2 device that supports multiple logins, and you're either
+ * running read-only filesystems or some sort of special filesystem supporting multiple hosts, then
+ * set sbp2_exclusive_login to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
+ * concurrent logins.
+ */
+MODULE_PARM(sbp2_exclusive_login,"i");
+MODULE_PARM_DESC(sbp2_exclusive_login, "Exclusive login to sbp2 device (default = 1)");
+static int sbp2_exclusive_login = 1;
+
 
 /*
  * Export information about protocols/devices supported by this driver.
@@ -411,6 +446,7 @@
 /* #define CONFIG_IEEE1394_SBP2_DEBUG_DMA */
 /* #define CONFIG_IEEE1394_SBP2_DEBUG 1 */
 /* #define CONFIG_IEEE1394_SBP2_DEBUG 2 */
+/* #define CONFIG_IEEE1394_SBP2_PACKET_DUMP */
 
 #ifdef CONFIG_IEEE1394_SBP2_DEBUG_ORBS
 #define SBP2_ORB_DEBUG(fmt, args...)	HPSB_ERR("sbp2(%s): "fmt, __FUNCTION__, ## args)
@@ -456,10 +492,10 @@
 #define SBP2_ERR(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
 
 /*
- * Spinlock debugging stuff. I'm playing it safe until the driver has been
- * debugged on SMP. (JSG)
+ * Spinlock debugging stuff.
  */
-/* #define SBP2_USE_REAL_SPINLOCKS */
+#define SBP2_USE_REAL_SPINLOCKS
+
 #ifdef SBP2_USE_REAL_SPINLOCKS
 #define sbp2_spin_lock(lock, flags)	spin_lock_irqsave(lock, flags)	
 #define sbp2_spin_unlock(lock, flags)	spin_unlock_irqrestore(lock, flags);
@@ -470,6 +506,14 @@
 #endif
 
 /*
+ * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on if your sbp2 device
+ * is not properly handling the SCSI inquiry command. This hack makes the inquiry look more 
+ * like a typical MS Windows inquiry.
+ */
+
+/* #define SBP2_FORCE_36_BYTE_INQUIRY */
+
+/*
  * Globals
  */
 
@@ -490,6 +534,13 @@
 	write: sbp2_handle_status_write
 };
 
+#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
+static struct hpsb_address_ops sbp2_physdma_ops = {
+        read: sbp2_handle_physdma_read,
+        write: sbp2_handle_physdma_write,
+};
+#endif
+
 static struct hpsb_protocol_driver sbp2_driver = {
 	name:		"SBP2 Driver",
 	id_table: 	sbp2_id_table,
@@ -498,7 +549,6 @@
 	update: 	sbp2_update
 };
 
-
 
 /**************************************
  * General utility functions
@@ -537,6 +587,56 @@
 #define sbp2util_cpu_to_be32_buffer(x,y)
 #endif
 
+#ifdef CONFIG_IEEE1394_SBP2_PACKET_DUMP
+/*
+ * Debug packet dump routine. Length is in bytes.
+ */
+static void sbp2util_packet_dump(void *buffer, int length, char *dump_name, u32 dump_phys_addr)
+{
+	int i;
+	unsigned char *dump = buffer;
+
+	if (!dump || !length || !dump_name)
+		return;
+
+	if (dump_phys_addr)
+		printk("[%s, 0x%x]", dump_name, dump_phys_addr);
+	else
+		printk("[%s]", dump_name);
+	for (i = 0; i < length; i++) {
+		if (i > 0x3f) {
+			printk("\n   ...");
+			break;
+		}
+		if ((i & 0x3) == 0)
+			printk("  ");
+		if ((i & 0xf) == 0)
+			printk("\n   ");
+		printk("%02x ", (int) dump[i]);
+	}
+	printk("\n");
+
+	return;
+}
+#else
+#define sbp2util_packet_dump(w,x,y,z)
+#endif
+
+/*
+ * Goofy routine that basically does a down_timeout function.
+ */
+static int sbp2util_down_timeout(atomic_t *done, int timeout)
+{
+	int i;
+
+	for (i = timeout; (i > 0 && atomic_read(done) == 0); i-= HZ/10) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (schedule_timeout(HZ/10))	/* 100ms */
+			return(1);
+	}
+	return ((i > 0) ? 0:1);
+}
+
 /*
  * This function is called to initially create a packet pool for use in
  * sbp2 I/O requests. This packet pool is used when sending out sbp2
@@ -665,7 +765,7 @@
 		
 		hpsb_node_fill_packet(ne, packet);
 
-		packet->tlabel = get_tlabel(hi->host, packet->node_id, 1);
+		packet->tlabel = get_tlabel(hi->host, packet->node_id, 0);
 
 		if (!data_size) {
 			fill_async_writequad(packet, addr, data);
@@ -950,6 +1050,13 @@
 				SBP2_STATUS_FIFO_ADDRESS + 
 				SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2SCSI_MAX_SCSI_IDS+1));
 
+	/*
+	 * Handle data movement if physical dma is not enabled/supported on host controller
+	 */
+#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
+	hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL);
+#endif
+
 	hpsb_register_protocol(&sbp2_driver);
 
 	return 0;
@@ -1241,7 +1348,7 @@
 	scsi_id->max_payload_size = sbp2_speedto_maxrec[SPEED_100];
 	ud->driver_data = scsi_id;
 
-	init_waitqueue_head(&scsi_id->sbp2_login_wait);
+	atomic_set(&scsi_id->sbp2_login_complete, 0);
 
 	/* 
 	 * Initialize structures needed for the command orb pool.
@@ -1379,20 +1486,62 @@
 	kfree(scsi_id);
 }
 
-
+#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
+/*
+ * This function deals with physical dma write requests (for adapters that do not support
+ * physical dma in hardware). Mostly just here for debugging...
+ */
+static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data,
+                                     u64 addr, unsigned int length)
+{
+
+        /*
+         * Manually put the data in the right place.
+         */
+        memcpy(bus_to_virt((u32)addr), data, length);
+	sbp2util_packet_dump(data, length, "sbp2 phys dma write by device", (u32)addr);
+        return(RCODE_COMPLETE);
+}
+
+/*
+ * This function deals with physical dma read requests (for adapters that do not support
+ * physical dma in hardware). Mostly just here for debugging...
+ */
+static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
+                                    u64 addr, unsigned int length)
+{
+
+        /*
+         * Grab data from memory and send a read response.
+         */
+        memcpy(data, bus_to_virt((u32)addr), length);
+	sbp2util_packet_dump(data, length, "sbp2 phys dma read by device", (u32)addr);
+        return(RCODE_COMPLETE);
+}
+#endif
+
 
 /**************************************
  * SBP-2 protocol related section
  **************************************/
 
 /*
+ * This function determines if we should convert scsi commands for a particular sbp2 device type
+ */
+static __inline__ int sbp2_command_conversion_device_type(u8 device_type)
+{
+	return (((device_type == TYPE_DISK) ||
+		 (device_type == TYPE_SDAD) ||
+		 (device_type == TYPE_ROM)) ? 1:0);
+}
+
+/*
  * This function is called in order to login to a particular SBP-2 device,
  * after a bus reset.
  */
 static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) 
 {
 	quadlet_t data[2];
-	unsigned long flags;
 
 	SBP2_DEBUG("sbp2_login_device");
 
@@ -1412,7 +1561,7 @@
 
 	scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST);
 	scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0);	/* One second reconnect time */
-	scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(1);	/* Exclusive access to device */
+	scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(sbp2_exclusive_login);	/* Exclusive access to device */
 	scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1);	/* Notify us of login complete */
 	/* Set the lun if we were able to pull it from the device's unit directory */
 	if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
@@ -1437,6 +1586,9 @@
 
 	SBP2_DEBUG("sbp2_login_device: orb byte-swapped");
 
+	sbp2util_packet_dump(scsi_id->login_orb, sizeof(struct sbp2_login_orb), 
+			     "sbp2 login orb", scsi_id->login_orb_dma);
+
 	/*
 	 * Initialize login response and status fifo
 	 */
@@ -1452,35 +1604,28 @@
 	data[1] = scsi_id->login_orb_dma;
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
+	atomic_set(&scsi_id->sbp2_login_complete, 0);
+
 	SBP2_DEBUG("sbp2_login_device: prepared to write");
 	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
 	SBP2_DEBUG("sbp2_login_device: written");
 
 	/*
-	 * Wait for login status... but, only if the device has not
-	 * already logged-in (some devices are fast)
+	 * Wait for login status (up to 20 seconds)... 
 	 */
-
-	save_flags(flags);
-	cli();
-	/* 20 second timeout */
-	if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma)
-		sleep_on_timeout(&scsi_id->sbp2_login_wait, 20*HZ);
-	restore_flags(flags);
-
-	SBP2_DEBUG("sbp2_login_device: initial check");
+	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 20*HZ)) {
+		SBP2_ERR("Error logging into SBP-2 device - login timed-out");
+		return(-EIO);
+	}
 
 	/*
-	 * Match status to the login orb. If they do not match, it's
-	 * probably because the login timed-out.
+	 * Sanity. Make sure status returned matches login orb.
 	 */
 	if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) {
 		SBP2_ERR("Error logging into SBP-2 device - login timed-out");
 		return(-EIO);
 	}
 
-	SBP2_DEBUG("sbp2_login_device: second check");
-
 	/*
 	 * Check status
 	 */
@@ -1552,6 +1697,9 @@
 	 */
 	sbp2util_cpu_to_be32_buffer(scsi_id->logout_orb, sizeof(struct sbp2_logout_orb));
 
+	sbp2util_packet_dump(scsi_id->logout_orb, sizeof(struct sbp2_logout_orb), 
+			     "sbp2 logout orb", scsi_id->logout_orb_dma);
+
 	/*
 	 * Ok, let's write to the target's management agent register
 	 */
@@ -1559,10 +1707,12 @@
 	data[1] = scsi_id->logout_orb_dma;
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
+	atomic_set(&scsi_id->sbp2_login_complete, 0);
+
 	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
 
 	/* Wait for device to logout...1 second. */
-	sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ);
+	sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ);
 
 	SBP2_INFO("Logged out of SBP-2 device");
 
@@ -1577,7 +1727,6 @@
 static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) 
 {
 	quadlet_t data[2];
-	unsigned long flags;
 
 	SBP2_DEBUG("sbp2_reconnect_device");
 
@@ -1607,6 +1756,9 @@
 	 */
 	sbp2util_cpu_to_be32_buffer(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb));
 
+	sbp2util_packet_dump(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb), 
+			     "sbp2 reconnect orb", scsi_id->reconnect_orb_dma);
+
 	/*
 	 * Initialize status fifo
 	 */
@@ -1619,22 +1771,20 @@
 	data[1] = scsi_id->reconnect_orb_dma;
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
+	atomic_set(&scsi_id->sbp2_login_complete, 0);
+
 	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
 
 	/*
-	 * Wait for reconnect status... but, only if the device has not
-	 * already reconnected (some devices are fast).
+	 * Wait for reconnect status (up to 1 second)...
 	 */
-	save_flags(flags);
-	cli();
-	/* One second timout */
-	if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma)
-		sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ);
-	restore_flags(flags);
+	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ)) {
+		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");
+		return(-EIO);
+	}
 
 	/*
-	 * Match status to the reconnect orb. If they do not match, it's
-	 * probably because the reconnect timed-out.
+	 * Sanity. Make sure status returned matches reconnect orb.
 	 */
 	if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) {
 		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");
@@ -2002,6 +2152,10 @@
 			/* Number of page table (s/g) elements */
 			command_orb->misc |= ORB_SET_DATA_SIZE(sg_count);
 
+			sbp2util_packet_dump(scatter_gather_element, 
+					     (sizeof(struct sbp2_unrestricted_page_table)) * sg_count, 
+					     "sbp2 s/g list", command->sge_dma);
+
 			/*
 			 * Byte swap page tables if necessary
 			 */
@@ -2081,6 +2235,10 @@
 			/* Number of page table (s/g) elements */
 			command_orb->misc |= ORB_SET_DATA_SIZE(sg_count);
 
+			sbp2util_packet_dump(scatter_gather_element, 
+					     (sizeof(struct sbp2_unrestricted_page_table)) * sg_count, 
+					     "sbp2 s/g list", command->sge_dma);
+
 			/*
 			 * Byte swap page tables if necessary
 			 */
@@ -2219,13 +2377,11 @@
 {
 	unchar *cmd = (unchar *) SCpnt->cmnd;
 	unsigned int request_bufflen = SCpnt->request_bufflen;
-	u8 device_type
-		= SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
 	struct sbp2_command_info *command;
 
 	SBP2_DEBUG("sbp2_send_command");
-	SBP2_DEBUG("SCSI command:");
-#if CONFIG_IEEE1394_SBP2_DEBUG >= 2
+#if (CONFIG_IEEE1394_SBP2_DEBUG >= 2) || defined(CONFIG_IEEE1394_SBP2_PACKET_DUMP)
+	printk("[scsi command]\n   ");
 	print_command (cmd);
 #endif
 	SBP2_DEBUG("SCSI transfer size = %x", request_bufflen);
@@ -2242,11 +2398,14 @@
 	/*
 	 * The scsi stack sends down a request_bufflen which does not match the
 	 * length field in the scsi cdb. This causes some sbp2 devices to 
-	 * reject this inquiry command. Hack fix is to set both buff length and
-	 * length field in cdb to 36. This gives best compatibility.
+	 * reject this inquiry command. Fix the request_bufflen. 
 	 */
 	if (*cmd == INQUIRY) {
+#ifdef SBP2_FORCE_36_BYTE_INQUIRY
 		request_bufflen = cmd[4] = 0x24;
+#else
+		request_bufflen = cmd[4];
+#endif
 	}
 
 	/*
@@ -2259,11 +2418,10 @@
 	 * Update our cdb if necessary (to handle sbp2 RBC command set
 	 * differences). This is where the command set hacks go!   =)
 	 */
-	if ((device_type == TYPE_DISK) ||
-	    (device_type == TYPE_SDAD) ||
-	    (device_type == TYPE_ROM)) {
-		sbp2_check_sbp2_command(command->command_orb.cdb);
-	}
+	sbp2_check_sbp2_command(scsi_id, command->command_orb.cdb);
+
+	sbp2util_packet_dump(&command->command_orb, sizeof(struct sbp2_command_orb), 
+			     "sbp2 command orb", command->command_orb_dma);
 
 	/*
 	 * Initialize status fifo
@@ -2283,9 +2441,10 @@
  * This function deals with command set differences between Linux scsi
  * command set and sbp2 RBC command set.
  */
-static void sbp2_check_sbp2_command(unchar *cmd)
+static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd)
 {
 	unchar new_cmd[16];
+	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
 
 	SBP2_DEBUG("sbp2_check_sbp2_command");
 
@@ -2293,67 +2452,79 @@
 		
 		case READ_6:
 
-			SBP2_DEBUG("Convert READ_6 to READ_10");
+			if (sbp2_command_conversion_device_type(device_type)) {
 
-			/*
-			 * Need to turn read_6 into read_10
-			 */
-			new_cmd[0] = 0x28;
-			new_cmd[1] = (cmd[1] & 0xe0);
-			new_cmd[2] = 0x0;
-			new_cmd[3] = (cmd[1] & 0x1f);
-			new_cmd[4] = cmd[2];
-			new_cmd[5] = cmd[3];
-			new_cmd[6] = 0x0;
-			new_cmd[7] = 0x0;
-			new_cmd[8] = cmd[4];
-			new_cmd[9] = cmd[5];
+				SBP2_DEBUG("Convert READ_6 to READ_10");
+					    
+				/*
+				 * Need to turn read_6 into read_10
+				 */
+				new_cmd[0] = 0x28;
+				new_cmd[1] = (cmd[1] & 0xe0);
+				new_cmd[2] = 0x0;
+				new_cmd[3] = (cmd[1] & 0x1f);
+				new_cmd[4] = cmd[2];
+				new_cmd[5] = cmd[3];
+				new_cmd[6] = 0x0;
+				new_cmd[7] = 0x0;
+				new_cmd[8] = cmd[4];
+				new_cmd[9] = cmd[5];
+	
+				memcpy(cmd, new_cmd, 10);
 
-			memcpy(cmd, new_cmd, 10);
+			}
 
 			break;
 
 		case WRITE_6:
 
-			SBP2_DEBUG("Convert WRITE_6 to WRITE_10");
+			if (sbp2_command_conversion_device_type(device_type)) {
 
-			/*
-			 * Need to turn write_6 into write_10
-			 */
-			new_cmd[0] = 0x2a;
-			new_cmd[1] = (cmd[1] & 0xe0);
-			new_cmd[2] = 0x0;
-			new_cmd[3] = (cmd[1] & 0x1f);
-			new_cmd[4] = cmd[2];
-			new_cmd[5] = cmd[3];
-			new_cmd[6] = 0x0;
-			new_cmd[7] = 0x0;
-			new_cmd[8] = cmd[4];
-			new_cmd[9] = cmd[5];
+				SBP2_DEBUG("Convert WRITE_6 to WRITE_10");
+	
+				/*
+				 * Need to turn write_6 into write_10
+				 */
+				new_cmd[0] = 0x2a;
+				new_cmd[1] = (cmd[1] & 0xe0);
+				new_cmd[2] = 0x0;
+				new_cmd[3] = (cmd[1] & 0x1f);
+				new_cmd[4] = cmd[2];
+				new_cmd[5] = cmd[3];
+				new_cmd[6] = 0x0;
+				new_cmd[7] = 0x0;
+				new_cmd[8] = cmd[4];
+				new_cmd[9] = cmd[5];
+	
+				memcpy(cmd, new_cmd, 10);
 
-			memcpy(cmd, new_cmd, 10);
+			}
 
 			break;
 
 		case MODE_SENSE:
 
-			SBP2_DEBUG("Convert MODE_SENSE_6 to MOSE_SENSE_10");
+			if (sbp2_command_conversion_device_type(device_type)) {
 
-			/*
-			 * Need to turn mode_sense_6 into mode_sense_10
-			 */
-			new_cmd[0] = 0x5a;
-			new_cmd[1] = cmd[1];
-			new_cmd[2] = cmd[2];
-			new_cmd[3] = 0x0;
-			new_cmd[4] = 0x0;
-			new_cmd[5] = 0x0;
-			new_cmd[6] = 0x0;
-			new_cmd[7] = 0x0;
-			new_cmd[8] = cmd[4];
-			new_cmd[9] = cmd[5];
+				SBP2_DEBUG("Convert MODE_SENSE_6 to MODE_SENSE_10");
 
-			memcpy(cmd, new_cmd, 10);
+				/*
+				 * Need to turn mode_sense_6 into mode_sense_10
+				 */
+				new_cmd[0] = 0x5a;
+				new_cmd[1] = cmd[1];
+				new_cmd[2] = cmd[2];
+				new_cmd[3] = 0x0;
+				new_cmd[4] = 0x0;
+				new_cmd[5] = 0x0;
+				new_cmd[6] = 0x0;
+				new_cmd[7] = 0x0;
+				new_cmd[8] = cmd[4];
+				new_cmd[9] = cmd[5];
+	
+				memcpy(cmd, new_cmd, 10);
+
+			}
 
 			break;
 
@@ -2404,8 +2575,7 @@
  * This function is called after a command is completed, in order to do any necessary SBP-2
  * response data translations for the SCSI stack
  */
-static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi,
-				     struct scsi_id_instance_data *scsi_id, 
+static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, 
 				     Scsi_Cmnd *SCpnt)
 {
 	u8 *scsi_buf = SCpnt->request_buffer;
@@ -2451,18 +2621,16 @@
 
 		case MODE_SENSE:
 
-			if ((device_type == TYPE_DISK) ||
-			    (device_type == TYPE_SDAD) ||
-			    (device_type == TYPE_ROM)) {
-
+			if (sbp2_command_conversion_device_type(device_type)) {
+			
 				SBP2_DEBUG("Modify mode sense response (10 byte version)");
-	
+
 				scsi_buf[0] = scsi_buf[1];	/* Mode data length */
 				scsi_buf[1] = scsi_buf[2];	/* Medium type */
 				scsi_buf[2] = scsi_buf[3];	/* Device specific parameter */
 				scsi_buf[3] = scsi_buf[7];	/* Block descriptor length */
 				memcpy(scsi_buf + 4, scsi_buf + 8, scsi_buf[0]);
-
+	
 			}
 
 			break;
@@ -2495,6 +2663,8 @@
 
 	SBP2_DEBUG("sbp2_handle_status_write");
 
+	sbp2util_packet_dump(data, length, "sbp2 status write by device", (u32)addr);
+
 	if (!host) {
 		SBP2_ERR("host is NULL - this is bad!");
 		return(RCODE_ADDRESS_ERROR);
@@ -2566,21 +2736,21 @@
 				/*
 				 * Translate SBP-2 status to SCSI sense data
 				 */
+				SBP2_DEBUG("CHECK CONDITION");
 				scsi_status = sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer);
 			}
 
 			/*
-			 * Handle check conditions. If there is either SBP status or SCSI status
-			 * then we'll do a fetch agent reset and note that a check condition
-			 * occured.
+			 * Check to see if the dead bit is set. If so, we'll have to initiate
+			 * a fetch agent reset.
 			 */
-			if (STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc) ||
-			    scsi_status) {
+			if (STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc)) {
+
 				/*
 				 * Initiate a fetch agent reset. 
 				 */
-				SBP2_DEBUG("CHECK CONDITION");
-				sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT);
+				SBP2_DEBUG("Dead bit set - initiating fetch agent reset");
+                                sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT);
 			}
 
 			SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb);
@@ -2602,10 +2772,19 @@
 			scsi_id->last_orb = NULL;
 		}
 
+	} else {
+		
+		/* 
+		 * It's probably a login/logout/reconnect status.
+		 */
+		if ((scsi_id->login_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
+		    (scsi_id->reconnect_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
+		    (scsi_id->logout_orb_dma == scsi_id->status_block.ORB_offset_lo)) {
+			atomic_set(&scsi_id->sbp2_login_complete, 1);
+		}
 	}
 
 	sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
-	wake_up(&scsi_id->sbp2_login_wait);
 	return(RCODE_COMPLETE);
 }
 
@@ -2805,7 +2984,7 @@
 	 * Take care of any sbp2 response data mucking here (RBC stuff, etc.)
 	 */
 	if (SCpnt->result == DID_OK) {
-		sbp2_check_sbp2_response(hi, scsi_id, SCpnt);
+		sbp2_check_sbp2_response(scsi_id, SCpnt);
 	}
 
 	/*
@@ -2822,10 +3001,13 @@
 	 * retried... it could have happened because of a 1394 bus reset
 	 * or hot-plug...
 	 */
-	if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) {
+#if 0
+	if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && 
+	    (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) {
 		SBP2_DEBUG("UNIT ATTENTION - return busy");
 		SCpnt->result = DID_BUS_BUSY << 16;
 	}
+#endif
 
 	/*
 	 * Tell scsi stack that we're done with this command
@@ -2835,9 +3017,9 @@
 	done (SCpnt);
 	spin_unlock_irq(&io_request_lock);
 #else
-	spin_lock_irq(&hi->scsi_host->host_lock);
+	spin_lock_irq(hi->scsi_host->host_lock);
 	done (SCpnt);
-	spin_unlock_irq(&hi->scsi_host->host_lock);
+	spin_unlock_irq(hi->scsi_host->host_lock);
 #endif
 
 	return;
@@ -2905,7 +3087,7 @@
 	SBP2_ERR("reset requested");
 
 	if (scsi_id) {
-		SBP2_ERR("Generating IEEE-1394 bus reset");
+		SBP2_ERR("Generating sbp2 fetch agent reset");
 		sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT);
 	}
 
@@ -2969,19 +3151,22 @@
 	if (!hi) /* shouldn't happen, but... */
         	return "IEEE-1394 SBP-2 protocol driver";
 
-	sprintf(info, "IEEE-1394 SBP-2 protocol driver (host: %s)\n"
+	sprintf(info, "IEEE-1394 SBP-2 protocol driver (host: %s)\n%s\n"
 		"SBP-2 module load options:\n"
 		"- Max speed supported: %s\n"
 		"- Max sectors per I/O supported: %d\n"
 		"- Max outstanding commands supported: %d\n"
 		"- Max outstanding commands per lun supported: %d\n"
-                "- Serialized I/O (debug): %s",
-		hi->host->driver->name, 
+                "- Serialized I/O (debug): %s\n"
+		"- Exclusive login: %s",
+		hi->host->driver->name,
+		version,
 		hpsb_speedto_str[sbp2_max_speed],
 		sbp2_max_sectors,
 		sbp2_max_outstanding_cmds,
 		sbp2_max_cmds_per_lun,
-		sbp2_serialize_io ? "yes" : "no");
+		sbp2_serialize_io ? "yes" : "no",
+		sbp2_exclusive_login ? "yes" : "no");
 
 	return info;
 }
diff -Nru a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
--- a/drivers/ieee1394/sbp2.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/ieee1394/sbp2.h	Tue Jul 16 16:49:41 2002
@@ -398,9 +398,9 @@
 	u32 sbp2_firmware_revision;
 
 	/* 
-	 * Wait queue used for logins, reconnects, logouts 
+	 * Variable used for logins, reconnects, logouts 
 	 */
-	wait_queue_head_t sbp2_login_wait;
+	atomic_t sbp2_login_complete;
 
 	/* 
 	 * Pool of command orbs, so we can have more than overlapped command per id
@@ -501,6 +501,13 @@
 static void sbp2_remove_device(struct sbp2scsi_host_info *hi, 
 			       struct scsi_id_instance_data *scsi_id);
 
+#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
+static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data,
+                                     u64 addr, unsigned int length);
+static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
+                                    u64 addr, unsigned int length);
+#endif
+
 /*
  * SBP-2 protocol related prototypes
  */
@@ -523,9 +530,8 @@
 static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
 			     Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
 static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data);
-static void sbp2_check_sbp2_command(unchar *cmd);
-static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, 
-				     Scsi_Cmnd *SCpnt);
+static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd);
+static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, Scsi_Cmnd *SCpnt);
 static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id);
 static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
 static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
diff -Nru a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
--- a/drivers/ieee1394/video1394.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/ieee1394/video1394.c	Tue Jul 16 16:49:41 2002
@@ -168,86 +168,35 @@
 /* Memory management functions */
 /*******************************/
 
-#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
-
-/* [DaveM] I've recoded most of this so that:
- * 1) It's easier to tell what is happening
- * 2) It's more portable, especially for translating things
- *    out of vmalloc mapped areas in the kernel.
- * 3) Less unnecessary translations happen.
- *
- * The code used to assume that the kernel vmalloc mappings
- * existed in the page tables of every process, this is simply
- * not guaranteed.  We now use pgd_offset_k which is the
- * defined way to get at the kernel page tables.
- */
-
-/* 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_kernel(pmd, adr);
-                        pte = *ptep;
-                        if(pte_present(pte)) {
-				ret = (unsigned long) 
-					page_address(pte_page(pte));
-                                ret |= (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;
+	unsigned long kva, ret;
 
-        va = VMALLOC_VMADDR(adr);
-        kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = virt_to_bus((void *)kva);
-        MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
-        return 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.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr) 
 {
-        unsigned long va, kva, ret;
+        unsigned long kva, ret;
 
-        va = VMALLOC_VMADDR(adr);
-        kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
-        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
         return ret;
 }
 
 static void * rvmalloc(unsigned long size)
 {
 	void * mem;
-	unsigned long adr, page;
-        
+	unsigned long adr;
+
+	size=PAGE_ALIGN(size);
 	mem=vmalloc_32(size);
 	if (mem) 
 	{
@@ -256,8 +205,7 @@
 	        adr=(unsigned long) mem;
 		while (size > 0) 
                 {
-	                page = kvirt_to_pa(adr);
-			mem_map_reserve(virt_to_page(__va(page)));
+			mem_map_reserve(vmalloc_to_page((void *)adr));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -267,15 +215,14 @@
 
 static void rvfree(void * mem, unsigned long size)
 {
-        unsigned long adr, page;
-        
+        unsigned long adr;
+
 	if (mem) 
 	{
 	        adr=(unsigned long) mem;
-		while (size > 0) 
+		while ((long) size > 0) 
                 {
-	                page = kvirt_to_pa(adr);
-			mem_map_unreserve(virt_to_page(__va(page)));
+			mem_map_unreserve(vmalloc_to_page((void *)adr));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -520,11 +467,11 @@
 static void reset_ir_status(struct dma_iso_ctx *d, int n)
 {
 	int i;
-	d->ir_prg[n][0].status = 4;
-	d->ir_prg[n][1].status = PAGE_SIZE-4;
+	d->ir_prg[n][0].status = cpu_to_le32(4);
+	d->ir_prg[n][1].status = cpu_to_le32(PAGE_SIZE-4);
 	for (i=2;i<d->nb_cmd-1;i++)
-		d->ir_prg[n][i].status = PAGE_SIZE;
-	d->ir_prg[n][i].status = d->left_size;
+		d->ir_prg[n][i].status = cpu_to_le32(PAGE_SIZE);
+	d->ir_prg[n][i].status = cpu_to_le32(d->left_size);
 }
 
 static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags)
@@ -534,38 +481,38 @@
 	int i;
 
 	/* the first descriptor will read only 4 bytes */
-	ir_prg[0].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-		DMA_CTL_BRANCH | 4;
+	ir_prg[0].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
+		DMA_CTL_BRANCH | 4);
 
 	/* set the sync flag */
 	if (flags & VIDEO1394_SYNC_FRAMES)
-		ir_prg[0].control |= DMA_CTL_WAIT;
+		ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT);
 
-	ir_prg[0].address = kvirt_to_bus(buf);
-	ir_prg[0].branchAddress =  (virt_to_bus(&(ir_prg[1].control)) 
-				    & 0xfffffff0) | 0x1;
+	ir_prg[0].address = cpu_to_le32(kvirt_to_bus(buf));
+	ir_prg[0].branchAddress =  cpu_to_le32((virt_to_bus(&(ir_prg[1].control)) 
+				    & 0xfffffff0) | 0x1);
 
 	/* the second descriptor will read PAGE_SIZE-4 bytes */
-	ir_prg[1].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-		DMA_CTL_BRANCH | (PAGE_SIZE-4);
-	ir_prg[1].address = kvirt_to_bus(buf+4);
-	ir_prg[1].branchAddress =  (virt_to_bus(&(ir_prg[2].control)) 
-				    & 0xfffffff0) | 0x1;
+	ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
+		DMA_CTL_BRANCH | (PAGE_SIZE-4));
+	ir_prg[1].address = cpu_to_le32(kvirt_to_bus(buf+4));
+	ir_prg[1].branchAddress =  cpu_to_le32((virt_to_bus(&(ir_prg[2].control)) 
+				    & 0xfffffff0) | 0x1);
 	
 	for (i=2;i<d->nb_cmd-1;i++) {
-		ir_prg[i].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | 
-			DMA_CTL_BRANCH | PAGE_SIZE;
-		ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE);
+		ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | 
+			DMA_CTL_BRANCH | PAGE_SIZE);
+		ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE));
 
 		ir_prg[i].branchAddress =  
-			(virt_to_bus(&(ir_prg[i+1].control)) 
-			 & 0xfffffff0) | 0x1;
+			cpu_to_le32((virt_to_bus(&(ir_prg[i+1].control)) 
+			 & 0xfffffff0) | 0x1);
 	}
 
 	/* the last descriptor will generate an interrupt */
-	ir_prg[i].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | 
-		DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size;
-	ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE);
+	ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | 
+		DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
+	ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE));
 }
 	
 static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags)
@@ -628,7 +575,7 @@
 
 	spin_lock(&d->lock);
 	for (i=0;i<d->num_desc;i++) {
-		if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) {
+		if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) {
 			reset_ir_status(d, i);
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
@@ -664,7 +611,7 @@
 	buf[7] = timeStamp & 0xff; 
 
     /* if first packet is empty packet, then put timestamp into the next full one too */
-    if ( (d->it_prg[n][0].data[1] >>16) == 0x008) {
+    if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {
    	    buf += d->packet_size;
     	buf[6] = timeStamp >> 8;
 	    buf[7] = timeStamp & 0xff;
@@ -683,7 +630,7 @@
 	buf[7] = timeStamp & 0xff;
 
     /* if first packet is empty packet, then put timestamp into the next full one too */
-    if ( (d->it_prg[n][0].data[1] >>16) == 0x008) {
+    if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {
    	    buf += d->packet_size;
     	buf[6] = timeStamp >> 8;
 	    buf[7] = timeStamp & 0xff;
@@ -707,7 +654,8 @@
 
 	spin_lock(&d->lock);
 	for (i=0;i<d->num_desc;i++) {
-		if (d->it_prg[i][d->last_used_cmd[i]].end.status& 0xFFFF0000) {
+		if (d->it_prg[i][d->last_used_cmd[i]].end.status& 
+			cpu_to_le32(0xFFFF0000)) {
 			int next = d->next_buffer[i];
 			put_timestamp(ohci, d, next);
 			d->it_prg[i][d->last_used_cmd[i]].end.status = 0;
@@ -727,39 +675,40 @@
 	d->last_used_cmd[n] = d->nb_cmd - 1;
 	for (i=0;i<d->nb_cmd;i++) {
 				 
-		it_prg[i].begin.control = DMA_CTL_OUTPUT_MORE |
-			DMA_CTL_IMMEDIATE | 8 ;
+		it_prg[i].begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE |
+			DMA_CTL_IMMEDIATE | 8) ;
 		it_prg[i].begin.address = 0;
 		
 		it_prg[i].begin.status = 0;
 		
-		it_prg[i].data[0] = 
+		it_prg[i].data[0] = cpu_to_le32(
 			(SPEED_100 << 16) 
 			| (/* tag */ 1 << 14)
 			| (d->channel << 8) 
-			| (TCODE_ISO_DATA << 4);
-		if (i==0) it_prg[i].data[0] |= sync_tag;
-		it_prg[i].data[1] = d->packet_size << 16;
+			| (TCODE_ISO_DATA << 4));
+		if (i==0) it_prg[i].data[0] |= cpu_to_le32(sync_tag);
+		it_prg[i].data[1] = cpu_to_le32(d->packet_size << 16);
 		it_prg[i].data[2] = 0;
 		it_prg[i].data[3] = 0;
 		
-		it_prg[i].end.control = DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH;
+		it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST |
+			    	    	     DMA_CTL_BRANCH);
 		it_prg[i].end.address =
-			kvirt_to_bus(buf+i*d->packet_size);
+			cpu_to_le32(kvirt_to_bus(buf+i*d->packet_size));
 
 		if (i<d->nb_cmd-1) {
-			it_prg[i].end.control |= d->packet_size;
+			it_prg[i].end.control |= cpu_to_le32(d->packet_size);
 			it_prg[i].begin.branchAddress = 
-				(virt_to_bus(&(it_prg[i+1].begin.control)) 
-				 & 0xfffffff0) | 0x3;
+				cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) 
+				 & 0xfffffff0) | 0x3);
 			it_prg[i].end.branchAddress = 
-				(virt_to_bus(&(it_prg[i+1].begin.control)) 
-				 & 0xfffffff0) | 0x3;
+				cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) 
+				 & 0xfffffff0) | 0x3);
 		}
 		else {
 			/* the last prg generates an interrupt */
-			it_prg[i].end.control |= DMA_CTL_UPDATE | 
-				DMA_CTL_IRQ | d->left_size;
+			it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE | 
+				DMA_CTL_IRQ | d->left_size);
 			/* the last prg doesn't branch */
 			it_prg[i].begin.branchAddress = 0;
 			it_prg[i].end.branchAddress = 0;
@@ -798,21 +747,21 @@
 		} else {
 			size = packet_sizes[i];
 		}
-		it_prg[i].data[1] = size << 16; 
-		it_prg[i].end.control = DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH;
+		it_prg[i].data[1] = cpu_to_le32(size << 16); 
+		it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH);
 
 		if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) {
-			it_prg[i].end.control |= size;
+			it_prg[i].end.control |= cpu_to_le32(size);
 			it_prg[i].begin.branchAddress = 
-				(virt_to_bus(&(it_prg[i+1].begin.control)) 
-				 & 0xfffffff0) | 0x3;
+				cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) 
+				 & 0xfffffff0) | 0x3);
 			it_prg[i].end.branchAddress = 
-				(virt_to_bus(&(it_prg[i+1].begin.control)) 
-				 & 0xfffffff0) | 0x3;
+				cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) 
+				 & 0xfffffff0) | 0x3);
 		} else {
 			/* the last prg generates an interrupt */
-			it_prg[i].end.control |= DMA_CTL_UPDATE | 
-				DMA_CTL_IRQ | size;
+			it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE | 
+				DMA_CTL_IRQ | size);
 			/* the last prg doesn't branch */
 			it_prg[i].begin.branchAddress = 0;
 			it_prg[i].end.branchAddress = 0;
@@ -1057,8 +1006,8 @@
 
 		if (d->last_buffer>=0) 
 			d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 
-				(virt_to_bus(&(d->ir_prg[v.buffer][0].control)) 
-				 & 0xfffffff0) | 0x1;
+				cpu_to_le32((virt_to_bus(&(d->ir_prg[v.buffer][0].control)) 
+				 & 0xfffffff0) | 0x1);
 
 		d->last_buffer = v.buffer;
 
@@ -1217,14 +1166,14 @@
 			d->it_prg[d->last_buffer]
 				[ d->last_used_cmd[d->last_buffer]
 					].end.branchAddress = 
-				(virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) 
-				 & 0xfffffff0) | 0x3;
+				cpu_to_le32((virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) 
+				 & 0xfffffff0) | 0x3);
 
 			d->it_prg[d->last_buffer]
 				[d->last_used_cmd[d->last_buffer]
 					].begin.branchAddress = 
-				(virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) 
-				 & 0xfffffff0) | 0x3;
+				cpu_to_le32((virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) 
+				 & 0xfffffff0) | 0x3);
 			d->next_buffer[d->last_buffer] = v.buffer;
 		}
 		d->last_buffer = v.buffer;
diff -Nru a/drivers/input/Config.help b/drivers/input/Config.help
--- a/drivers/input/Config.help	Tue Jul 16 16:49:42 2002
+++ b/drivers/input/Config.help	Tue Jul 16 16:49:42 2002
@@ -98,3 +98,12 @@
   inserted in and removed from the running kernel whenever you want).
   The module will be called joydev.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_UINPUT
+  Say Y here if you want to support user level drivers for input
+  subsystem accessible under char device 10:223 - /dev/input/uinput.
+
+  This driver 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 uinput.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.	    
diff -Nru a/drivers/input/Config.in b/drivers/input/Config.in
--- a/drivers/input/Config.in	Tue Jul 16 16:49:42 2002
+++ b/drivers/input/Config.in	Tue Jul 16 16:49:42 2002
@@ -23,6 +23,7 @@
 fi
 dep_tristate '  Event interface' CONFIG_INPUT_EVDEV $CONFIG_INPUT
 dep_tristate '  Event debugging' CONFIG_INPUT_EVBUG $CONFIG_INPUT
+dep_tristate '  User level driver support' CONFIG_INPUT_UINPUT $CONFIG_INPUT $CONFIG_EXPERIMENTAL
 
 comment 'Input I/O drivers'
 source drivers/input/gameport/Config.in
diff -Nru a/drivers/input/Makefile b/drivers/input/Makefile
--- a/drivers/input/Makefile	Tue Jul 16 16:49:43 2002
+++ b/drivers/input/Makefile	Tue Jul 16 16:49:43 2002
@@ -16,6 +16,7 @@
 obj-$(CONFIG_INPUT_TSDEV)	+= tsdev.o
 obj-$(CONFIG_INPUT_POWER)	+= power.o
 obj-$(CONFIG_INPUT_EVBUG)	+= evbug.o
+obj-$(CONFIG_INPUT_UINPUT)	+= uinput.o
 
 obj-$(CONFIG_INPUT_KEYBOARD)	+= keyboard/
 obj-$(CONFIG_INPUT_MOUSE)	+= mouse/
diff -Nru a/drivers/input/evbug.c b/drivers/input/evbug.c
--- a/drivers/input/evbug.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/input/evbug.c	Tue Jul 16 16:49:42 2002
@@ -37,6 +37,8 @@
 MODULE_DESCRIPTION("Input driver event debug module"); 
 MODULE_LICENSE("GPL");
 
+static char evbug_name[] = "evbug";
+
 static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
 	printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value);
@@ -52,6 +54,7 @@
 
 	handle->dev = dev;
 	handle->handler = handler;
+	handle->name = evbug_name;
 
 	input_open_device(handle);
 
diff -Nru a/drivers/input/gameport/Config.in b/drivers/input/gameport/Config.in
--- a/drivers/input/gameport/Config.in	Tue Jul 16 16:49:41 2002
+++ b/drivers/input/gameport/Config.in	Tue Jul 16 16:49:41 2002
@@ -13,7 +13,7 @@
 
 dep_tristate '  Classic ISA and PnP gameport support' CONFIG_GAMEPORT_NS558 $CONFIG_GAMEPORT
 dep_tristate '  PDPI Lightning 4 gamecard support' CONFIG_GAMEPORT_L4 $CONFIG_GAMEPORT
-dep_tristate '  SB Live and Audigy gameport support' CONFIG_INPUT_EMU10K1 $CONFIG_GAMEPORT
+dep_tristate '  SB Live and Audigy gameport support' CONFIG_GAMEPORT_EMU10K1 $CONFIG_GAMEPORT
 dep_tristate '  Aureal Vortex, Vortex 2 gameport support' CONFIG_GAMEPORT_VORTEX $CONFIG_GAMEPORT
 dep_tristate '  ForteMedia FM801 gameport support' CONFIG_GAMEPORT_FM801 $CONFIG_GAMEPORT
 dep_tristate '  Crystal SoundFusion gameport support' CONFIG_GAMEPORT_CS461x $CONFIG_GAMEPORT
diff -Nru a/drivers/input/joystick/Config.help b/drivers/input/joystick/Config.help
--- a/drivers/input/joystick/Config.help	Tue Jul 16 16:49:41 2002
+++ b/drivers/input/joystick/Config.help	Tue Jul 16 16:49:41 2002
@@ -1,4 +1,4 @@
-CONFIG_JOYSTICK
+CONFIG_INPUT_JOYSTICK
   If you have a joystick, 6dof controller, gamepad, steering wheel,
   weapon control system or something like that you can say Y here
   and the list of supported devices will be displayed. This option
@@ -103,24 +103,6 @@
   The module will be called tmdc.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-CONFIG_JOYSTICK_IFORCE_USB
-  Say Y here if you have an I-Force joystick or steering wheel
-  connected to your USB port. 
-
-  This driver 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 iforce.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_JOYSTICK_IFORCE_232
-  Say Y here if you have an I-Force joystick or steering wheel
-  connected to your serial (COM) port.
-
-  This driver 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 iforce.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
 CONFIG_JOYSTICK_WARRIOR
   Say Y here if you have a Logitech WingMan Warrior joystick connected
   to your computer's serial port. 
@@ -221,3 +203,12 @@
   The module will be called joy-amiga.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+CONFIG_INPUT_JOYDUMP
+  Say Y here if you want to dump data from your joystick into the system
+  log for debugging purposes. Say N if you are making a production
+  configuration or aren't sure. 
+
+  This driver 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 joydump.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
diff -Nru a/drivers/input/joystick/Config.in b/drivers/input/joystick/Config.in
--- a/drivers/input/joystick/Config.in	Tue Jul 16 16:49:43 2002
+++ b/drivers/input/joystick/Config.in	Tue Jul 16 16:49:43 2002
@@ -14,15 +14,13 @@
 dep_tristate '  InterAct digital joysticks and gamepads' CONFIG_JOYSTICK_INTERACT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
 dep_tristate '  Microsoft SideWinder digital joysticks and gamepads' CONFIG_JOYSTICK_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
 dep_tristate '  ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOYSTICK_TMDC $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
-
-dep_tristate '  I-Force USB joysticks and wheels' CONFIG_JOYSTICK_IFORCE_USB $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_USB
-dep_tristate '  I-Force Serial joysticks and wheels' CONFIG_JOYSTICK_IFORCE_232 $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+source drivers/input/joystick/iforce/Config.in
 dep_tristate '  Logitech WingMan Warrior joystick' CONFIG_JOYSTICK_WARRIOR $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
 dep_tristate '  LogiCad3d Magellan/SpaceMouse 6dof controllers' CONFIG_JOYSTICK_MAGELLAN $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
 dep_tristate '  SpaceTec SpaceOrb/Avenger 6dof controllers' CONFIG_JOYSTICK_SPACEORB $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
 dep_tristate '  SpaceTec SpaceBall 6dof controllers' CONFIG_JOYSTICK_SPACEBALL $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
 dep_tristate '  Gravis Stinger gamepad' CONFIG_JOYSTICK_STINGER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
-dep_tristate '  Twiddler as as joystick' CONFIG_JOYSTICK_TWIDDLER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+dep_tristate '  Twiddler as a joystick' CONFIG_JOYSTICK_TWIDDLER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
 
 dep_tristate '  Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_JOYSTICK_DB9 $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT
 dep_tristate '  Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_JOYSTICK_GAMECON $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT
@@ -31,3 +29,5 @@
 if [ "$CONFIG_AMIGA" = "y" ]; then
    dep_tristate '  Amiga joysticks' CONFIG_JOYSTICK_AMIJOY $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK
 fi
+
+dep_tristate '  Gameport data dumper' CONFIG_INPUT_JOYDUMP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK
diff -Nru a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
--- a/drivers/input/joystick/Makefile	Tue Jul 16 16:49:43 2002
+++ b/drivers/input/joystick/Makefile	Tue Jul 16 16:49:43 2002
@@ -2,24 +2,6 @@
 # Makefile for the input core drivers.
 #
 
-# I-Force may need both USB and RS-232
-
-CONFIG_JOYSTICK_IFORCE := n
-
-ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
-	ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
-		CONFIG_JOYSTICK_IFORCE := y
-	endif
-endif
-
-ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m)
-	CONFIG_JOYSTICK_IFORCE := m
-endif
-
-ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m)
-	CONFIG_JOYSTICK_IFORCE := m
-endif
-
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_JOYSTICK_A3D)		+= a3d.o
diff -Nru a/drivers/input/joystick/iforce/Config.help b/drivers/input/joystick/iforce/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/iforce/Config.help	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,21 @@
+CONFIG_JOYSTICK_IFORCE
+  Say Y here if you have an I-Force joystick or steering wheel
+
+  You also must choose at least one of the two options below.
+
+  This driver 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 iforce.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_IFORCE_USB
+  Say Y here if you have an I-Force joystick or steering wheel
+  connected to your USB port. 
+
+CONFIG_JOYSTICK_IFORCE_232
+  Say Y here if you have an I-Force joystick or steering wheel
+  connected to your serial (COM) port.
+
+  You will need an additional utility called inputattach, see
+  Documentation/input/joystick.txt and ff.txt.
+
diff -Nru a/drivers/input/joystick/iforce/Config.in b/drivers/input/joystick/iforce/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/iforce/Config.in	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,14 @@
+#
+# I-Force driver configuration
+#
+
+dep_tristate '  I-Force devices' CONFIG_JOYSTICK_IFORCE $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK
+
+if [ "$CONFIG_JOYSTICK_IFORCE" = "m" -o "$CONFIG_JOYSTICK_IFORCE" = "y" ]; then
+	if [ "$CONFIG_JOYSTICK_IFORCE" = "m" -o "$CONFIG_USB" = "y" ]; then
+		dep_mbool '    I-Force USB joysticks and wheels' CONFIG_JOYSTICK_IFORCE_USB $CONFIG_USB
+	fi
+	if [ "$CONFIG_JOYSTICK_IFORCE" = "m" -o "$CONFIG_SERIO" = "y" ]; then
+		dep_mbool '    I-Force Serial joysticks and wheels' CONFIG_JOYSTICK_IFORCE_232 $CONFIG_SERIO
+	fi
+fi
diff -Nru a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile
--- a/drivers/input/joystick/iforce/Makefile	Tue Jul 16 16:49:42 2002
+++ b/drivers/input/joystick/iforce/Makefile	Tue Jul 16 16:49:42 2002
@@ -1,42 +1,30 @@
 #
 # Makefile for the I-Force driver
 #
+# By Johann Deneux <deneux@ifrance.com>
+#
 
-# I-Force may need both USB and RS-232
+# Goal definition
+list-multi	:= iforce.o
+iforce-objs	:= iforce-ff.o iforce-main.o iforce-packets.o
 
-CONFIG_JOYSTICK_IFORCE := n
+obj-$(CONFIG_JOYSTICK_IFORCE)	+= iforce.o 
 
 ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
-	ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
-		CONFIG_JOYSTICK_IFORCE := y
-	endif
+	iforce-objs += iforce-serio.o 
 endif
 
-ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m)
-	CONFIG_JOYSTICK_IFORCE := m
+ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
+	iforce-objs += iforce-usb.o 
 endif
 
-ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m)
-	CONFIG_JOYSTICK_IFORCE := m
-endif
-
-obj-$(CONFIG_JOYSTICK_IFORCE)	+= iforce.o 
+EXTRA_CFLAGS = -Werror-implicit-function-declaration
 
 # The global Rules.make.
 
 include $(TOPDIR)/Rules.make
 
-# iforce.o is a multipart module.
-
-IFORCEOBJS = iforce-ff.o iforce-main.o iforce-packets.o
-
-ifneq ($(CONFIG_JOYSTICK_IFORCE_232),)
-	IFORCEOBJS += iforce-serio.o 
-endif
-
-ifneq ($(CONFIG_JOYSTICK_IFORCE_USB),)
-	IFORCEOBJS += iforce-usb.o 
-endif
+# Additional rules
+iforce.o: $(iforce-objs)
+	$(LD) -r -o $@ $(iforce-objs)
 
-iforce.o: $(IFORCEOBJS) 
-	$(LD) -i $(IFORCEOBJS) -o $@
diff -Nru a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
--- a/drivers/input/joystick/iforce/iforce-main.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/input/joystick/iforce/iforce-main.c	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: iforce-main.c,v 1.18 2002/06/09 11:03:03 jdeneux Exp $
+ * $Id: iforce-main.c,v 1.19 2002/07/07 10:22:50 jdeneux Exp $
  *
  *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
  *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
@@ -248,7 +248,7 @@
 	struct iforce *iforce = dev->private;
 
 	switch (iforce->bus) {
-#ifdef IFORCE_USB
+#ifdef CONFIG_JOYSTICK_IFORCE_USB
 		case IFORCE_USB:
 			iforce->irq->dev = iforce->usbdev;
 			if (usb_submit_urb(iforce->irq, GFP_KERNEL))
@@ -305,7 +305,7 @@
 	iforce_send_packet(iforce, FF_CMD_ENABLE, "\001");
 
 	switch (iforce->bus) {
-#ifdef IFORCE_USB
+#ifdef CONFIG_JOYSTICK_IFORCE_USB
 		case IFORCE_USB:
 			usb_unlink_urb(iforce->irq);
 
@@ -323,12 +323,12 @@
 void iforce_delete_device(struct iforce *iforce)
 {
 	switch (iforce->bus) {
-#ifdef IFORCE_USB
+#ifdef CONFIG_JOYSTICK_IFORCE_USB
 	case IFORCE_USB:
 		iforce_usb_delete(iforce);
 		break;
 #endif
-#ifdef IFORCE_232
+#ifdef CONFIG_JOYSTICK_IFORCE_232
 	case IFORCE_232:
 		//TODO: Wait for the last packets to be sent
 		break;
@@ -520,10 +520,10 @@
 
 static int __init iforce_init(void)
 {
-#ifdef IFORCE_USB
+#ifdef CONFIG_JOYSTICK_IFORCE_USB
 	usb_register(&iforce_usb_driver);
 #endif
-#ifdef IFORCE_232
+#ifdef CONFIG_JOYSTICK_IFORCE_232
 	serio_register_device(&iforce_serio_dev);
 #endif
 	return 0;
@@ -531,10 +531,10 @@
 
 static void __exit iforce_exit(void)
 {
-#ifdef IFORCE_USB
+#ifdef CONFIG_JOYSTICK_IFORCE_USB
 	usb_deregister(&iforce_usb_driver);
 #endif
-#ifdef IFORCE_232
+#ifdef CONFIG_JOYSTICK_IFORCE_232
 	serio_unregister_device(&iforce_serio_dev);
 #endif
 }
diff -Nru a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
--- a/drivers/input/joystick/iforce/iforce-packets.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/input/joystick/iforce/iforce-packets.c	Tue Jul 16 16:49:41 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: iforce-packets.c,v 1.15 2002/06/09 11:08:04 jdeneux Exp $
+ * $Id: iforce-packets.c,v 1.16 2002/07/07 10:22:50 jdeneux Exp $
  *
  *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
  *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
@@ -101,13 +101,13 @@
  */
 	switch (iforce->bus) {
 
-#ifdef IFORCE_232
+#ifdef CONFIG_JOYSTICK_IFORCE_232
 		case IFORCE_232:
 		if (empty)
 			iforce_serial_xmit(iforce);
 		break;
 #endif
-#ifdef IFORCE_USB
+#ifdef CONFIG_JOYSTICK_IFORCE_USB
 		case IFORCE_USB: 
 
 		if (iforce->usbdev && empty &&
@@ -161,7 +161,7 @@
 		printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used);
 	being_used++;
 
-#ifdef IFORCE_232
+#ifdef CONFIG_JOYSTICK_IFORCE_232
 	if (HI(iforce->expect_packet) == HI(cmd)) {
 		iforce->expect_packet = 0;
 		iforce->ecmd = cmd;
@@ -251,7 +251,7 @@
 
 	case IFORCE_USB:
 
-#ifdef IFORCE_USB
+#ifdef CONFIG_JOYSTICK_IFORCE_USB
 		iforce->cr.bRequest = packet[0];
 		iforce->ctrl->dev = iforce->usbdev;
 
@@ -281,7 +281,7 @@
 
 	case IFORCE_232:
 
-#ifdef IFORCE_232
+#ifdef CONFIG_JOYSTICK_IFORCE_232
 		iforce->expect_packet = FF_CMD_QUERY;
 		iforce_send_packet(iforce, FF_CMD_QUERY, packet);
 
diff -Nru a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
--- a/drivers/input/joystick/iforce/iforce.h	Tue Jul 16 16:49:42 2002
+++ b/drivers/input/joystick/iforce/iforce.h	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: iforce.h,v 1.12 2002/06/09 11:08:04 jdeneux Exp $
+ * $Id: iforce.h,v 1.13 2002/07/07 10:22:50 jdeneux Exp $
  *
  *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
  *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
@@ -39,7 +39,7 @@
 #include <linux/circ_buf.h>
 #include <asm/semaphore.h>
 
-/* FF: This module provides arbitrary resource management routines.
+/* This module provides arbitrary resource management routines.
  * I use it to manage the device's memory.
  * Despite the name of this module, I am *not* going to access the ioports.
  */
@@ -47,12 +47,9 @@
 
 #define IFORCE_MAX_LENGTH	16
 
-#if defined(CONFIG_JOYSTICK_IFORCE_232)
+/* iforce::bus */
 #define IFORCE_232	1
-#endif
-#if defined(CONFIG_JOYSTICK_IFORCE_USB)
 #define IFORCE_USB	2
-#endif
 
 #define FALSE 0
 #define TRUE 1
@@ -129,12 +126,12 @@
 	u16 ecmd;
 	u16 expect_packet;
 
-#ifdef IFORCE_232
+#ifdef CONFIG_JOYSTICK_IFORCE_232
 	struct serio *serio;		/* RS232 transfer */
 	int idx, pkt, len, id;
 	unsigned char csum;
 #endif
-#ifdef IFORCE_USB
+#ifdef CONFIG_JOYSTICK_IFORCE_USB
 	struct usb_device *usbdev;	/* USB transfer */
 	struct urb *irq, *out, *ctrl;
 	struct usb_ctrlrequest cr;
diff -Nru a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/joydump.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,152 @@
+/*
+ * $Id: joydump.c,v 1.1 2002/01/23 06:56:16 jsimmons Exp $
+ *
+ *  Copyright (c) 1996-2001 Vojtech Pavlik
+ */
+
+/*
+ * This is just a very simple driver that can dump the data
+ * out of the joystick port into the syslog ...
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/gameport.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Gameport data dumper module");
+MODULE_LICENSE("GPL");
+
+#define BUF_SIZE 256
+
+struct joydump {
+	unsigned int time;
+	unsigned char data;
+};
+
+static void __devinit joydump_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+	struct joydump buf[BUF_SIZE];
+	int axes[4], buttons;
+	int i, j, t, timeout;
+	unsigned long flags;
+	unsigned char u;
+
+	printk(KERN_INFO "joydump: ,------------------- START ------------------.\n");
+	printk(KERN_INFO "joydump: | Dumping gameport%s.\n", gameport->phys);
+	printk(KERN_INFO "joydump: | Speed: %4d kHz.                            |\n", gameport->speed);
+
+	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+
+		printk(KERN_INFO "joydump: | Raw mode not available - trying cooked.    |\n");
+
+		if (gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
+			
+			printk(KERN_INFO "joydump: | Cooked not available either. Failing.      |\n");
+			printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
+			return;
+		}
+
+		gameport_cooked_read(gameport, axes, &buttons);
+
+		for (i = 0; i < 4; i++)
+			printk(KERN_INFO "joydump: | Axis %d: %4d.                              |\n", i, axes[i]);
+		printk(KERN_INFO "joydump: | Buttons %02x.                                |\n", buttons);
+		printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
+	}
+
+	timeout = gameport_time(gameport, 10000); /* 10 ms */
+	t = 0;
+	i = 1;
+
+	save_flags(flags);
+	cli();
+
+	u = gameport_read(gameport);
+
+	buf[0].data = u;
+	buf[0].time = t;
+
+	gameport_trigger(gameport);
+
+	while (i < BUF_SIZE && t < timeout) {
+
+		buf[i].data = gameport_read(gameport);
+
+		if (buf[i].data ^ u) {
+			u = buf[i].data;
+			buf[i].time = t;
+			i++;
+		}
+		t++;
+	}
+
+	restore_flags(flags);
+
+/*
+ * Dump data.
+ */
+
+	t = i;
+
+	printk(KERN_INFO "joydump: >------------------- DATA -------------------<\n");
+	printk(KERN_INFO "joydump: | index: %3d delta: %3d.%02d us data: ", 0, 0, 0);
+	for (j = 7; j >= 0; j--)
+		printk("%d",(buf[0].data >> j) & 1);
+	printk(" |\n");
+	for (i = 1; i < t; i++) {
+		printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ",
+			i, buf[i].time - buf[i-1].time);
+		for (j = 7; j >= 0; j--)
+			printk("%d",(buf[i].data >> j) & 1);
+		printk("    |\n");
+	}
+
+	printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
+}
+
+static void __devexit joydump_disconnect(struct gameport *gameport)
+{
+	gameport_close(gameport);
+}
+
+static struct gameport_dev joydump_dev = {
+	connect:	joydump_connect,
+	disconnect:	joydump_disconnect,
+};
+
+static int __init joydump_init(void)
+{
+	gameport_register_device(&joydump_dev);
+	return 0;
+}
+
+static void __exit joydump_exit(void)
+{
+	gameport_unregister_device(&joydump_dev);
+}
+
+module_init(joydump_init);
+module_exit(joydump_exit);
diff -Nru a/drivers/input/keyboard/Config.help b/drivers/input/keyboard/Config.help
--- a/drivers/input/keyboard/Config.help	Tue Jul 16 16:49:42 2002
+++ b/drivers/input/keyboard/Config.help	Tue Jul 16 16:49:42 2002
@@ -46,6 +46,14 @@
   The module will be called xtkbd.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
+CONFIG_KEYBOARD_NEWTON
+  Say Y here if you have a Newton keyboard on a serial port.
+
+  This driver 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 maple_keyb.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
 CONFIG_KEYBOARD_MAPLE  
   Say Y here if you have a DreamCast console running Linux and have
   a keyboard attached to its Maple bus.
diff -Nru a/drivers/input/keyboard/Config.in b/drivers/input/keyboard/Config.in
--- a/drivers/input/keyboard/Config.in	Tue Jul 16 16:49:43 2002
+++ b/drivers/input/keyboard/Config.in	Tue Jul 16 16:49:43 2002
@@ -8,6 +8,7 @@
 dep_tristate '  Sun Type 4 and Type 5 keyboard support' CONFIG_KEYBOARD_SUNKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
 dep_tristate '  PS/2 to Serial converter support' CONFIG_KEYBOARD_PS2SERKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
 dep_tristate '  XT Keyboard support' CONFIG_KEYBOARD_XTKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+dep_tristate '  Newton keyboard' CONFIG_KEYBOARD_NEWTON $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
 
 if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
    dep_tristate '  Maple bus keyboard support' CONFIG_KEYBOARD_MAPLE $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_MAPLE
diff -Nru a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
--- a/drivers/input/keyboard/Makefile	Tue Jul 16 16:49:42 2002
+++ b/drivers/input/keyboard/Makefile	Tue Jul 16 16:49:42 2002
@@ -10,6 +10,7 @@
 obj-$(CONFIG_KEYBOARD_SUNKBD)		+= sunkbd.o
 obj-$(CONFIG_KEYBOARD_XTKBD)		+= xtkbd.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
+obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o
 
 # The global Rules.make.
 
diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
--- a/drivers/input/keyboard/atkbd.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/input/keyboard/atkbd.c	Tue Jul 16 16:49:43 2002
@@ -121,14 +121,12 @@
 	struct serio *serio;
 	char name[64];
 	char phys[32];
-	struct tq_struct tq;
 	unsigned char cmdbuf[4];
 	unsigned char cmdcnt;
 	unsigned char set;
-	char release;
-	char ack;
-	char emul;
-	char error;
+	unsigned char release;
+	signed char ack;
+	unsigned char emul;
 	unsigned short id;
 };
 
@@ -162,8 +160,7 @@
 
 	switch (atkbd->keycode[code]) {
 		case ATKBD_KEY_BAT:
-			queue_task(&atkbd->tq, &tq_immediate);
-			mark_bh(IMMEDIATE_BH);
+			serio_rescan(atkbd->serio);
 			return;
 		case ATKBD_KEY_EMUL0:
 			atkbd->emul = 1;
@@ -432,21 +429,6 @@
 }
 
 /*
- * atkbd_powerup() is called when the keyboard sends the 0xaa character,
- * meaning that it was disconnected and reconnected. We close the port
- * in that case and let the upper layer find an appropriate driver for
- * the device that was connected. It may be a mouse, or a keyboard, we
- * don't know yet.
- */
-
-static void atkbd_powerup(void *data)
-{
-	struct atkbd *atkbd = data;
-	mdelay(40); /* FIXME!!! Wait some nicer way */
-	serio_rescan(atkbd->serio);
-}
-
-/*
  * atkbd_connect() is called when the serio module finds and interface
  * that isn't handled yet by an appropriate device driver. We check if
  * there is an AT keyboard out there and if yes, we register ourselves
@@ -477,9 +459,6 @@
 	atkbd->dev.event = atkbd_event;
 	atkbd->dev.private = atkbd;
 
-	atkbd->tq.routine = atkbd_powerup;
-	atkbd->tq.data = atkbd;
-
 	serio->private = atkbd;
 
 	if (serio_open(serio, dev)) {
@@ -504,7 +483,7 @@
 
 	if (atkbd->set == 4) {
 		atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE);
-		sprintf(atkbd->name, "AT Set 2 Extended keyboard\n");
+		sprintf(atkbd->name, "AT Set 2 Extended keyboard");
 	} else
 		sprintf(atkbd->name, "AT Set %d keyboard", atkbd->set);
 
diff -Nru a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/keyboard/newtonkbd.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,149 @@
+/*
+ *  Copyright (c) 2000 Justin Cormack
+ */
+
+/*
+ * Newton keyboard driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <j.cormack@doc.ic.ac.uk>, or by paper mail:
+ * Justin Cormack, 68 Dartmouth Park Road, London NW5 1SN, UK.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+
+MODULE_AUTHOR("Justin Cormack <j.cormack@doc.ic.ac.uk>");
+
+#define NKBD_KEY	0x7f
+#define NKBD_PRESS	0x80
+
+static unsigned char nkbd_keycode[128] = {
+	KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X,
+	KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R,
+	KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5,
+	KEY_EQUAL, KEY_9, KEY_7, KEY_MINUS, KEY_8, KEY_0, KEY_RIGHTBRACE, KEY_O,
+	KEY_U, KEY_LEFTBRACE, KEY_I, KEY_P, KEY_ENTER, KEY_L, KEY_J, KEY_APOSTROPHE,
+	KEY_K, KEY_SEMICOLON, KEY_BACKSLASH, KEY_COMMA, KEY_SLASH, KEY_N, KEY_M, KEY_DOT,
+	KEY_TAB, KEY_SPACE, KEY_GRAVE, KEY_DELETE, 0, 0, 0, KEY_LEFTMETA,
+	KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_LEFTALT, KEY_LEFTCTRL, KEY_RIGHTSHIFT, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0
+};
+
+static char *nkbd_name = "Newton Keyboard";
+
+struct nkbd {
+	unsigned char keycode[128];
+	struct input_dev dev;
+	struct serio *serio;
+	char phys[32];
+};
+
+void nkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct nkbd *nkbd = serio->private;
+
+	/* invalid scan codes are probably the init sequence, so we ignore them */
+	if (nkbd->keycode[data & NKBD_KEY])
+		input_report_key(&nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS);
+
+	else if (data == 0xe7) /* end of init sequence */
+		printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys);
+}
+
+void nkbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct nkbd *nkbd;
+	int i;
+
+	if (serio->type != (SERIO_RS232 | SERIO_NEWTON))
+		return;
+
+	if (!(nkbd = kmalloc(sizeof(struct nkbd), GFP_KERNEL)))
+		return;
+
+	memset(nkbd, 0, sizeof(struct nkbd));
+
+	nkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+
+	nkbd->serio = serio;
+
+	nkbd->dev.keycode = nkbd->keycode;
+	nkbd->dev.private = nkbd;
+
+	serio->private = nkbd;
+
+	if (serio_open(serio, dev)) {
+		kfree(nkbd);
+		return;
+	}
+
+	memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode));
+	for (i = 0; i < 128; i++)
+		set_bit(nkbd->keycode[i], nkbd->dev.keybit);
+	clear_bit(0, nkbd->dev.keybit);
+
+	sprintf(nkbd->phys, "%s/input0", serio->phys);
+
+	nkbd->dev.name = nkbd_name;
+	nkbd->dev.phys = nkbd->phys;
+	nkbd->dev.idbus = BUS_RS232;
+	nkbd->dev.idvendor = SERIO_NEWTON;
+	nkbd->dev.idproduct = 0x0001;
+	nkbd->dev.idversion = 0x0100;
+
+	input_register_device(&nkbd->dev);
+
+	printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys);
+}
+
+void nkbd_disconnect(struct serio *serio)
+{
+	struct nkbd *nkbd = serio->private;
+	input_unregister_device(&nkbd->dev);
+	serio_close(serio);
+	kfree(nkbd);
+}
+
+struct serio_dev nkbd_dev = {
+	interrupt:	nkbd_interrupt,
+	connect:	nkbd_connect,
+	disconnect:	nkbd_disconnect
+};
+
+int __init nkbd_init(void)
+{
+	serio_register_device(&nkbd_dev);
+	return 0;
+}
+
+void __exit nkbd_exit(void)
+{
+	serio_unregister_device(&nkbd_dev);
+}
+
+module_init(nkbd_init);
+module_exit(nkbd_exit);
diff -Nru a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
--- a/drivers/input/mouse/amimouse.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/input/mouse/amimouse.c	Tue Jul 16 16:49:41 2002
@@ -1,38 +1,20 @@
 /*
- * $Id: amimouse.c,v 1.9 2001/09/25 10:12:07 vojtech Exp $
+ *  Amiga mouse driver for Linux/m68k
  *
- *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *  Copyright (c) 2000-2002 Vojtech Pavlik
  *
  *  Based on the work of:
  *	Michael Rausch		James Banks
  *	Matther Dillon		David Giller
  *	Nathan Laredo		Linus Torvalds
  *	Johan Myreen		Jes Sorensen
- *	Russel King
+ *	Russell King
  */
 
 /*
- * Amiga mouse driver for Linux/m68k
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation
  */
 
 #include <linux/module.h>
@@ -70,10 +52,10 @@
 	dx = nx - amimouse_lastx;
 	dy = ny - amimouse_lasty;
 
-	if (dx < -127) dx = (256 + nx) - lastx;
-	if (dx >  127) dx = (nx - 256) - lastx;
-	if (dy < -127) dy = (256 + ny) - lasty;
-	if (dy >  127) dy = (ny - 256) - lasty;
+	if (dx < -127) dx = (256 + nx) - amimouse_lastx;
+	if (dx >  127) dx = (nx - 256) - amimouse_lastx;
+	if (dy < -127) dy = (256 + ny) - amimouse_lasty;
+	if (dy >  127) dy = (ny - 256) - amimouse_lasty;
 
 	amimouse_lastx = nx;
 	amimouse_lasty = ny;
diff -Nru a/drivers/input/mouse/psmouse.c b/drivers/input/mouse/psmouse.c
--- a/drivers/input/mouse/psmouse.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/input/mouse/psmouse.c	Tue Jul 16 16:49:41 2002
@@ -216,8 +216,7 @@
 	}
 
 	if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
-		queue_task(&psmouse->tq, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
+		serio_rescan(serio);
 		return;
 	}	
 }
@@ -558,22 +557,6 @@
 }
 
 /*
- * psmouse_powerup() is called when we get the powerup
- * sequence - 0xaa [0x00], so that the mouse/kbd is re-probed.
- */
-
-static void psmouse_powerup(void *data)
-{
-        struct psmouse *psmouse = data;
-
-	if (psmouse->packet[0] == PSMOUSE_RET_BAT && (psmouse->pktcnt == 1 ||
-	   (psmouse->pktcnt == 2 && psmouse->packet[1] == 0x00))) {
-		mdelay(40); /* FIXME!!! Wait some nicer way */
-		serio_rescan(psmouse->serio);
-	}
-}
-
-/*
  * psmouse_connect() is a callback form the serio module when
  * an unhandled serio port is found.
  */
@@ -596,8 +579,6 @@
 
 	psmouse->serio = serio;
 	psmouse->dev.private = psmouse;
-	psmouse->tq.routine = psmouse_powerup;
-	psmouse->tq.data = psmouse;
 
 	serio->private = psmouse;
 
diff -Nru a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
--- a/drivers/input/mouse/rpcmouse.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/input/mouse/rpcmouse.c	Tue Jul 16 16:49:42 2002
@@ -1,37 +1,22 @@
 /*
- * $Id: rpcmouse.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *  Acorn RiscPC mouse driver for Linux/ARM
  *
- *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *  Copyright (c) 2000-2002 Vojtech Pavlik
+ *  Copyright (C) 1996-1998 Russell King
  *
- *  Based on the work of:
- *      Russel King
  */
 
 /*
- * Acorn RiscPC mouse driver for Linux/ARM
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * This handles the Acorn RiscPCs mouse.  We basically have a couple of
+ * hardware registers that track the sensor count for the X-Y movement and
+ * another register holding the button state.  On every VSYNC interrupt we read
+ * the complete state and then work out if something has changed.
  */
 
-
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/ptrace.h>
@@ -41,14 +26,12 @@
 #include <asm/hardware.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/iomd.h>
+#include <asm/hardware/iomd.h>
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_AUTHOR("Vojtech Pavlik, Russell King");
 MODULE_DESCRIPTION("Acorn RiscPC mouse driver");
 MODULE_LICENSE("GPL");
 
-#define IOMD_MOUSEBTN	0x800C4000
-
 static short rpcmouse_lastx, rpcmouse_lasty;
 
 static struct input_dev rpcmouse_dev = {
@@ -57,7 +40,7 @@
 	relbit:		{ BIT(REL_X) | BIT(REL_Y) },
 	name:		"Acorn RiscPC Mouse",
 	phys:		"rpcmouse/input0",
-	idbus:		BUS_ISA,
+	idbus:		BUS_HOST,
 	idvendor:	0x0005,
 	idproduct:	0x0001,
 	idversion:	0x0100,
@@ -67,9 +50,9 @@
 {
 	short x, y, dx, dy, b;
 
-	x = (short) inl(IOMD_MOUSEX);
-	y = (short) inl(IOMD_MOUSEY);
-	b = (short) inl(IOMD_MOUSEBTN);
+	x = (short) iomd_readl(IOMD_MOUSEX);
+	y = (short) iomd_readl(IOMD_MOUSEY);
+	b = (short) (__raw_readl(0xe0310000) >> 4) & 7;
 
 	dx = x - rpcmouse_lastx;
 	dy = y - rpcmouse_lasty; 
@@ -80,15 +63,15 @@
 	input_report_rel(&rpcmouse_dev, REL_X, dx);
 	input_report_rel(&rpcmouse_dev, REL_Y, dy);
 
-	input_report_key(&amimouse_dev, BTN_LEFT,   buttons & 0x10);
-	input_report_key(&amimouse_dev, BTN_MIDDLE, buttons & 0x20);
-	input_report_key(&amimouse_dev, BTN_RIGHT,  buttons & 0x40);
+	input_report_key(&rpcmouse_dev, BTN_LEFT,   buttons & 0x10);
+	input_report_key(&rpcmouse_dev, BTN_MIDDLE, buttons & 0x20);
+	input_report_key(&rpcmouse_dev, BTN_RIGHT,  buttons & 0x40);
 }
 
 static int __init rpcmouse_init(void)
 {
-	rpcmouse_lastx = (short) inl(IOMD_MOUSEX);
-	rpcmouse_lasty = (short) inl(IOMD_MOUSEY);
+	rpcmouse_lastx = (short) iomd_readl(IOMD_MOUSEX);
+	rpcmouse_lasty = (short) iomd_readl(IOMD_MOUSEY);
 
 	if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", NULL)) {
 		printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n");
@@ -96,7 +79,7 @@
 	}
 
 	input_register_device(&rpcmouse_dev);
-	printk(KERN_INFO "input%d: Acorn RiscPC mouse irq %d", IRQ_VSYNCPULSE);
+	printk(KERN_INFO "input: Acorn RiscPC mouse irq %d", IRQ_VSYNCPULSE);
 
 	return 0;
 }
diff -Nru a/drivers/input/serio/Config.in b/drivers/input/serio/Config.in
--- a/drivers/input/serio/Config.in	Tue Jul 16 16:49:43 2002
+++ b/drivers/input/serio/Config.in	Tue Jul 16 16:49:43 2002
@@ -4,14 +4,15 @@
 
 tristate 'Serial i/o support' CONFIG_SERIO
 
-dep_tristate '  i8042 PC Keyboard controller' CONFIG_SERIO_I8042 $CONFIG_SERIO $CONFIG_ISA
+dep_tristate '  i8042 PC Keyboard controller' CONFIG_SERIO_I8042 $CONFIG_SERIO
 if [ "$CONFIG_SERIO_I8042" != "n" ]; then
    hex '    Register Base Address' CONFIG_I8042_REG_BASE 60
    int '    PS/2 Keyboard IRQ' CONFIG_I8042_KBD_IRQ 1
    int '    PS/2 AUX IRQ' CONFIG_I8042_AUX_IRQ 12
 fi
 dep_tristate '  Serial port line discipline' CONFIG_SERIO_SERPORT $CONFIG_SERIO 
-dep_tristate '  ct82c710 Aux port controller' CONFIG_SERIO_CT82C710 $CONFIG_SERIO $CONFIG_ISA
+dep_tristate '  ct82c710 Aux port controller' CONFIG_SERIO_CT82C710 $CONFIG_SERIO
+dep_tristate '  Q40 keyboard controller' CONFIG_SERIO_Q40KBD $CONFIG_SERIO
 dep_tristate '  Parallel port keyboard adapter' CONFIG_SERIO_PARKBD $CONFIG_SERIO $CONFIG_PARPORT
 
 if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
--- a/drivers/input/serio/Makefile	Tue Jul 16 16:49:41 2002
+++ b/drivers/input/serio/Makefile	Tue Jul 16 16:49:41 2002
@@ -14,6 +14,7 @@
 obj-$(CONFIG_SERIO_SERPORT)	+= serport.o
 obj-$(CONFIG_SERIO_CT82C710)	+= ct82c710.o
 obj-$(CONFIG_SERIO_RPCKBD)	+= rpckbd.o
+obj-$(CONFIG_SERIO_Q40KBD)	+= q40kbd.o
 
 # The global Rules.make.
 
diff -Nru a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
--- a/drivers/input/serio/ct82c710.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/input/serio/ct82c710.c	Tue Jul 16 16:49:41 2002
@@ -156,8 +156,7 @@
 
 static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
 {
-	if (ct82c710_port.dev)
-		ct82c710_port.dev->interrupt(&ct82c710_port, inb(ct82c710_data), 0);
+	serio_interrupt(&ct82c710_port, inb(ct82c710_data), 0);
 }
 
 /*
diff -Nru a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/i8042-io.h	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,75 @@
+#ifndef _I8042_IO_H
+#define _I8042_IO_H
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by 
+ * the Free Software Foundation.
+ */
+
+/*
+ * Names.
+ */
+
+#define I8042_KBD_PHYS_DESC "isa0060/serio0"
+#define I8042_AUX_PHYS_DESC "isa0060/serio1"
+
+/*
+ * IRQs.
+ */
+
+#define I8042_KBD_IRQ CONFIG_I8042_KBD_IRQ 
+#define I8042_AUX_IRQ CONFIG_I8042_AUX_IRQ
+
+/*
+ * Register numbers.
+ */
+
+#define I8042_COMMAND_REG	CONFIG_I8042_REG_BASE + 4	
+#define I8042_STATUS_REG	CONFIG_I8042_REG_BASE + 4	
+#define I8042_DATA_REG		CONFIG_I8042_REG_BASE	
+
+
+static inline int i8042_read_data(void)
+{
+	return inb(I8042_DATA_REG);
+}
+
+static inline int i8042_read_status(void)
+{
+	return inb(I8042_STATUS_REG);
+}
+
+static inline void i8042_write_data(int val)
+{
+	outb(val, I8042_DATA_REG);
+	return;
+}
+
+static inline void i8042_write_command(int val)
+{
+	outb(val, I8042_COMMAND_REG);
+	return;
+}
+
+static inline int i8042_platform_init(void)
+{
+/*
+ * On ix86 platforms touching the i8042 data register region can do really
+ * bad things. Because of this the region is always reserved on ix86 boxes.
+ */
+#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
+	if (!request_region(I8042_DATA_REG, 16, "i8042"))
+		return 0;
+#endif
+	return 1;
+}
+
+static inline void i8042_platform_exit(void)
+{
+#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
+	release_region(I8042_DATA_REG, 16);
+#endif
+}
+
+#endif /* _I8042_IO_H */
diff -Nru a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/i8042-ppcio.h	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,130 @@
+#ifndef _I8042_PPCIO_H
+#define _I8042_PPCIO_H
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#if defined(CONFIG_WALNUT)
+
+#define I8042_KBD_IRQ 25
+#define I8042_AUX_IRQ 26
+
+#define I8042_KBD_PHYS_DESC "walnutps2/serio0"
+#define I8042_AUX_PHYS_DESC "walnutps2/serio1"
+
+extern void *kb_cs;
+extern void *kb_data;
+
+static inline int i8042_read_data(void)
+{
+	return readb(kb_data);
+}
+
+static inline int i8042_read_status(void)
+{
+	return readb(kb_cs);
+}
+
+static inline void i8042_write_data(int val)
+{
+	writeb(val, kb_data);
+	return;
+}
+
+static inline void i8042_write_command(int val)
+{
+	writeb(val, kb_cs);
+	return;
+}
+
+static inline int i8042_platform_init(void)
+{
+	return 1;
+}
+
+static inline void i8042_platform_exit(void)
+{
+}
+
+#elif defined(CONFIG_SPRUCE)
+
+#define I8042_KBD_IRQ 22
+#define I8042_AUX_IRQ 21
+
+#define I8042_KBD_PHYS_DESC "spruceps2/serio0"
+#define I8042_AUX_PHYS_DESC "spruceps2/serio1"
+
+static inline int i8042_read_data(void)
+{
+	unsigned long kbd_data;
+
+	__raw_writel(0x00000088, 0xff500008);
+	eieio();
+
+	__raw_writel(0x03000000, 0xff50000c);
+	eieio();
+
+	asm volatile("lis     7,0xff88        \n\
+		      lswi    6,7,0x8         \n\
+		      mr      %0,6"
+	              : "=r" (kbd_data) :: "6", "7");
+
+	__raw_writel(0x00000000, 0xff50000c);
+	eieio();
+
+	return (unsigned char)(kbd_data >> 24);
+}
+
+static inline int i8042_read_status(void)
+{
+	unsigned long kbd_status;
+
+	__raw_writel(0x00000088, 0xff500008);
+	eieio();
+
+	__raw_writel(0x03000000, 0xff50000c);
+	eieio();
+
+	asm volatile("lis     7,0xff88        \n\
+		      ori     7,7,0x8         \n\
+		      lswi    6,7,0x8         \n\
+		      mr      %0,6"
+		      : "=r" (kbd_status) :: "6", "7");
+
+	__raw_writel(0x00000000, 0xff50000c);
+	eieio();
+
+	return (unsigned char)(kbd_status >> 24);
+}
+
+static inline void i8042_write_data(int val)
+{
+	*((unsigned char *)0xff810000) = (char)val;
+	return;
+}
+
+static inline void i8042_write_command(int val)
+{
+	*((unsigned char *)0xff810001) = (char)val;
+	return;
+}
+
+static inline int i8042_platform_init(void)
+{
+	return 1;
+}
+
+static inline void i8042_platform_exit(void)
+{
+}
+
+#else
+
+#include "i8042-io.h"
+
+#endif
+
+#endif /* _I8042_PPCIO_H */
diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
--- a/drivers/input/serio/i8042.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/input/serio/i8042.c	Tue Jul 16 16:49:41 2002
@@ -1,31 +1,13 @@
 /*
- * $Id: i8042.c,v 1.21 2002/03/01 22:09:27 jsimmons Exp $
- *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- */
-
-/*
  *  i8042 keyboard and mouse controller driver for Linux
+ *
+ *  Copyright (c) 1999-2002 Vojtech Pavlik
  */
 
 /*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
 #include <asm/io.h>
@@ -70,6 +52,7 @@
 static struct serio i8042_aux_port;
 static unsigned char i8042_initial_ctr;
 static unsigned char i8042_ctr;
+struct timer_list i8042_timer;
 
 #ifdef I8042_DEBUG_IO
 static unsigned long i8042_start;
@@ -97,7 +80,7 @@
 static int i8042_wait_read(void)
 {
 	int i = 0;
-	while ((~inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
+	while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
 		udelay(50);
 		i++;
 	}
@@ -107,7 +90,7 @@
 static int i8042_wait_write(void)
 {
 	int i = 0;
-	while ((inb(I8042_STATUS_REG) & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
+	while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
 		udelay(50);
 		i++;
 	}
@@ -126,12 +109,12 @@
 
 	spin_lock_irqsave(&i8042_lock, flags);
 
-	while ((inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE))
+	while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE))
 #ifdef I8042_DEBUG_IO
 		printk(KERN_DEBUG "i8042.c: %02x <- i8042 (flush) [%d]\n",
-			inb(I8042_DATA_REG), (int) (jiffies - i8042_start));
+			i8042_read_data(), (int) (jiffies - i8042_start));
 #else
-		inb(I8042_DATA_REG);
+		i8042_read_data();
 #endif
 
 	spin_unlock_irqrestore(&i8042_lock, flags);
@@ -160,7 +143,7 @@
 		printk(KERN_DEBUG "i8042.c: %02x -> i8042 (command) [%d]\n",
 			command & 0xff, (int) (jiffies - i8042_start));
 #endif
-		outb(command & 0xff, I8042_COMMAND_REG);
+		i8042_write_command(command & 0xff);
 	}
 	
 	if (!retval)
@@ -170,16 +153,16 @@
 			printk(KERN_DEBUG "i8042.c: %02x -> i8042 (parameter) [%d]\n",
 				param[i], (int) (jiffies - i8042_start));
 #endif
-			outb(param[i], I8042_DATA_REG);
+			i8042_write_data(param[i]);
 		}
 
 	if (!retval)
 		for (i = 0; i < ((command >> 8) & 0xf); i++) {
 			if ((retval = i8042_wait_read())) break;
-			if (inb(I8042_STATUS_REG) & I8042_STR_AUXDATA) 
-				param[i] = ~inb(I8042_DATA_REG);
+			if (i8042_read_status() & I8042_STR_AUXDATA) 
+				param[i] = ~i8042_read_data();
 			else
-				param[i] = inb(I8042_DATA_REG);
+				param[i] = i8042_read_data();
 #ifdef I8042_DEBUG_IO
 			printk(KERN_DEBUG "i8042.c: %02x <- i8042 (return) [%d]\n",
 				param[i], (int) (jiffies - i8042_start));
@@ -216,7 +199,7 @@
 		printk(KERN_DEBUG "i8042.c: %02x -> i8042 (kbd-data) [%d]\n",
 			c, (int) (jiffies - i8042_start));
 #endif
-		outb(c, I8042_DATA_REG);
+		i8042_write_data(c);
 	}
 
 	spin_unlock_irqrestore(&i8042_lock, flags);
@@ -243,7 +226,7 @@
  * mode tend to trash their CTR when doing the AUX_SEND command.
  */
 
-	retval += i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR);
+	retval |= i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR);
 
 /*
  * Make sure the interrupt happens and the character is received even
@@ -251,7 +234,7 @@
  * characters later.
  */
 
-	i8042_interrupt(0, port, NULL);
+	i8042_interrupt(0, NULL, NULL);
 	return retval;
 }
 
@@ -269,28 +252,23 @@
  */
 
 	if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) {
-		printk(KERN_ERR "i8042.c: Can't get irq %d for %s\n", values->irq, values->name);
+		printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", values->irq, values->name);
+		values->exists = 0;
+		serio_unregister_port(port);
 		return -1;
 	}
 
 /*
- * Enable the device and its interrupt.
+ * Enable the interrupt.
  */
 
 	i8042_ctr |= values->irqen;
-	i8042_ctr &= ~values->disable;
 
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
 		printk(KERN_ERR "i8042.c: Can't write CTR while opening %s.\n", values->name);
 		return -1;
 	}
 
-/*
- * Flush buffers
- */
-
-	i8042_flush();
-
 	return 0;
 }
 
@@ -304,11 +282,10 @@
 	struct i8042_values *values = port->driver;
 
 /*
- * Disable the device and its interrupt.
+ * Disable the interrupt.
  */
 
 	i8042_ctr &= ~values->irqen;
-	i8042_ctr |= values->disable;
 
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
 		printk(KERN_ERR "i8042.c: Can't write CTR while closing %s.\n", values->name);
@@ -342,7 +319,7 @@
 	close:		i8042_close,
 	driver:		&i8042_kbd_values,
 	name:		"i8042 Kbd Port",
-	phys:		"isa0060/serio0",
+	phys:		I8042_KBD_PHYS_DESC,
 };
 
 static struct i8042_values i8042_aux_values = {
@@ -361,7 +338,7 @@
 	close:		i8042_close,
 	driver:		&i8042_aux_values,
 	name:		"i8042 Aux Port",
-	phys:		"isa0060/serio1",
+	phys:		I8042_AUX_PHYS_DESC,
 };
 
 /*
@@ -374,27 +351,29 @@
 {
 	unsigned long flags;
 	unsigned char str, data;
+	unsigned int dfl;
 
 	spin_lock_irqsave(&i8042_lock, flags);
 
-	while ((str = inb(I8042_STATUS_REG)) & I8042_STR_OBF) {
+	while ((str = i8042_read_status()) & I8042_STR_OBF) {
 
-		data = inb(I8042_DATA_REG);
+		data = i8042_read_data();
+		dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
+		      ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
 
 #ifdef I8042_DEBUG_IO
-		printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt-%s) [%d]\n",
-			data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", (int) (jiffies - i8042_start));
+		printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt-%s, %d) [%d]\n",
+			data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, (int) (jiffies - i8042_start));
 #endif
 
 		if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) {
-			if (i8042_aux_port.dev)
-				i8042_aux_port.dev->interrupt(&i8042_aux_port, data, 0);
+			serio_interrupt(&i8042_aux_port, data, dfl);
 		} else {
-			if (i8042_kbd_values.exists && i8042_kbd_port.dev) {
+			if (i8042_kbd_values.exists) {
 				if (!i8042_direct) {
 					if (data > 0x7f) {
 						if (test_and_clear_bit(data & 0x7f, i8042_unxlate_seen)) {
-							i8042_kbd_port.dev->interrupt(&i8042_kbd_port, 0xf0, 0);	
+							serio_interrupt(&i8042_kbd_port, 0xf0, dfl);
 							data = i8042_unxlate_table[data & 0x7f];
 						}
 					} else {
@@ -402,7 +381,7 @@
 						data = i8042_unxlate_table[data];
 					}
 				}
-				i8042_kbd_port.dev->interrupt(&i8042_kbd_port, data, 0);
+				serio_interrupt(&i8042_kbd_port, data, dfl);
 			}
 		}
 	}
@@ -477,7 +456,7 @@
  * Handle keylock.
  */
 
-	if (~inb(I8042_STATUS_REG) & I8042_STR_KEYLOCK) {
+	if (~i8042_read_status() & I8042_STR_KEYLOCK) {
 
 		if (i8042_unlock) {
 			i8042_ctr |= I8042_CTR_IGNKEYLOCK;
@@ -525,6 +504,8 @@
 void i8042_controller_cleanup(void)
 {
 
+	i8042_flush();
+
 /*
  * Reset the controller.
  */
@@ -566,6 +547,19 @@
 {
 	unsigned char param;
 
+/*
+ * Check if AUX irq is available. If it isn't, then there is no point
+ * in trying to detect AUX presence.
+ */
+
+	if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL))
+                return -1;
+	free_irq(values->irq, NULL);
+
+/*
+ * Get rid of bytes in the queue.
+ */
+
 	i8042_flush();
 
 /*
@@ -638,6 +632,32 @@
 	return 0;
 }
 
+static void i8042_timer_func(unsigned long data)
+{
+	i8042_interrupt(0, NULL, NULL);
+	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
+}
+
+static void __init i8042_start_polling(void)
+{
+	i8042_ctr &= ~I8042_CTR_KBDDIS;
+	if (i8042_aux_values.exists)
+		i8042_ctr &= ~I8042_CTR_AUXDIS;
+
+	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+		printk(KERN_WARNING "i8042.c: Can't write CTR while starting polling.\n");
+		return; 
+	}
+
+	i8042_timer.function = i8042_timer_func;
+	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
+}
+
+static void __exit i8042_stop_polling(void)
+{
+	del_timer(&i8042_timer);
+}
+	
 /*
  * Module init and cleanup functions.
  */
@@ -678,6 +698,9 @@
 	i8042_start = jiffies;
 #endif
 
+	if (!i8042_platform_init())
+		return -EBUSY;
+
 	if (i8042_controller_init())
 		return -ENODEV;
 
@@ -686,20 +709,18 @@
 	if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values, &i8042_aux_port))
 		i8042_port_register(&i8042_aux_values, &i8042_aux_port);
 
-/* 
- * On ix86 platforms touching the i8042 data register region can do really
- * bad things. Because of this the region is always reserved on ix86 boxes.  
- */
-#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
-	request_region(I8042_DATA_REG, 16, "i8042");
-#endif
+	i8042_start_polling();
+
 	register_reboot_notifier(&i8042_notifier);
+
 	return 0;
 }
 
 void __exit i8042_exit(void)
 {
 	unregister_reboot_notifier(&i8042_notifier);
+
+	i8042_stop_polling();
 	
 	if (i8042_kbd_values.exists)
 		serio_unregister_port(&i8042_kbd_port);
@@ -708,9 +729,8 @@
 		serio_unregister_port(&i8042_aux_port);
 
 	i8042_controller_cleanup();
-#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
-	release_region(I8042_DATA_REG, 16);
-#endif
+
+	i8042_platform_exit();
 }
 
 module_init(i8042_init);
diff -Nru a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
--- a/drivers/input/serio/i8042.h	Tue Jul 16 16:49:43 2002
+++ b/drivers/input/serio/i8042.h	Tue Jul 16 16:49:43 2002
@@ -2,36 +2,22 @@
 #define _I8042_H
 
 /*
- * $Id: i8042.h,v 1.6 2001/10/05 22:48:09 vojtech Exp $
+ *  Copyright (c) 1999-2002 Vojtech Pavlik
  *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
 /*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * Arch-dependent inline functions and defines.
  */
 
-/*
- * If you want to reset your i8042 upon boot, define this.
- */
-
-#undef I8042_RESET
+#if defined(CONFIG_PPC)
+#include "i8042-ppcio.h"
+#else
+#include "i8042-io.h"
+#endif
 
 /*
  * If you want to trace all the i/o the i8042 module does for
@@ -41,20 +27,6 @@
 #undef I8042_DEBUG_IO
 
 /*
- * On most PC based systems the keyboard IRQ is 1.
- */
-
-#define I8042_KBD_IRQ CONFIG_I8042_KBD_IRQ 
-
-/*
- * On most PC based systems the aux port IRQ is 12. There are exceptions,
- * though. Unfortunately IRQ probing is not possible without touching
- * the device attached to the port.
- */
-
-#define I8042_AUX_IRQ CONFIG_I8042_AUX_IRQ
-
-/*
  * This is in 50us units, the time we wait for the i8042 to react. This
  * has to be long enough for the i8042 itself to timeout on sending a byte
  * to a non-existent mouse.
@@ -63,12 +35,13 @@
 #define I8042_CTL_TIMEOUT	10000
 
 /*
- * Register numbers.
+ * When the device isn't opened and it's interrupts aren't used, we poll it at
+ * regular intervals to see if any characters arrived. If yes, we can start
+ * probing for any mouse / keyboard connected. This is the period of the
+ * polling.
  */
 
-#define I8042_COMMAND_REG	CONFIG_I8042_REG_BASE + 4	
-#define I8042_STATUS_REG	CONFIG_I8042_REG_BASE + 4	
-#define I8042_DATA_REG		CONFIG_I8042_REG_BASE	
+#define I8042_POLL_PERIOD	HZ/20
 
 /*
  * Status register bits.
diff -Nru a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
--- a/drivers/input/serio/parkbd.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/input/serio/parkbd.c	Tue Jul 16 16:49:41 2002
@@ -135,10 +135,8 @@
 
 		parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++;
 
-		if (parkbd_counter == parkbd_mode + 10) {
-			if (parkbd_port.dev)
-				parkbd_port.dev->interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0);
-		}
+		if (parkbd_counter == parkbd_mode + 10)
+			serio_interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0);
 	}
 
 	parkbd_last = jiffies;
diff -Nru a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/q40kbd.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,99 @@
+/*
+ * $Id: q40kbd.c,v 1.12 2002/02/02 22:26:44 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Richard Zidlicky <Richard.Zidlicky@stud.informatik.uni-erlangen.de>	
+ */
+
+/*
+ * Q40 PS/2 keyboard controller driver for Linux/m68k
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+
+#include <asm/keyboard.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/q40_master.h>
+#include <asm/irq.h>
+#include <asm/q40ints.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
+MODULE_LICENSE("GPL");
+
+static struct serio q40kbd_port =
+{
+	type:   SERIO_8042,
+	write:  NULL,
+	name:	"Q40 PS/2 kbd port",
+	phys:	"isa0060/serio0",
+};
+
+static void q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+
+	if (IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))
+		if (q40kbd_port.dev)
+                         q40kbd_port.dev->interrupt(&q40kbd_port, master_inb(KEYCODE_REG), 0);
+
+	master_outb(-1, KEYBOARD_UNLOCK_REG);
+}
+
+void __init q40kbd_init(void)
+{
+	int maxread = 100;
+
+	/* Get the keyboard controller registers (incomplete decode) */
+	request_region(0x60, 16, "q40kbd");
+
+	/* allocate the IRQ */
+	request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL);
+
+	/* flush any pending input. */
+	while (maxread-- && (IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)))
+		master_inb(KEYCODE_REG);
+	
+	/* off we go */
+	master_outb(-1,KEYBOARD_UNLOCK_REG);
+	master_outb(1,KEY_IRQ_ENABLE_REG);
+
+	register_serio_port(&q40kbd_port);
+	printk(KERN_INFO "serio: Q40 PS/2 kbd port irq %d\n", Q40_IRQ_KEYBOARD);
+}
+
+void __exit q40kbd_exit(void)
+{
+	unregister_serio_port(&q40kbd_port);
+	free_irq(Q40_IRQ_KEYBOARD, NULL);
+	release_region(0x60, 16);	
+}
+
+module_init(q40kbd_init);
+module_exit(q40kbd_exit);
diff -Nru a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
--- a/drivers/input/serio/rpckbd.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/input/serio/rpckbd.c	Tue Jul 16 16:49:41 2002
@@ -64,8 +64,7 @@
 	kbd_pt_regs = regs;
 
 	while (inb(IOMD_KCTRL) & (1 << 5))
-		if (rpckbd_port.dev)
-               		 rpckbd_port.dev->interrupt(&rpckbd_port, inb(IOMD_KARTRX), 0);
+		serio_interrupt(&rpckbd_port, inb(IOMD_KARTRX), 0);
 
 }
 
diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/input/serio/serio.c	Tue Jul 16 16:49:41 2002
@@ -32,6 +32,11 @@
 #include <linux/module.h>
 #include <linux/serio.h>
 #include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/suspend.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Serio abstraction core");
@@ -47,6 +52,7 @@
 
 static struct serio *serio_list;
 static struct serio_dev *serio_dev;
+static int serio_pid;
 
 static void serio_find_dev(struct serio *serio)
 {
@@ -59,11 +65,58 @@
         }
 }
 
+#define SERIO_RESCAN	1
+
+static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
+static DECLARE_COMPLETION(serio_exited);
+
+void serio_handle_events(void)
+{
+	struct serio *serio = serio_list;
+
+	while (serio) {
+		if (serio->event & SERIO_RESCAN) {
+			if (serio->dev && serio->dev->disconnect)
+				serio->dev->disconnect(serio);
+			serio_find_dev(serio);
+		}
+
+		serio->event = 0;
+		serio = serio->next;
+	}
+}
+
+static int serio_thread(void *nothing)
+{
+	lock_kernel();
+	daemonize();
+	strcpy(current->comm, "kseriod");
+
+	do {
+		serio_handle_events();
+		if (current->flags & PF_FREEZE)
+			refrigerator(PF_IOTHREAD);
+		interruptible_sleep_on(&serio_wait); 
+	} while (!signal_pending(current));
+
+	printk(KERN_DEBUG "serio: kseriod exiting");
+
+	unlock_kernel();
+	complete_and_exit(&serio_exited, 0);
+}
+
 void serio_rescan(struct serio *serio)
 {
-	if (serio->dev && serio->dev->disconnect)
-		serio->dev->disconnect(serio);
-	serio_find_dev(serio);
+	serio->event |= SERIO_RESCAN;
+	wake_up(&serio_wait);
+}
+
+void serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{       
+        if (serio->dev && serio->dev->interrupt) 
+                serio->dev->interrupt(serio, data, flags);
+	else
+		serio_rescan(serio);
 }
 
 void serio_register_port(struct serio *serio)
@@ -127,3 +180,29 @@
 	serio->close(serio);
 	serio->dev = NULL;
 }
+
+int serio_init(void)
+{
+	int pid;
+
+	pid = kernel_thread(serio_thread, NULL,
+		CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+
+	if (!pid) {
+		printk(KERN_WARNING "serio: Failed to start kseriod\n");
+		return -1;
+	}
+
+	serio_pid = pid;
+
+	return 0;
+}
+
+void serio_exit(void)
+{
+	kill_proc(serio_pid, SIGTERM, 1);
+	wait_for_completion(&serio_exited);
+}
+
+module_init(serio_init);
+module_exit(serio_exit);
diff -Nru a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
--- a/drivers/input/serio/serport.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/input/serio/serport.c	Tue Jul 16 16:49:42 2002
@@ -138,8 +138,7 @@
 	struct serport *serport = (struct serport*) tty->disc_data;
 	int i;
 	for (i = 0; i < count; i++)
-		if (serport->serio.dev)
-			serport->serio.dev->interrupt(&serport->serio, cp[i], 0);
+		serio_interrupt(&serport->serio, cp[i], 0);
 }
 
 /*
diff -Nru a/drivers/input/touchscreen/Config.help b/drivers/input/touchscreen/Config.help
--- a/drivers/input/touchscreen/Config.help	Tue Jul 16 16:49:42 2002
+++ b/drivers/input/touchscreen/Config.help	Tue Jul 16 16:49:42 2002
@@ -14,3 +14,13 @@
   inserted in and removed from the running kernel whenever you want).
   The module will be called gunze.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_TOUCHSCREEN_BITSY
+  Say Y here if you have the h3600 (Bitsy) touchscreen.
+
+  If unsure, say N.
+
+  This driver 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 gunze.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
diff -Nru a/drivers/input/touchscreen/Config.in b/drivers/input/touchscreen/Config.in
--- a/drivers/input/touchscreen/Config.in	Tue Jul 16 16:49:43 2002
+++ b/drivers/input/touchscreen/Config.in	Tue Jul 16 16:49:43 2002
@@ -4,4 +4,7 @@
 
 bool 'Touchscreens' CONFIG_INPUT_TOUCHSCREEN
 
+if [ "$CONFIG_SA1100_BITSY" = "y" ]; then
+   dep_tristate '  Compaq iPAQ H3600 (Bitsy) touchscreen input driver' CONFIG_TOUCHSCREEN_BITSY $CONFIG_INPUT $CONFIG_INPUT_TOUCHSCREEN $CONFIG_SERIO
+fi
 dep_tristate '  Gunze AHL-51S touchscreen' CONFIG_TOUCHSCREEN_GUNZE $CONFIG_INPUT $CONFIG_INPUT_TOUCHSCREEN $CONFIG_SERIO
diff -Nru a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
--- a/drivers/input/touchscreen/Makefile	Tue Jul 16 16:49:42 2002
+++ b/drivers/input/touchscreen/Makefile	Tue Jul 16 16:49:42 2002
@@ -4,6 +4,7 @@
 
 # Each configuration option enables a list of files.
 
+obj-$(CONFIG_TOUCHSCREEN_BITSY)	+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)	+= gunze.o
 
 # The global Rules.make.
diff -Nru a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/touchscreen/h3600_ts_input.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,485 @@
+/*
+ * $Id: h3600_ts_input.c,v 1.4 2002/01/23 06:39:37 jsimmons Exp $
+ *
+ *  Copyright (c) 2001 "Crazy" James Simmons jsimmons@transvirtual.com 
+ *
+ *  Sponsored by Transvirtual Technology. 
+ * 
+ *  Derived from the code in h3600_ts.[ch] by Charles Flynn  
+ */
+
+/*
+ * Driver for the h3600 Touch Screen and other Atmel controlled devices.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <jsimmons@transvirtual.com>.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+
+/* SA1100 serial defines */
+#include <asm/arch/hardware.h>
+#include <asm/arch/irqs.h>
+
+/*
+ * Definitions & global arrays.
+ */
+
+/* The start and end of frame characters SOF and EOF */
+#define CHAR_SOF                0x02
+#define CHAR_EOF                0x03
+#define FRAME_OVERHEAD          3       /* CHAR_SOF,CHAR_EOF,LENGTH = 3 */
+
+/*
+        Atmel events and response IDs contained in frame.
+        Programmer has no control over these numbers.
+        TODO there are holes - specifically  1,7,0x0a
+*/
+#define VERSION_ID              0       /* Get Version (request/respose) */
+#define KEYBD_ID                2       /* Keyboard (event) */
+#define TOUCHS_ID               3       /* Touch Screen (event)*/
+#define EEPROM_READ_ID          4       /* (request/response) */
+#define EEPROM_WRITE_ID         5       /* (request/response) */
+#define THERMAL_ID              6       /* (request/response) */
+#define NOTIFY_LED_ID           8       /* (request/response) */
+#define BATTERY_ID              9       /* (request/response) */
+#define SPI_READ_ID             0x0b    /* ( request/response) */
+#define SPI_WRITE_ID            0x0c    /* ( request/response) */
+#define FLITE_ID                0x0d    /* backlight ( request/response) */
+#define STX_ID                  0xa1    /* extension pack status (req/resp) */
+
+#define MAX_ID                  14
+
+#define H3600_MAX_LENGTH 16
+#define H3600_KEY 0xf 
+
+#define H3600_SCANCODE_RECORD	1	 /* 1 -> record button */
+#define H3600_SCANCODE_CALENDAR 2	 /* 2 -> calendar */
+#define H3600_SCANCODE_CONTACTS 3	 /* 3 -> contact */
+#define H3600_SCANCODE_Q	4	 /* 4 -> Q button */
+#define	H3600_SCANCODE_START	5	 /* 5 -> start menu */
+#define	H3600_SCANCODE_UP	6	 /* 6 -> up */
+#define H3600_SCANCODE_RIGHT	7 	 /* 7 -> right */
+#define H3600_SCANCODE_LEFT 	8	 /* 8 -> left */
+#define H3600_SCANCODE_DOWN 	9	 /* 9 -> down */
+
+static char *h3600_name = "H3600 TouchScreen";
+
+/*
+ * Per-touchscreen data.
+ */
+struct h3600_dev {
+	struct input_dev dev;
+	struct serio *serio;
+	unsigned char event;	/* event ID from packet */
+	unsigned char chksum;
+	unsigned char len;
+	unsigned char idx;
+	unsigned char buf[H3600_MAX_LENGTH];
+	char phys[32];
+};
+
+static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+        int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
+	struct input_dev *dev = (struct input_dev *) dev_id;
+
+	input_report_key(dev, KEY_ENTER, down);
+}
+
+static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+        int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
+	struct input_dev *dev = (struct input_dev *) dev_id;
+
+	/* 
+	 * This interrupt is only called when we release the key. So we have 
+	 * to fake a key press.
+	 */ 	
+	input_report_key(dev, KEY_SUSPEND, 1);
+	input_report_key(dev, KEY_SUSPEND, down); 	
+}
+
+#ifdef CONFIG_PM
+
+static int flite_brightness = 25;
+
+enum flite_pwr {
+        FLITE_PWR_OFF = 0,
+        FLITE_PWR_ON = 1
+};
+
+/*
+ * h3600_flite_power: enables or disables power to frontlight, using last bright */
+unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
+{
+	unsigned char brightness = ((pwr==FLITE_PWR_OFF) ? 0:flite_brightness);
+	struct h3600_dev *ts = dev->private;
+
+	/* Must be in this order */	
+       	ts->serio->write(ts->serio, 1);
+	ts->serio->write(ts->serio, pwr);
+      	ts->serio->write(ts->serio, brightness); 
+	return 0;
+}
+
+static int suspended = 0;
+static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req, 
+				void *data)
+{
+	struct input_dev *dev = (struct input_dev *) data;	
+
+        switch (req) {
+        case PM_SUSPEND: /* enter D1-D3 */
+                suspended = 1;
+                h3600_flite_power(dev, FLITE_PWR_OFF);
+                break;
+        case PM_BLANK:
+                if (!suspended)
+                        h3600_flite_power(dev, FLITE_PWR_OFF);
+                break;
+        case PM_RESUME:  /* enter D0 */
+                /* same as unblank */
+        case PM_UNBLANK:
+                if (suspended) {
+                        //initSerial();
+                        suspended = 0;
+                }
+                h3600_flite_power(dev, FLITE_PWR_ON);
+                break;
+        }
+        return 0;
+}
+#endif
+
+/*
+ * This function translates the native event packets to linux input event
+ * packets. Some packets coming from serial are not touchscreen related. In
+ * this case we send them off to be processed elsewhere. 
+ */
+static void h3600ts_process_packet(struct h3600_dev *ts)
+{
+        struct input_dev *dev = &ts->dev;
+	static int touched = 0;
+	int key, down = 0;
+
+        switch (ts->event) {
+                /*
+                   Buttons - returned as a single byte
+                        7 6 5 4 3 2 1 0
+                        S x x x N N N N
+
+                   S       switch state ( 0=pressed 1=released)
+                   x       Unused.
+                   NNNN    switch number 0-15
+
+                Note: This is true for non interrupt generated key events.
+                */
+                case KEYBD_ID:
+			down = (ts->buf[0] & 0x80) ? 0 : 1; 
+
+			switch (ts->buf[0] & 0x7f) {
+				case H3600_SCANCODE_RECORD:
+					key = KEY_RECORD;
+					break;
+				case H3600_SCANCODE_CALENDAR:
+					key = KEY_PROG1;
+                                        break;
+				case H3600_SCANCODE_CONTACTS:
+					key = KEY_PROG2;
+                                        break;
+				case H3600_SCANCODE_Q:        
+					key = KEY_Q;
+                                        break;
+				case H3600_SCANCODE_START:
+					key = KEY_PROG3;
+                                        break;
+				case H3600_SCANCODE_UP:
+					key = KEY_UP;
+                                        break;
+				case H3600_SCANCODE_RIGHT:
+					key = KEY_RIGHT;
+                                        break;
+				case H3600_SCANCODE_LEFT:
+					key = KEY_LEFT;
+                                        break;
+				case H3600_SCANCODE_DOWN:
+					key = KEY_DOWN;
+                                        break;
+				default:
+					key = 0;	
+			}	
+                        if (key) 
+                        	input_report_key(dev, key, down);
+                        break;
+                /*
+                 * Native touchscreen event data is formatted as shown below:-
+                 *
+                 *      +-------+-------+-------+-------+
+                 *      | Xmsb  | Xlsb  | Ymsb  | Ylsb  |
+                 *      +-------+-------+-------+-------+
+                 *       byte 0    1       2       3
+                 */
+                case TOUCHS_ID:
+			if (!touched) { 
+				input_report_key(dev, BTN_TOUCH, 1);
+				touched = 1;
+			}			
+
+			if (ts->len) {
+				unsigned short x, y;				
+
+				x = ts->buf[0]; x <<= 8; x += ts->buf[1];
+                                y = ts->buf[2]; y <<= 8; y += ts->buf[3];
+
+                       		input_report_abs(dev, ABS_X, x);
+                       		input_report_abs(dev, ABS_Y, y);
+			} else {
+		               	input_report_key(dev, BTN_TOUCH, 0);
+				touched = 0;
+			}	
+                        break;
+		default:
+			/* Send a non input event elsewhere */
+			break;
+        }
+}
+
+/*
+ * h3600ts_event() handles events from the input module.
+ */
+static int h3600ts_event(struct input_dev *dev, unsigned int type, 
+		 	 unsigned int code, int value)
+{
+	struct h3600_dev *ts = dev->private;
+
+	switch (type) {
+		case EV_LED: {
+		//	ts->serio->write(ts->serio, SOME_CMD);
+			return 0;
+		}
+	}					
+	return -1;
+}
+
+/*
+        Frame format
+  byte    1       2               3              len + 4
+        +-------+---------------+---------------+--=------------+
+        |SOF    |id     |len    | len bytes     | Chksum        |
+        +-------+---------------+---------------+--=------------+
+  bit   0     7  8    11 12   15 16
+
+        +-------+---------------+-------+
+        |SOF    |id     |0      |Chksum | - Note Chksum does not include SOF
+        +-------+---------------+-------+
+  bit   0     7  8    11 12   15 16
+
+*/
+
+static int state;
+
+/* decode States  */
+#define STATE_SOF       0       /* start of FRAME */
+#define STATE_ID        1       /* state where we decode the ID & len */
+#define STATE_DATA      2       /* state where we decode data */
+#define STATE_EOF       3       /* state where we decode checksum or EOF */
+
+static void h3600ts_interrupt(struct serio *serio, unsigned char data,
+                              unsigned int flags)
+{
+        struct h3600_dev *ts = serio->private;
+
+	/*
+         * We have a new frame coming in. 
+         */
+	switch (state) {
+		case STATE_SOF:
+        		if (data == CHAR_SOF)
+                		state = STATE_ID;	
+			return;
+        	case STATE_ID:
+			ts->event = (data & 0xf0) >> 4;
+			ts->len = (data & 0xf);
+			ts->idx = 0;
+			if (ts->event >= MAX_ID) {
+				state = STATE_SOF;
+                        	break;
+			}
+			ts->chksum = data;
+                	state=(ts->len > 0 ) ? STATE_DATA : STATE_EOF;
+			break;
+		case STATE_DATA:
+			ts->chksum += data;
+			ts->buf[ts->idx]= data;
+			if(++ts->idx == ts->len) 
+                        	state = STATE_EOF;
+			break;
+		case STATE_EOF:
+                	state = STATE_SOF;
+                	if (data == CHAR_EOF || data == ts->chksum )
+				h3600ts_process_packet(ts);
+                	break;
+        	default:
+                	printk("Error3\n");
+                	break;
+	}
+}
+
+/*
+ * h3600ts_connect() is the routine that is called when someone adds a
+ * new serio device. It looks whether it was registered as a H3600 touchscreen
+ * and if yes, registers it as an input device.
+ */
+static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct h3600_dev *ts;
+
+	if (serio->type != (SERIO_RS232 | SERIO_H3600))
+		return;
+
+	if (!(ts = kmalloc(sizeof(struct h3600_dev), GFP_KERNEL)))
+		return;
+
+	memset(ts, 0, sizeof(struct h3600_dev));
+
+	/* Device specific stuff */
+        set_GPIO_IRQ_edge( GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES );
+        set_GPIO_IRQ_edge( GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE );
+
+        if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
+			SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,	
+			"h3600_action", &ts->dev)) {
+		printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
+		kfree(ts);
+		return;
+	}
+
+        if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
+			SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, 
+			"h3600_suspend", &ts->dev)) {
+		free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
+		printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
+		kfree(ts);
+		return;
+	}
+	/* Now we have things going we setup our input device */
+	ts->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR);
+	ts->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+	ts->dev.ledbit[0] = BIT(LED_SLEEP); 
+
+	ts->dev.absmin[ABS_X] = 60;   ts->dev.absmin[ABS_Y] = 35;
+	ts->dev.absmax[ABS_X] = 985; ts->dev.absmax[ABS_Y] = 1024;
+	ts->dev.absfuzz[ABS_X] = 0; ts->dev.absfuzz[ABS_Y] = 0;
+
+	ts->serio = serio;
+	serio->private = ts;
+
+	set_bit(KEY_RECORD, ts->dev.keybit);
+	set_bit(KEY_Q, ts->dev.keybit);
+	set_bit(KEY_PROG1, ts->dev.keybit);
+	set_bit(KEY_PROG2, ts->dev.keybit);
+	set_bit(KEY_PROG3, ts->dev.keybit);
+	set_bit(KEY_UP, ts->dev.keybit);
+	set_bit(KEY_RIGHT, ts->dev.keybit);
+	set_bit(KEY_LEFT, ts->dev.keybit);
+	set_bit(KEY_DOWN, ts->dev.keybit);
+	set_bit(KEY_ENTER, ts->dev.keybit);
+	ts->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+	ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND);
+
+	sprintf(ts->phys, "%s/input0", serio->phys);
+
+       	ts->dev.event = h3600ts_event;
+	ts->dev.private = ts;
+	ts->dev.name = h3600_name;
+	ts->dev.phys = ts->phys;
+	ts->dev.idbus = BUS_RS232;
+	ts->dev.idvendor = SERIO_H3600;
+	ts->dev.idproduct = 0x0666;  /* FIXME !!! We can ask the hardware */
+	ts->dev.idversion = 0x0100;
+
+	if (serio_open(serio, dev)) {
+        	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
+        	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
+		kfree(ts);
+		return;
+	}
+
+	//h3600_flite_control(1, 25);     /* default brightness */
+#ifdef CONFIG_PM
+	ts->dev.pm_dev = pm_register(PM_ILLUMINATION_DEV, PM_SYS_LIGHT, 
+					h3600ts_pm_callback);
+	printk("registered pm callback\n");
+#endif
+	input_register_device(&ts->dev);
+
+	printk(KERN_INFO "input: %s on %s\n", h3600_name, serio->phys);
+}
+
+/*
+ * h3600ts_disconnect() is the opposite of h3600ts_connect()
+ */
+
+static void h3600ts_disconnect(struct serio *serio)
+{
+	struct h3600_dev *ts = serio->private;
+	
+        free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
+        free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev);
+	input_unregister_device(&ts->dev);
+	serio_close(serio);
+	kfree(ts);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev h3600ts_dev = {
+	interrupt:	h3600ts_interrupt,
+	connect:	h3600ts_connect,
+	disconnect:	h3600ts_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init h3600ts_init(void)
+{
+	serio_register_device(&h3600ts_dev);
+	return 0;
+}
+
+static void __exit h3600ts_exit(void)
+{
+	serio_unregister_device(&h3600ts_dev);
+}
+
+module_init(h3600ts_init);
+module_exit(h3600ts_exit);
diff -Nru a/drivers/input/uinput.c b/drivers/input/uinput.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/uinput.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,395 @@
+/*
+ *  User level driver support for input subsystem
+ *
+ * Heavily based on evdev.c by Vojtech Pavlik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
+ * 
+ * Changes/Revisions:
+ *	0.1	20/06/2002
+ *		- first public version
+ */
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/smp_lock.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uinput.h>
+
+static int uinput_dev_open(struct input_dev *dev)
+{
+	return 0;
+}
+
+static void uinput_dev_close(struct input_dev *dev)
+{
+
+}
+
+static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct uinput_device	*udev;
+
+	udev = (struct uinput_device *)dev->private;
+
+	udev->head = (udev->head + 1) & 0xF;
+	udev->buff[udev->head].type = type;
+	udev->buff[udev->head].code = code;
+	udev->buff[udev->head].value = value;
+	do_gettimeofday(&udev->buff[udev->head].time);
+
+	wake_up_interruptible(&udev->waitq);
+
+	return 0;
+}
+
+static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
+{
+	return 0;
+}
+
+static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
+{
+	return 0;
+}					
+
+static int uinput_create_device(struct uinput_device *udev)
+{
+	if (!udev->dev->name) {
+		printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
+		return -EINVAL;
+	}
+
+	udev->dev->open = uinput_dev_open;
+	udev->dev->close = uinput_dev_close;
+	udev->dev->event = uinput_dev_event;
+	udev->dev->upload_effect = uinput_dev_upload_effect;
+	udev->dev->erase_effect = uinput_dev_erase_effect;
+
+	init_waitqueue_head(&(udev->waitq));
+
+	input_register_device(udev->dev);
+
+	udev->state |= UIST_CREATED;
+
+	return 0;
+}
+
+static int uinput_destroy_device(struct uinput_device *udev)
+{
+	if (!(udev->state & UIST_CREATED)) {
+		printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME);
+		return -EINVAL;
+	}
+
+	input_unregister_device(udev->dev);
+
+	clear_bit(UIST_CREATED, &(udev->state));
+
+	return 0;
+}
+
+static int uinput_open(struct inode *inode, struct file *file)
+{
+	struct uinput_device	*newdev;
+	struct input_dev	*newinput;
+
+	MOD_INC_USE_COUNT;
+
+	newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL);
+	if (!newdev)
+		goto error;
+	memset(newdev, 0, sizeof(struct uinput_device));
+
+	newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
+	if (!newinput)
+		goto cleanup;
+	memset(newinput, 0, sizeof(struct input_dev));
+
+	newdev->dev = newinput;
+	
+	file->private_data = newdev;
+
+	return 0;
+cleanup:
+	kfree(newdev);
+error:
+	MOD_DEC_USE_COUNT;
+	return -ENOMEM;
+}
+
+static int uinput_alloc_device(struct file *file, const char *buffer, size_t count)
+{
+	struct uinput_user_dev	user_dev;
+	struct input_dev	*dev;
+	struct uinput_device	*udev;
+	int			size,
+				retval;
+
+	retval = count;
+
+	if (copy_from_user(&user_dev, buffer, sizeof(struct uinput_user_dev))) {
+		retval = -EFAULT;
+		goto exit;
+	}
+
+	udev = (struct uinput_device *)file->private_data;
+	dev = udev->dev;
+
+	size = strnlen(user_dev.name, UINPUT_MAX_NAME_SIZE);
+	dev->name = kmalloc(size + 1, GFP_KERNEL);
+	if (!dev->name) {
+		retval = -ENOMEM;
+		goto exit;
+	}
+
+	strncpy(dev->name, user_dev.name, size);
+	dev->name[size] = '\0';
+	dev->idbus 	= user_dev.idbus;
+	dev->idvendor 	= user_dev.idvendor;
+	dev->idproduct 	= user_dev.idproduct;
+	dev->idversion 	= user_dev.idversion;
+	dev->ff_effects_max = user_dev.ff_effects_max;
+
+	size = sizeof(unsigned long) * NBITS(ABS_MAX + 1);
+	memcpy(dev->absmax, user_dev.absmax, size);
+	memcpy(dev->absmin, user_dev.absmin, size);
+	memcpy(dev->absfuzz, user_dev.absfuzz, size);
+	memcpy(dev->absflat, user_dev.absflat, size);
+
+	/* check if absmin/absmax/absfuzz/absflat are filled as
+	 * told in Documentation/input/input-programming.txt */
+	if (test_bit(EV_ABS, dev->evbit)) {
+		unsigned int cnt;
+		for (cnt = 1; cnt < ABS_MAX; cnt++)
+			if (test_bit(cnt, dev->absbit) &&
+					(!dev->absmin[cnt] ||
+					 !dev->absmax[cnt] ||
+					 !dev->absfuzz[cnt] ||
+					 !dev->absflat[cnt])) {
+				printk(KERN_DEBUG "%s: set abs fields "
+					"first\n", UINPUT_NAME);
+				retval = -EINVAL;
+				goto free_name;
+			}
+	}
+
+exit:
+	return retval;
+free_name:
+	kfree(dev->name);
+	goto exit;
+}
+
+static int uinput_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct uinput_device	*udev = file->private_data;
+	
+
+	if (udev->state & UIST_CREATED) {
+		struct input_event	ev;
+
+		if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
+			return -EFAULT;
+		input_event(udev->dev, ev.type, ev.code, ev.value);
+	}
+	else
+		count = uinput_alloc_device(file, buffer, count);
+
+	return count;
+}
+
+static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct uinput_device	*udev;
+	int retval = 0;
+	DECLARE_WAITQUEUE(waitq, current);
+
+	udev = (struct uinput_device *)file->private_data;
+
+	if (udev->head == udev->tail) {
+		add_wait_queue(&udev->waitq, &waitq);
+		current->state = TASK_INTERRUPTIBLE;
+
+		while (udev->head == udev->tail) {
+			if (!(udev->state & UIST_CREATED)) {
+				retval = -ENODEV;
+				break;
+			}
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				retval = -ERESTARTSYS;
+				break;
+			}
+			schedule();
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&udev->waitq, &waitq);
+	}
+
+	if (retval)
+		return retval;
+
+	while (udev->head != udev->tail && retval + sizeof(struct uinput_device) <= count) {
+		if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]),
+		    sizeof(struct input_event)))
+			return -EFAULT;
+		udev->tail = (udev->tail + 1)%(UINPUT_BUFFER_SIZE - 1);
+		retval += sizeof(struct input_event);
+	}
+
+	return retval;
+}
+
+static unsigned int uinput_poll(struct file *file, poll_table *wait)
+{
+        struct uinput_device *udev = file->private_data;
+
+	poll_wait(file, &udev->waitq, wait);
+
+	if (udev->head != udev->tail)
+		return POLLIN | POLLRDNORM;
+
+	return 0;			
+}
+
+static int uinput_burn_device(struct uinput_device *udev)
+{
+	if (udev->state & UIST_CREATED)
+		uinput_destroy_device(udev);
+
+	kfree(udev->dev);
+	kfree(udev);
+
+	return 0;
+}
+
+static int uinput_close(struct inode *inode, struct file *file)
+{
+	int	retval;
+
+	retval = uinput_burn_device((struct uinput_device *)file->private_data);
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int			retval = 0;
+	struct uinput_device	*udev;
+
+	udev = (struct uinput_device *)file->private_data;
+
+	if (cmd >= UI_SET_EVBIT && (udev->state & UIST_CREATED))
+		return -EINVAL;
+
+	switch (cmd) {
+		case UI_DEV_CREATE:
+			retval = uinput_create_device(udev);
+
+			break;
+		case UI_DEV_DESTROY:
+			retval = uinput_destroy_device(udev);
+
+			break;
+		case UI_SET_EVBIT:
+			set_bit(arg, udev->dev->evbit);
+
+		break;
+		case UI_SET_KEYBIT:
+			set_bit(arg, udev->dev->keybit);
+
+		break;
+		case UI_SET_RELBIT:
+			set_bit(arg, udev->dev->relbit);
+
+		break;
+		case UI_SET_ABSBIT:
+			set_bit(arg, udev->dev->absbit);
+
+		break;
+		case UI_SET_MSCBIT:
+			set_bit(arg, udev->dev->mscbit);
+
+		break;
+		case UI_SET_LEDBIT:
+			set_bit(arg, udev->dev->ledbit);
+
+		break;
+		case UI_SET_SNDBIT:
+			set_bit(arg, udev->dev->sndbit);
+
+		break;
+		case UI_SET_FFBIT:
+			set_bit(arg, udev->dev->ffbit);
+
+		break;
+		default:
+			retval = -EFAULT;
+	}
+	return retval;
+}
+
+struct file_operations uinput_fops = {
+	owner:		THIS_MODULE,
+	open:		uinput_open,
+	release:	uinput_close,
+	read:		uinput_read,
+	write:		uinput_write,
+	poll:		uinput_poll,
+//	fasync:		uinput_fasync,
+	ioctl:		uinput_ioctl,
+};
+
+static struct miscdevice uinput_misc = {
+	fops:		&uinput_fops,
+	minor:		UINPUT_MINOR,
+	name:		UINPUT_NAME,
+};
+
+static int __init uinput_init(void)
+{
+	int	retval;
+	
+	retval = misc_register(&uinput_misc);
+
+	if (!retval) {
+		printk(KERN_INFO "%s: User level driver support for input subsystem loaded\n", UINPUT_NAME);
+		printk(KERN_INFO "%s: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>\n", UINPUT_NAME);
+	}
+
+	return retval;
+}
+
+static void __exit uinput_exit(void)
+{
+	misc_deregister(&uinput_misc);
+}
+
+MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
+MODULE_DESCRIPTION("User level driver support for input subsystem");
+MODULE_LICENSE("GPL");
+
+module_init(uinput_init);
+module_exit(uinput_exit);
+
diff -Nru a/drivers/isdn/hisax/Config.in b/drivers/isdn/hisax/Config.in
--- a/drivers/isdn/hisax/Config.in	Tue Jul 16 16:49:41 2002
+++ b/drivers/isdn/hisax/Config.in	Tue Jul 16 16:49:41 2002
@@ -14,27 +14,27 @@
    bool '  HiSax Support for US NI1' CONFIG_HISAX_NI1
    int  '  Maximum number of cards supported by HiSax' CONFIG_HISAX_MAX_CARDS 8
    comment '  HiSax supported cards'
-   bool '  Teles 16.0/8.0' CONFIG_HISAX_16_0 $CONFIG_ISA
+   dep_bool '  Teles 16.0/8.0' CONFIG_HISAX_16_0 $CONFIG_ISA
    bool '  Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
    bool '  Teles PCI' CONFIG_HISAX_TELESPCI 
    bool '  Teles S0Box' CONFIG_HISAX_S0BOX 
-   bool '  AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1 $CONFIG_ISA
+   dep_bool '  AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1 $CONFIG_ISA
    bool '  AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
    bool '  AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
    bool '  Elsa cards' CONFIG_HISAX_ELSA
-   bool '  ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2 $CONFIG_ISA
+   dep_bool '  ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2 $CONFIG_ISA
    bool '  Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
-   bool '  ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM $CONFIG_ISA
-   bool '  TELEINT cards' CONFIG_HISAX_TELEINT $CONFIG_ISA
-   bool '  HFC-S based cards' CONFIG_HISAX_HFCS $CONFIG_ISA
+   dep_bool '  ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM $CONFIG_ISA
+   dep_bool '  TELEINT cards' CONFIG_HISAX_TELEINT $CONFIG_ISA
+   dep_bool '  HFC-S based cards' CONFIG_HISAX_HFCS $CONFIG_ISA
    bool '  Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
-   bool '  USR Sportster internal TA' CONFIG_HISAX_SPORTSTER $CONFIG_ISA
-   bool '  MIC card' CONFIG_HISAX_MIC $CONFIG_ISA
+   dep_bool '  USR Sportster internal TA' CONFIG_HISAX_SPORTSTER $CONFIG_ISA
+   dep_bool '  MIC card' CONFIG_HISAX_MIC $CONFIG_ISA
    bool '  NETjet card' CONFIG_HISAX_NETJET
    bool '  NETspider U card' CONFIG_HISAX_NETJET_U
    bool '  Niccy PnP/PCI card' CONFIG_HISAX_NICCY
-   bool '  Siemens I-Surf card' CONFIG_HISAX_ISURF $CONFIG_ISA
-   bool '  HST Saphir card' CONFIG_HISAX_HSTSAPHIR $CONFIG_ISA
+   dep_bool '  Siemens I-Surf card' CONFIG_HISAX_ISURF $CONFIG_ISA
+   dep_bool '  HST Saphir card' CONFIG_HISAX_HSTSAPHIR $CONFIG_ISA
    bool '  Telekom A4T card' CONFIG_HISAX_BKM_A4T 
    bool '  Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
    bool '  Gazel cards' CONFIG_HISAX_GAZEL
@@ -44,7 +44,7 @@
    if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
 #      bool '  TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
       bool '  Formula-n enter:now PCI card' CONFIG_HISAX_ENTERNOW_PCI
-      if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+      if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
 	 bool '  Am7930' CONFIG_HISAX_AMD7930
       fi
    fi
diff -Nru a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
--- a/drivers/macintosh/adbhid.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/macintosh/adbhid.c	Tue Jul 16 16:49:42 2002
@@ -77,6 +77,7 @@
 	int mouse_kind;
 	unsigned char *keycode;
 	char name[64];
+	char phys[32];
 };
 
 static struct adbhid *adbhid[16] = { 0 };
@@ -273,12 +274,37 @@
 	switch (adbhid[id]->original_handler_id) {
 	default:
 	case 0x02: /* Adjustable keyboard button device */
-		printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n",
-		       data[0], data[1], data[2], data[3]);
-		break;
+	  {
+		int down = (data[1] == (data[1] & 0xf));
+
+		switch (data[1] & 0x0f) {
+		case 0x0:	/* microphone */
+			input_report_key(&adbhid[id]->input, KEY_SOUND, down);
+			break;
+
+		case 0x1:	/* mute */
+			input_report_key(&adbhid[id]->input, KEY_MUTE, down);
+			break;
+
+		case 0x2:	/* volume decrease */
+			input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN, down);
+			break;
+
+		case 0x3:	/* volume increase */
+			input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, down);
+			break;
+
+		default:
+			printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n",
+			       data[0], data[1], data[2], data[3]);
+			break;
+		}
+	  }
+	  break;
+
 	case 0x1f: /* Powerbook button device */
 	  {
-	  	int down = (data[1] == (data[1] & 0xf));
+		int down = (data[1] == (data[1] & 0xf));
 #ifdef CONFIG_PMAC_BACKLIGHT
 		int backlight = get_backlight_level();
 #endif
@@ -298,11 +324,12 @@
 
 		case 0x6:	/* volume increase */
 			input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, down);
- 			break;
+			break;
 
 		case 0xb:	/* eject */
 			input_report_key(&adbhid[id]->input, KEY_EJECTCD, down);
 			break;
+
 		case 0xa:	/* brightness decrease */
 #ifdef CONFIG_PMAC_BACKLIGHT
 			if (!disable_kernel_backlight) {
@@ -317,6 +344,7 @@
 #endif /* CONFIG_PMAC_BACKLIGHT */
 			input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
 			break;
+
 		case 0x9:	/* brightness increase */
 #ifdef CONFIG_PMAC_BACKLIGHT
 			if (!disable_kernel_backlight) {
@@ -442,6 +470,7 @@
 		return;
 
 	memset(adbhid[id], 0, sizeof(struct adbhid));
+	sprintf(adbhid[id]->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id);
 
 	adbhid[id]->id = default_id;
 	adbhid[id]->original_handler_id = original_handler_id;
@@ -449,6 +478,7 @@
 	adbhid[id]->mouse_kind = mouse_kind;
 	adbhid[id]->input.private = adbhid[id];
 	adbhid[id]->input.name = adbhid[id]->name;
+	adbhid[id]->input.phys = adbhid[id]->phys;
 	adbhid[id]->input.idbus = BUS_ADB;
 	adbhid[id]->input.idvendor = 0x0001;
 	adbhid[id]->input.idproduct = (id << 12) | (default_id << 8) | original_handler_id;
@@ -461,8 +491,7 @@
 			return;
 		}
 
-		sprintf(adbhid[id]->name, "ADB keyboard on ID %d:%d.%02x",
-			id, default_id, original_handler_id);
+		sprintf(adbhid[id]->name, "ADB keyboard");
 
 		memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes));
 
@@ -509,8 +538,7 @@
 		break;
 
 	case ADB_MOUSE:
-		sprintf(adbhid[id]->name, "ADB mouse on ID %d:%d.%02x",
-			id, default_id, original_handler_id);
+		sprintf(adbhid[id]->name, "ADB mouse");
 
 		adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 		adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
@@ -520,12 +548,15 @@
 	case ADB_MISC:
 		switch (original_handler_id) {
 		case 0x02: /* Adjustable keyboard button device */
-			sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons on ID %d:%d.%02x",
-				id, default_id, original_handler_id);
+			sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons");
+			adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+			set_bit(KEY_SOUND, adbhid[id]->input.keybit);
+			set_bit(KEY_MUTE, adbhid[id]->input.keybit);
+			set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit);
+			set_bit(KEY_VOLUMEDOWN, adbhid[id]->input.keybit);
 			break;
 		case 0x1f: /* Powerbook button device */
-			sprintf(adbhid[id]->name, "ADB Powerbook buttons on ID %d:%d.%02x",
-				id, default_id, original_handler_id);
+			sprintf(adbhid[id]->name, "ADB Powerbook buttons");
 			adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
 			set_bit(KEY_MUTE, adbhid[id]->input.keybit);
 			set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit);
@@ -549,8 +580,8 @@
 
 	input_register_device(&adbhid[id]->input);
 
-	printk(KERN_INFO "input%d: ADB HID on ID %d:%d.%02x\n",
-	       adbhid[id]->input.number, id, default_id, original_handler_id);
+	printk(KERN_INFO "input: %s on %s\n",
+	       adbhid[id]->name, adbhid[id]->phys);
 
 	if (default_id == ADB_KEYBOARD) {
 		/* HACK WARNING!! This should go away as soon there is an utility
@@ -580,11 +611,11 @@
 		    ((id << 12)|(default_id << 8)|org_handler_id)) {
 			adbhid_input_unregister(id);
 			adbhid_input_register(id, default_id, org_handler_id,
-				cur_handler_id, mk);
+					      cur_handler_id, mk);
 		}
 	} else
 		adbhid_input_register(id, default_id, org_handler_id,
-			cur_handler_id, mk);
+				      cur_handler_id, mk);
 	return 1<<id;
 }
 
@@ -593,10 +624,10 @@
 {
 	int i;
 	for(i=1; i<16; i++)
-	    if (adbhid[i] && !(exist&(1<<i)))
-		adbhid_input_unregister(i);
+		if (adbhid[i] && !(exist&(1<<i)))
+			adbhid_input_unregister(i);
 }
- 
+
 static void
 adbhid_probe(void)
 {
@@ -631,14 +662,16 @@
 			printk("ADB keyboard at %d, handler 1\n", id);
 
 		adb_get_infos(id, &default_id, &cur_handler_id);
-		reg |= adbhid_input_reregister(id, default_id, org_handler_id, cur_handler_id, 0);
+		reg |= adbhid_input_reregister(id, default_id, org_handler_id,
+					       cur_handler_id, 0);
 	}
 
 	for (i = 0; i < buttons_ids.nids; i++) {
 		int id = buttons_ids.id[i];
 
 		adb_get_infos(id, &default_id, &org_handler_id);
-		reg |= adbhid_input_reregister(id, default_id, org_handler_id, org_handler_id, 0);
+		reg |= adbhid_input_reregister(id, default_id, org_handler_id,
+					       org_handler_id, 0);
 	}
 
 	/* Try to switch all mice to handler 4, or 2 for three-button
@@ -728,8 +761,8 @@
 
 		adb_get_infos(id, &default_id, &cur_handler_id);
 		reg |= adbhid_input_reregister(id, default_id, org_handler_id,
-				      cur_handler_id, mouse_kind);
-        }
+					       cur_handler_id, mouse_kind);
+	}
 	adbhid_input_devcleanup(reg);
 }
 
@@ -742,7 +775,7 @@
 	printk(" (trackpad)");
 
 	adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
-		ADB_READREG(id,1));
+		    ADB_READREG(id,1));
 	if (req.reply_len < 8)
 	    printk("bad length for reg. 1\n");
 	else
@@ -782,7 +815,7 @@
 	            0x03, /*r1_buffer[6],*/
 	            r1_buffer[7]);
 
-	    /* Without this flush, the trackpad may be locked up */	    
+	    /* Without this flush, the trackpad may be locked up */
 	    adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
         }
 }
diff -Nru a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
--- a/drivers/macintosh/mac_hid.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/macintosh/mac_hid.c	Tue Jul 16 16:49:43 2002
@@ -5,8 +5,6 @@
  *
  * Copyright (C) 2000 Franz Sirl.
  *
- * Stuff inside CONFIG_MAC_ADBKEYCODES should go away during 2.5 when all
- * major distributions are using the Linux keycodes.
  * Stuff inside CONFIG_MAC_EMUMOUSEBTN should really be moved to userspace.
  */
 
@@ -17,184 +15,6 @@
 #include <linux/input.h>
 #include <linux/module.h>
 
-#ifdef CONFIG_MAC_ADBKEYCODES
-#include <linux/keyboard.h>
-#include <asm/keyboard.h>
-#include <asm/machdep.h>
-#endif
-
-#ifdef CONFIG_MAC_ADBKEYCODES
-/* Simple translation table for the SysRq keys */
-
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned char mac_hid_kbd_sysrq_xlate[128] =
-	"asdfhgzxcv\000bqwer"				/* 0x00 - 0x0f */
-	"yt123465=97-80o]"				/* 0x10 - 0x1f */
-	"u[ip\rlj'k;\\,/nm."				/* 0x20 - 0x2f */
-	"\t `\177\000\033\000\000\000\000\000\000\000\000\000\000"
-							/* 0x30 - 0x3f */
-	"\000\000\000*\000+\000\000\000\000\000/\r\000-\000"
-							/* 0x40 - 0x4f */
-	"\000\0000123456789\000\000\000"		/* 0x50 - 0x5f */
-	"\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214";
-							/* 0x60 - 0x6f */
-extern unsigned char pckbd_sysrq_xlate[128];
-#endif
-
-static u_short macplain_map[NR_KEYS] = {
-	0xfb61,	0xfb73,	0xfb64,	0xfb66,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
-	0xfb63,	0xfb76,	0xf200,	0xfb62,	0xfb71,	0xfb77,	0xfb65,	0xfb72,
-	0xfb79,	0xfb74,	0xf031,	0xf032,	0xf033,	0xf034,	0xf036,	0xf035,
-	0xf03d,	0xf039,	0xf037,	0xf02d,	0xf038,	0xf030,	0xf05d,	0xfb6f,
-	0xfb75,	0xf05b,	0xfb69,	0xfb70,	0xf201,	0xfb6c,	0xfb6a,	0xf027,
-	0xfb6b,	0xf03b,	0xf05c,	0xf02c,	0xf02f,	0xfb6e,	0xfb6d,	0xf02e,
-	0xf009,	0xf020,	0xf060,	0xf07f,	0xf200,	0xf01b,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf104,	0xf105,	0xf106,	0xf102,	0xf107,	0xf108,	0xf200,	0xf10a,
-	0xf200,	0xf10c,	0xf200,	0xf209,	0xf200,	0xf109,	0xf200,	0xf10b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf103,	0xf117,
-	0xf101,	0xf119,	0xf100,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
-};
-
-static u_short macshift_map[NR_KEYS] = {
-	0xfb41,	0xfb53,	0xfb44,	0xfb46,	0xfb48,	0xfb47,	0xfb5a,	0xfb58,
-	0xfb43,	0xfb56,	0xf200,	0xfb42,	0xfb51,	0xfb57,	0xfb45,	0xfb52,
-	0xfb59,	0xfb54,	0xf021,	0xf040,	0xf023,	0xf024,	0xf05e,	0xf025,
-	0xf02b,	0xf028,	0xf026,	0xf05f,	0xf02a,	0xf029,	0xf07d,	0xfb4f,
-	0xfb55,	0xf07b,	0xfb49,	0xfb50,	0xf201,	0xfb4c,	0xfb4a,	0xf022,
-	0xfb4b,	0xf03a,	0xf07c,	0xf03c,	0xf03f,	0xfb4e,	0xfb4d,	0xf03e,
-	0xf009,	0xf020,	0xf07e,	0xf07f,	0xf200,	0xf01b,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf10e,	0xf10f,	0xf110,	0xf10c,	0xf111,	0xf112,	0xf200,	0xf10a,
-	0xf200,	0xf10c,	0xf200,	0xf203,	0xf200,	0xf113,	0xf200,	0xf10b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf20b,	0xf116,	0xf10d,	0xf117,
-	0xf10b,	0xf20a,	0xf10a,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
-};
-
-static u_short macaltgr_map[NR_KEYS] = {
-	0xf914,	0xfb73,	0xf917,	0xf919,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
-	0xf916,	0xfb76,	0xf200,	0xf915,	0xfb71,	0xfb77,	0xf918,	0xfb72,
-	0xfb79,	0xfb74,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,
-	0xf200,	0xf05d,	0xf07b,	0xf05c,	0xf05b,	0xf07d,	0xf07e,	0xfb6f,
-	0xfb75,	0xf200,	0xfb69,	0xfb70,	0xf201,	0xfb6c,	0xfb6a,	0xf200,
-	0xfb6b,	0xf200,	0xf200,	0xf200,	0xf200,	0xfb6e,	0xfb6d,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf90a,	0xf90b,	0xf90c,	0xf90d,	0xf90e,	0xf90f,
-	0xf910,	0xf911,	0xf200,	0xf912,	0xf913,	0xf200,	0xf200,	0xf200,
-	0xf510,	0xf511,	0xf512,	0xf50e,	0xf513,	0xf514,	0xf200,	0xf516,
-	0xf200,	0xf10c,	0xf200,	0xf202,	0xf200,	0xf515,	0xf200,	0xf517,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf50f,	0xf117,
-	0xf50d,	0xf119,	0xf50c,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
-};
-
-static u_short macctrl_map[NR_KEYS] = {
-	0xf001,	0xf013,	0xf004,	0xf006,	0xf008,	0xf007,	0xf01a,	0xf018,
-	0xf003,	0xf016,	0xf200,	0xf002,	0xf011,	0xf017,	0xf005,	0xf012,
-	0xf019,	0xf014,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01e,	0xf01d,
-	0xf200,	0xf200,	0xf01f,	0xf01f,	0xf07f,	0xf200,	0xf01d,	0xf00f,
-	0xf015,	0xf01b,	0xf009,	0xf010,	0xf201,	0xf00c,	0xf00a,	0xf007,
-	0xf00b,	0xf200,	0xf01c,	0xf200,	0xf07f,	0xf00e,	0xf00d,	0xf20e,
-	0xf200,	0xf000,	0xf000,	0xf008,	0xf200,	0xf200,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf104,	0xf105,	0xf106,	0xf102,	0xf107,	0xf108,	0xf200,	0xf10a,
-	0xf200,	0xf10c,	0xf200,	0xf204,	0xf200,	0xf109,	0xf200,	0xf10b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf103,	0xf117,
-	0xf101,	0xf119,	0xf100,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
-};
-
-static u_short macshift_ctrl_map[NR_KEYS] = {
-	0xf001,	0xf013,	0xf004,	0xf006,	0xf008,	0xf007,	0xf01a,	0xf018,
-	0xf003,	0xf016,	0xf200,	0xf002,	0xf011,	0xf017,	0xf005,	0xf012,
-	0xf019,	0xf014,	0xf200,	0xf000,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,	0xf00f,
-	0xf015,	0xf200,	0xf009,	0xf010,	0xf201,	0xf00c,	0xf00a,	0xf200,
-	0xf00b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf00e,	0xf00d,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf10c,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf200,	0xf117,
-	0xf200,	0xf119,	0xf200,	0xf700,	0xf701,	0xf702,	0xf200,	0xf20c,
-};
-
-static u_short macalt_map[NR_KEYS] = {
-	0xf861,	0xf873,	0xf864,	0xf866,	0xf868,	0xf867,	0xf87a,	0xf878,
-	0xf863,	0xf876,	0xf200,	0xf862,	0xf871,	0xf877,	0xf865,	0xf872,
-	0xf879,	0xf874,	0xf831,	0xf832,	0xf833,	0xf834,	0xf836,	0xf835,
-	0xf83d,	0xf839,	0xf837,	0xf82d,	0xf838,	0xf830,	0xf85d,	0xf86f,
-	0xf875,	0xf85b,	0xf869,	0xf870,	0xf80d,	0xf86c,	0xf86a,	0xf827,
-	0xf86b,	0xf83b,	0xf85c,	0xf82c,	0xf82f,	0xf86e,	0xf86d,	0xf82e,
-	0xf809,	0xf820,	0xf860,	0xf87f,	0xf200,	0xf81b,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf210,	0xf211,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf900,	0xf901,	0xf902,	0xf903,	0xf904,	0xf905,
-	0xf906,	0xf907,	0xf200,	0xf908,	0xf909,	0xf200,	0xf200,	0xf200,
-	0xf504,	0xf505,	0xf506,	0xf502,	0xf507,	0xf508,	0xf200,	0xf50a,
-	0xf200,	0xf10c,	0xf200,	0xf209,	0xf200,	0xf509,	0xf200,	0xf50b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf503,	0xf117,
-	0xf501,	0xf119,	0xf500,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
-};
-
-static u_short macctrl_alt_map[NR_KEYS] = {
-	0xf801,	0xf813,	0xf804,	0xf806,	0xf808,	0xf807,	0xf81a,	0xf818,
-	0xf803,	0xf816,	0xf200,	0xf802,	0xf811,	0xf817,	0xf805,	0xf812,
-	0xf819,	0xf814,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf80f,
-	0xf815,	0xf200,	0xf809,	0xf810,	0xf201,	0xf80c,	0xf80a,	0xf200,
-	0xf80b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf80e,	0xf80d,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf504,	0xf505,	0xf506,	0xf502,	0xf507,	0xf508,	0xf200,	0xf50a,
-	0xf200,	0xf10c,	0xf200,	0xf200,	0xf200,	0xf509,	0xf200,	0xf50b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf503,	0xf117,
-	0xf501,	0xf119,	0xf500,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
-};
-
-static unsigned short *mac_key_maps_save[MAX_NR_KEYMAPS] = {
-	macplain_map, macshift_map, macaltgr_map, 0,
-	macctrl_map, macshift_ctrl_map, 0, 0,
-	macalt_map, 0, 0, 0,
-	macctrl_alt_map,   0
-};
-
-static unsigned short *pc_key_maps_save[MAX_NR_KEYMAPS];
-
-int mac_hid_kbd_translate(unsigned char keycode, unsigned char *keycodep,
-			  char raw_mode);
-static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
-				   void *buffer, size_t *lenp);
-char mac_hid_kbd_unexpected_up(unsigned char keycode);
-
-static int keyboard_lock_keycodes = 0;
-int keyboard_sends_linux_keycodes = 0;
-#else
-int keyboard_sends_linux_keycodes = 1;
-#endif
-
 
 static unsigned char e0_keys[128] = {
 	0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0,		/* 0x00-0x07 */
@@ -225,25 +45,10 @@
 static int mouse_last_keycode = 0;
 #endif
 
-extern void pckbd_init_hw(void);
-
-#if defined CONFIG_SYSCTL && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN))
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_MAC_EMUMOUSEBTN)
 /* file(s) in /proc/sys/dev/mac_hid */
 ctl_table mac_hid_files[] =
 {
-#ifdef CONFIG_MAC_ADBKEYCODES
-  {
-    DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES,
-    "keyboard_sends_linux_keycodes", &keyboard_sends_linux_keycodes, sizeof(int),
-    0644, NULL, &mac_hid_sysctl_keycodes
-  },
-  {
-    DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES,
-    "keyboard_lock_keycodes", &keyboard_lock_keycodes, sizeof(int),
-    0644, NULL, &proc_dointvec
-  },
-#endif
-#ifdef CONFIG_MAC_EMUMOUSEBTN
   {
     DEV_MAC_HID_MOUSE_BUTTON_EMULATION,
     "mouse_button_emulation", &mouse_emulate_buttons, sizeof(int),
@@ -259,7 +64,6 @@
     "mouse_button3_keycode", &mouse_button3_keycode, sizeof(int),
     0644, NULL, &proc_dointvec
   },
-#endif
   { 0 }
 };
 
@@ -279,148 +83,72 @@
 
 static struct ctl_table_header *mac_hid_sysctl_header;
 
-#ifdef CONFIG_MAC_ADBKEYCODES
-static
-int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
-			    void *buffer, size_t *lenp)
-{
-	int val = keyboard_sends_linux_keycodes;
-	int ret = 0;
-
-	if (!write
-	    || (write && !keyboard_lock_keycodes))
-		ret = proc_dointvec(ctl, write, filp, buffer, lenp);
-
-	if (write
-	    && keyboard_sends_linux_keycodes != val) {
-		if (!keyboard_sends_linux_keycodes) {
-#ifdef CONFIG_MAGIC_SYSRQ
-			ppc_md.ppc_kbd_sysrq_xlate   = mac_hid_kbd_sysrq_xlate;
-			SYSRQ_KEY                = 0x69;
-#endif
-			memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
-			memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
-		} else {
-#ifdef CONFIG_MAGIC_SYSRQ
-			ppc_md.ppc_kbd_sysrq_xlate   = pckbd_sysrq_xlate;
-			SYSRQ_KEY                = 0x54;
-#endif
-			memcpy(mac_key_maps_save, key_maps, sizeof(key_maps));
-			memcpy(key_maps, pc_key_maps_save, sizeof(key_maps));
-		}
-	}
-
-	return ret;
-}
-#endif
 #endif /* endif CONFIG_SYSCTL */
 
 int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
 			  char raw_mode)
 {
-#ifdef CONFIG_MAC_ADBKEYCODES
-	if (!keyboard_sends_linux_keycodes) {
-		if (!raw_mode) {
-		/*
-		 * Convert R-shift/control/option to L version.
-		 */
-			switch (scancode) {
-			case 0x7b: scancode = 0x38; break; /* R-shift */
-			case 0x7c: scancode = 0x3a; break; /* R-option */
-			case 0x7d: scancode = 0x36; break; /* R-control */
-			}
-		}
-		*keycode = scancode;
-		return 1;
-	} else
-#endif
-	{
-		/* This code was copied from char/pc_keyb.c and will be
-		 * superflous when the input layer is fully integrated.
-		 * We don't need the high_keys handling, so this part
-		 * has been removed.
-		 */
-		static int prev_scancode = 0;
-
-		/* special prefix scancodes.. */
-		if (scancode == 0xe0 || scancode == 0xe1) {
-			prev_scancode = scancode;
-			return 0;
-		}
+	/* This code was copied from char/pc_keyb.c and will be
+	 * superflous when the input layer is fully integrated.
+	 * We don't need the high_keys handling, so this part
+	 * has been removed.
+	 */
+	static int prev_scancode = 0;
+
+	/* special prefix scancodes.. */
+	if (scancode == 0xe0 || scancode == 0xe1) {
+		prev_scancode = scancode;
+		return 0;
+	}
 
-		scancode &= 0x7f;
+	scancode &= 0x7f;
 
-		if (prev_scancode) {
-			if (prev_scancode != 0xe0) {
-				if (prev_scancode == 0xe1 && scancode == 0x1d) {
-					prev_scancode = 0x100;
-					return 0;
-				} else if (prev_scancode == 0x100 && scancode == 0x45) {
-					*keycode = KEY_PAUSE;
-					prev_scancode = 0;
-				} else {
-					if (!raw_mode)
-						printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
-					prev_scancode = 0;
-					return 0;
-				}
-			} else {
+	if (prev_scancode) {
+		if (prev_scancode != 0xe0) {
+			if (prev_scancode == 0xe1 && scancode == 0x1d) {
+				prev_scancode = 0x100;
+				return 0;
+			} else if (prev_scancode == 0x100 && scancode == 0x45) {
+				*keycode = KEY_PAUSE;
 				prev_scancode = 0;
-				if (scancode == 0x2a || scancode == 0x36)
-					return 0;
-			}
-			if (e0_keys[scancode])
-				*keycode = e0_keys[scancode];
-			else {
+			} else {
 				if (!raw_mode)
-					printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
-					       scancode);
+					printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
+				prev_scancode = 0;
 				return 0;
 			}
 		} else {
-			switch (scancode) {
-			case  91: scancode = KEY_LINEFEED; break;
-			case  92: scancode = KEY_KPEQUAL; break;
-			case 125: scancode = KEY_INTL1; break;
-			}
-			*keycode = scancode;
+			prev_scancode = 0;
+			if (scancode == 0x2a || scancode == 0x36)
+				return 0;
+		}
+		if (e0_keys[scancode])
+			*keycode = e0_keys[scancode];
+		else {
+			if (!raw_mode)
+				printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+				       scancode);
+			return 0;
+		}
+	} else {
+		switch (scancode) {
+		case  91: scancode = KEY_LINEFEED; break;
+		case  92: scancode = KEY_KPEQUAL; break;
+		case 125: scancode = KEY_INTL1; break;
 		}
-		return 1;
+		*keycode = scancode;
 	}
+	return 1;
 }
 
 char mac_hid_kbd_unexpected_up(unsigned char keycode)
 {
-	if (keyboard_sends_linux_keycodes && keycode == KEY_F13)
+	if (keycode == KEY_F13)
 		return 0;
 	else
 		return 0x80;
 }
 
-#ifdef CONFIG_MAC_ADBKEYCODES
-int mac_hid_keyboard_sends_linux_keycodes(void)
-{
-	return keyboard_sends_linux_keycodes;
-}
-
-EXPORT_SYMBOL(mac_hid_keyboard_sends_linux_keycodes);
-
-static int __init mac_hid_setup(char *str)
-{
-	int ints[2];
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-	if (ints[0] == 1) {
-		keyboard_sends_linux_keycodes = ints[1] != 0;
-		keyboard_lock_keycodes = 1;
-	}
-	return 1;
-}
-
-__setup("keyboard_sends_linux_keycodes=", mac_hid_setup);
-
-#endif
-
 #ifdef CONFIG_MAC_EMUMOUSEBTN
 int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
 {
@@ -439,15 +167,6 @@
 			mouse_last_keycode = down ? keycode : 0;
 		}
 		break;
-	case 2:
-		/* Called from mousedev.c */
-		if (mouse_emulate_buttons == 2 && keycode == 0) {
-			if (mouse_last_keycode == mouse_button2_keycode)
-				return 1; /* map to middle button */
-			if (mouse_last_keycode == mouse_button3_keycode)
-				return 2; /* map to right button */
-		}
-		return keycode; /* keep button */
 	}
 	return 0;
 }
@@ -469,40 +188,22 @@
 
 	input_register_device(&emumousebtn);
 
-	printk(KERN_INFO "input%d: Macintosh mouse button emulation\n", emumousebtn.number);
+	printk(KERN_INFO "input: Macintosh mouse button emulation\n");
 }
 #endif
 
-void __init mac_hid_init_hw(void)
+int __init mac_hid_init(void)
 {
 
-#ifdef CONFIG_MAC_ADBKEYCODES
-	memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
-
-	if (!keyboard_sends_linux_keycodes) {
-#ifdef CONFIG_MAGIC_SYSRQ
-		ppc_md.ppc_kbd_sysrq_xlate   = mac_hid_kbd_sysrq_xlate;
-		SYSRQ_KEY                = 0x69;
-#endif
-		memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
-	} else {
-#ifdef CONFIG_MAGIC_SYSRQ
-		ppc_md.ppc_kbd_sysrq_xlate   = pckbd_sysrq_xlate;
-		SYSRQ_KEY                = 0x54;
-#endif
-	}
-#endif /* CONFIG_MAC_ADBKEYCODES */
-
 #ifdef CONFIG_MAC_EMUMOUSEBTN
 	emumousebtn_input_register();
 #endif
 
-#if CONFIG_PPC
-	if (_machine != _MACH_Pmac)
-		pckbd_init_hw();
-#endif
-
-#if defined(CONFIG_SYSCTL) && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN))
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_MAC_EMUMOUSEBTN)
 	mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1);
 #endif /* CONFIG_SYSCTL */
+
+	return 0;
 }
+
+device_initcall(mac_hid_init);
diff -Nru a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
--- a/drivers/media/video/bttv-cards.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/media/video/bttv-cards.c	Tue Jul 16 16:49:42 2002
@@ -63,9 +63,9 @@
 static int triton1=0;
 static int vsfx=0;
 int no_overlay=-1;
-static unsigned int card[4]  = { -1, -1, -1, -1 };
-static unsigned int pll[4]   = { -1, -1, -1, -1 };
-static unsigned int tuner[4] = { -1, -1, -1, -1 };
+static unsigned int card[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = -1};
+static unsigned int pll[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = -1};
+static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = -1};
 #ifdef MODULE
 static unsigned int autoload = 1;
 #else
@@ -83,11 +83,11 @@
 MODULE_PARM_DESC(vsfx,"set VSFX pci config bit "
 		 "[yet another chipset flaw workaround]");
 MODULE_PARM(no_overlay,"i");
-MODULE_PARM(card,"1-4i");
+MODULE_PARM(card,"1-" __MODULE_STRING(BTTV_MAX) "i");
 MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
-MODULE_PARM(pll,"1-4i");
+MODULE_PARM(pll,"1-" __MODULE_STRING(BTTV_MAX) "i");
 MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
-MODULE_PARM(tuner,"1-4i");
+MODULE_PARM(tuner,"1-" __MODULE_STRING(BTTV_MAX) "i");
 MODULE_PARM_DESC(tuner,"specify installed tuner type");
 MODULE_PARM(autoload,"i");
 MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
@@ -135,9 +135,10 @@
 	{ 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
 
 	{ 0x6606107d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0x6607107d, BTTV_WINFAST2000,   "Leadtek WinFast VC 100" },
 	{ 0x263610b4, BTTV_STB2,          "STB TV PCI FM, P/N 6000704" },
- 	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV3/PCI" },
-	{ 0x405010fc, BTTV_GVBCTV4PCI,    "I-O Data Co. GV-BCV4/PCI" },
+ 	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
+	{ 0x405010fc, BTTV_GVBCTV4PCI,    "I-O Data Co. GV-BCTV4/PCI" },
 
 	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV" },
 	{ 0x001211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
@@ -163,6 +164,8 @@
 	{ 0x111a153b, BTTV_TERRATVALUE,   "Terratec TValue" },
 	{ 0x1123153b, BTTV_TERRATVRADIO,  "Terratec TV Radio+" },
 	{ 0x1127153b, BTTV_TERRATV,       "Terratec TV+"    },
+	// clashes with FlyVideo
+	//{ 0x18521852, BTTV_TERRATV,     "Terratec TV+"    },
 	{ 0x1134153b, BTTV_TERRATVALUE,   "Terratec TValue" },
 	{ 0x1135153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" },
 	{ 0x5018153b, BTTV_TERRATVALUE,   "Terratec TValue" },
@@ -174,13 +177,14 @@
 
     	{ 0x010115cb, BTTV_GMV1,          "AG GMV1" },
 	{ 0x010114c7, BTTV_MODTEC_205,    "Modular Technology MM205 PCTV" },
-	{ 0x18501851, BTTV_CHRONOS_VS2,   "Flyvideo 98 (LR50)/ Chronos Video Shuttle II" },
-	{ 0x18511851, BTTV_FLYVIDEO98EZ,  "Flyvideo 98EZ (LR51)/ CyberMail AV" },
-	{ 0x18521852, BTTV_TYPHOON_TVIEW, "Flyvideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
+	{ 0x18501851, BTTV_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+	{ 0x18511851, BTTV_FLYVIDEO98EZ,  "FlyVideo 98EZ (LR51)/ CyberMail AV" },
+	{ 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
 	{ 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
 	{ 0x217d6606, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
 	{ 0x03116000, BTTV_SENSORAY311,   "Sensoray 311" },
 	{ 0x00790e11, BTTV_WINDVR,        "Canopus WinDVR PCI" },
+	{ 0xa0fca1a0, BTTV_ZOLTRIX,       "Face to Face Tvmax" },
 
 	{ 0, -1, NULL }
 };
@@ -235,16 +239,16 @@
 },{
 
 /* ---- card 0x04 ---------------------------------- */
-	name:		"Intel",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		-1,
-	gpiomask:	7,
+	name:		"Intel Create and Share PCI/ Smart Video Recorder III",
+	video_inputs:	4,
+	audio_inputs:	0,
+	tuner:		-1,
+	svhs:		2,
+	gpiomask:	0,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 1, 2, 3, 4},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	audiomux:	{ 0 },
+	needs_tvaudio:	0,
+	tuner_type:	4,
 },{
 	name:		"Diamond DTV2000",
 	video_inputs:	4,
@@ -283,7 +287,7 @@
 },{
 
 /* ---- card 0x08 ---------------------------------- */
-	name:		"FlyVideo II (Bt848) LR26",
+	name:		"Lifeview FlyVideo II (Bt848) LR26",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -295,7 +299,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"IXMicro TurboTV",
+	name:		"IMS/IXmicro TurboTV",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -303,8 +307,9 @@
 	gpiomask:	3,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 1, 1, 2, 3, 0},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	needs_tvaudio:	0,
+	pll:		PLL_28,
+	tuner_type:	TUNER_TEMIC_PAL,
 },{
 	name:		"Hauppauge (bt878)",
 	video_inputs:	4,
@@ -331,7 +336,7 @@
 },{
 
 /* ---- card 0x0c ---------------------------------- */
-	name:		"ADS Technologies Channel Surfer TV",
+	name:		"ADS Technologies Channel Surfer TV (bt848)",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -363,6 +368,7 @@
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
 	needs_tvaudio:	1,
+	pll:		PLL_28,
 	tuner_type:	-1,
 },{
 	name:		"Zoltrix TV-Max",
@@ -378,7 +384,7 @@
 },{
 
 /* ---- card 0x10 ---------------------------------- */
-	name:		"Pixelview PlayTV (bt878)",
+	name:		"Prolink Pixelview PlayTV (bt878)",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -414,8 +420,8 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"LifeView FlyKit w/o Tuner",
-	video_inputs:	3,
+	name:		"Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
+	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		-1,
 	svhs:		-1,
@@ -435,19 +441,18 @@
 	muxsel:		{2, 3, 1, 1},
 	tuner_type:	-1,
 },{
-	name:		"Lucky Star Image World ConferenceTV",
-	video_inputs:	3,
-	audio_inputs:	1,
+	name:		"Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
+	video_inputs:	4,
+	audio_inputs:	2,  // tuner, line in
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0x00fffe07,
+	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 131072, 1, 1638400, 3, 4},
-	needs_tvaudio:	1,
+	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
 	pll:		PLL_28,
 	tuner_type:	TUNER_PHILIPS_PAL_I,
 },{
-	name:		"Phoebe Tv Master + FM (CPH050)",
+	name:		"Askey CPH050/ Phoebe Tv Master + FM",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -456,6 +461,7 @@
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{0, 1, 0x800, 0x400, 0xc00, 0},
 	needs_tvaudio:	1,
+	pll:		PLL_28,
 	tuner_type:	-1,
 },{
 	name:		"Modular Technology MM205 PCTV, bt878",
@@ -472,7 +478,7 @@
 },{
 
 /* ---- card 0x18 ---------------------------------- */
-	name:		"[many vendors] CPH05X/06X (bt878)",
+	name:		"Askey CPH05X/06X (bt878) [many vendors]",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -484,7 +490,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"Terratec/Vobis TV-Boostar",
+	name:		"Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -495,7 +501,7 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"Newer Hauppauge WinCam (bt878)",
+	name:		"Hauppauge WinCam newer (bt878)",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -506,15 +512,15 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"MAXI TV Video PCI2",
-	video_inputs:	3,
-	audio_inputs:	1,
+	name:		"Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
+	video_inputs:	4,
+	audio_inputs:	2,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0xffff,
+	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 1, 2, 3, 0xc00},
-	needs_tvaudio:	1,
+	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
+	pll:            PLL_28,
 	tuner_type:	TUNER_PHILIPS_SECAM,
 },{
 
@@ -543,18 +549,18 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"FlyVideo 98",
-	video_inputs:	3,
+	name:		"Lifeview FlyVideo 98 LR50",
+	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0x1800,  //0x8dfe00
-	muxsel:		{2, 3, 1, 1},
+	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
-	needs_tvaudio:	1,
+	pll:            PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"iProTV",
+	name:		"Formac iProTV",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -566,16 +572,16 @@
 },{
 
 /* ---- card 0x20 ---------------------------------- */
-	name:		"Intel Create and Share PCI",
+	name:		"Intel Create and Share PCI/ Smart Video Recorder III",
 	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
+	audio_inputs:	0,
+	tuner:		-1,
 	svhs:		2,
-	gpiomask:	7,
+	gpiomask:	0,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 4, 4, 4, 4, 4},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	audiomux:	{ 0 },
+	needs_tvaudio:	0,
+	tuner_type:	4,
 },{
 	name:		"Terratec TerraTValue",
 	video_inputs:	3,
@@ -602,34 +608,32 @@
 	tuner_type:	-1,
 	audio_hook:	winfast2000_audio,
 },{
-	name:		"Flyvideo 98 (LR50Q) / Chronos Video Shuttle II",
-	video_inputs:	3,
+	name:		"Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
+	video_inputs:	4,
 	audio_inputs:	3,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
-	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
 
 /* ---- card 0x24 ---------------------------------- */
-	name:		"Flyvideo 98FM (LR50Q) / Typhoon TView TV/FM Tuner",
-	video_inputs:	3,
+	name:		"Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
+	video_inputs:	4,
 	audio_inputs:	3,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	-1,
 	has_radio:	1,
 },{
-	name:		"PixelView PlayTV pro",
+	name:		"Prolink PixelView PlayTV pro",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -641,7 +645,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"TView99 CPH06X",
+	name:		"Askey CPH06X TView99",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -684,7 +688,7 @@
 	audio_inputs:	4,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	12,
+	gpiomask:	15,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 13, 4, 11, 7, 0, 0},
 	needs_tvaudio:	1,
@@ -700,6 +704,7 @@
 	gpiomask:	0,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 0, 0, 0, 0},
+	needs_tvaudio:	1,
 	no_msp34xx:	1,
 	pll:		PLL_28,
 	tuner_type:	1,
@@ -758,9 +763,9 @@
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0x1f0000,
+	gpiomask:	0x70000,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0xe2ffff, 0xebffff, 0, 0, 0xe0ffff, 0xe2ffff },
+	audiomux:	{ 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
 	needs_tvaudio:	1,
 	no_msp34xx:	1,
 	pll:		PLL_35,
@@ -769,7 +774,7 @@
 },{
 
 /* ---- card 0x30 ---------------------------------- */
-	name:		"Dynalink Magic TView ",
+	name:		"Askey CPH03x/ Dynalink Magic TView",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -781,7 +786,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"GV-BCTV3",
+	name:		"IODATA GV-BCTV3/PCI",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -828,6 +833,15 @@
 	gpiomask:       0x03000F,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 1, 0x10001, 0, 0, 10},
+			/* sound path (5 sources):
+			   MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
+				0= ext. Audio IN
+				1= from MUX2
+				2= Mono TV sound from Tuner
+				3= not connected
+			   MUX2 (mask 0x30000):
+				0,2,3= from MSP34xx
+				1= FM stereo Radio from Tuner */
 	needs_tvaudio:  1,
 	pll:            PLL_28,
 	tuner_type:     -1,
@@ -852,7 +866,7 @@
 		options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
 		audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
 		options tuner type=5 */
-	name:		"Lifetec LT 9415 TV (LR90 Rev.F)",
+	name:		"Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -860,17 +874,16 @@
 	gpiomask:	0x18e0,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0x0000,0x0800,0x1000,0x1000,0x18e0 },
-		       /* 0x0000: Tuner normal stereo
+		       /* For cards with tda9820/tda9821:
+			  0x0000: Tuner normal stereo
 			  0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
 			  0x0880: Tuner A2 stereo */
 	pll:		PLL_28,
-	tuner_type:	TUNER_PHILIPS_PAL,
-	audio_hook:	lt9415_audio,
-	has_radio:	1,
+	tuner_type:	-1,
 },{
 	/* Miguel Angel Alvarez <maacruz@navegalia.com>
 	   old Easy TV BT848 version (model CPH031) */
-	name:           "BESTBUY Easy TV (CPH031)",
+	name:           "Askey CPH031/ BESTBUY Easy TV",
 	video_inputs:	4,
 	audio_inputs:   1,
 	tuner:          0,
@@ -885,15 +898,14 @@
 
 /* ---- card 0x38 ---------------------------------- */
 	/* Gordon Heydon <gjheydon@bigfoot.com ('98) */
-	name:           "FlyVideo '98/FM",
-	video_inputs:   3,
+	name:           "Lifeview FlyVideo 98FM LR50",
+	video_inputs:   4,
 	audio_inputs:   3,
 	tuner:          0,
 	svhs:           2,
 	gpiomask:       0x1800,
-	muxsel:         { 2, 3, 0, 1},
+	muxsel:         { 2, 3, 1, 1},
 	audiomux:       { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-	needs_tvaudio:  1,
 	pll:            PLL_28,
 	tuner_type:     5,
 },{
@@ -914,7 +926,7 @@
 	tuner_type:     -1,
 },{
         /* Daniel Herrington <daniel.herrington@home.com> */
-        name:           "Phoebe TV Master Only (No FM) CPH060",
+        name:           "Askey CPH060/ Phoebe TV Master Only (No FM)",
         video_inputs:   3,
         audio_inputs:   1,
         tuner:          0,
@@ -923,11 +935,11 @@
         muxsel:         { 2, 3, 1, 1},
         audiomux:       { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
         needs_tvaudio:  1,
-        pll:            PLL_NONE,
+        pll:            PLL_28,
         tuner_type:     TUNER_TEMIC_4036FY5_NTSC,
 },{
 	/* Matti Mottus <mottus@physic.ut.ee> */
-	name:		"TV Capturer (CPH03X)",
+	name:		"Askey CPH03x TV Capturer",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -944,10 +956,12 @@
 	name:           "Modular Technology MM100PCTV",
 	video_inputs:   2,
 	audio_inputs:   2,
+	tuner:		0,
+	svhs:		-1,
 	gpiomask:       11,
 	muxsel:         { 2, 3, 1, 1},
 	audiomux:       { 2, 0, 0, 1, 8},
-	pll:            PLL_NONE,
+	pll:            PLL_35,
 	tuner_type:     TUNER_TEMIC_PAL,
 
 },{
@@ -968,7 +982,7 @@
 	/* Miguel Angel Alvarez <maacruz@navegalia.com>
 	   new Easy TV BT878 version (model CPH061) 
 	   special thanks to Informatica Mieres for providing the card */
-	name:           "BESTBUY Easy TV (bt878)",
+	name:           "Askey CPH061/ BESTBUY Easy TV (bt878)",
 	video_inputs:	3,
 	audio_inputs:   2,
 	tuner:          0,
@@ -1008,7 +1022,7 @@
 	tuner_type:	TUNER_TEMIC_4006FN5_MULTI_PAL,
 },{
 	/* DeeJay <deejay@westel900.net (2000S) */
-	name:           "FlyVideo 2000S",
+	name:           "Lifeview FlyVideo 2000S LR90",
 	video_inputs:   3,
 	audio_inputs:   3,
 	tuner:          0,
@@ -1016,7 +1030,7 @@
 	gpiomask:	0x18e0,
 	muxsel:		{ 2, 3, 0, 1},
 			/* Radio changed from 1e80 to 0x800 to make
-			   Flyvideo2000S in .hu happy (gm)*/
+			   FlyVideo2000S in .hu happy (gm)*/
 			/* -dk-???: set mute=0x1800 for tda9874h daughterboard */
 	audiomux:	{ 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
 	audio_hook:	fv2000s_audio,
@@ -1040,7 +1054,7 @@
 	has_radio:	1,
 },{
 	/* TANAKA Kei <peg00625@nifty.com> */
-	name:           "GV-BCTV4/PCI",
+	name:           "IODATA GV-BCTV4/PCI",
 	video_inputs:   3,
 	audio_inputs:   1,
 	tuner:          0,
@@ -1084,7 +1098,7 @@
 	gpiomask:       0
 },{
         /* Tomasz Pyra <hellfire@sedez.iq.pl> */
-        name:           "PV-BT878P+",
+        name:           "Prolink Pixelview PV-BT878P+ (Rev.4C)",
         video_inputs:   3,
         audio_inputs:   4,
         tuner:          0,
@@ -1096,7 +1110,7 @@
         pll:            PLL_28,
         tuner_type:     25,
 },{
-	name:		"Flyvideo 98EZ (capture only)",
+	name:		"Lifeview FlyVideo 98EZ (capture only) LR51",
 	video_inputs:	4,
 	audio_inputs:   0,
 	tuner:		-1,
@@ -1108,7 +1122,7 @@
 
 /* ---- card 0x48 ---------------------------------- */
 	/* Dariusz Kowalewski <darekk@automex.pl> */
-	name:		"Prolink PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
+	name:		"Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -1141,8 +1155,8 @@
 	name:           "RemoteVision MX (RV605)",
 	video_inputs:   16,
 	audio_inputs:   0,
-	tuner:          0,
-	svhs:           0,
+	tuner:          -1,
+	svhs:           -1,
 	gpiomask:       0x00,
 	gpiomask2:      0x07ff,
 	muxsel:         { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
@@ -1155,6 +1169,7 @@
         name:           "Powercolor MTV878/ MTV878R/ MTV878F",
         video_inputs:   3,
         audio_inputs:   2, 
+	tuner:		0,
         svhs:           2,
         gpiomask:       0x1C800F,  // Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset
         muxsel:         { 2, 1, 1, },
@@ -1191,15 +1206,42 @@
         pll:            PLL_28,
         tuner_type:     -1,
 },{
-	/* http://www.aopen.com/products/video/va1000.htm */
-	name:           "AOPEN VA1000",
-	video_inputs:   3, /* coax, AV, s-vid */
-	audio_inputs:   1,
-	tuner:          0,
-	tuner_type:     TUNER_LG_PAL, /* actually TP18PSB12P (PAL B/G) */
-	audiomux:       { 2, 0, 0, 0 },
-	muxsel:         { 2, 3, 1, 0 },
-	pll:            PLL_28,
+        name:           "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
+        video_inputs:   4,
+        audio_inputs:   3, 
+        tuner:          0,
+        svhs:           2,
+        gpiomask:       7,
+        muxsel:         { 2, 3, 1, 1 },   // Tuner, SVid, SVHS, SVid to SVHS connector
+        audiomux:       { 0 ,0 ,4, 4,4,4},// Yes, this tuner uses the same audio output for TV and FM radio!
+					  // This card lacks external Audio In, so we mute it on Ext. & Int.
+					  // The PCB can take a sbx1637/sbx1673, wiring unknown.
+					  // This card lacks PCI subsystem ID, sigh.
+					  // audiomux=1: lower volume, 2+3: mute
+					  // btwincap uses 0x80000/0x80003
+        needs_tvaudio:  0,
+        no_msp34xx:     1,
+        pll:            PLL_28,
+        tuner_type:     5, // Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
+			   // radio signal strength indicators work fine.
+	has_radio:		1,
+	/* GPIO Info:
+		GPIO0,1:   HEF4052 A0,A1
+		GPIO2:     HEF4052 nENABLE
+		GPIO3-7:   n.c.
+		GPIO8-13:  IRDC357 data0,5 (data6 n.c. ?) [chip not present on my card]
+		GPIO14,15: ??
+		GPIO16-21: n.c.
+		GPIO22,23: ??
+		??       : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
+},{
+        /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
+        name:           "DSP Design TCVIDEO",
+        video_inputs:   4,
+        svhs:           -1,
+        muxsel:         { 2, 3, 1, 0},
+        pll:            PLL_28,
+        tuner_type:     -1,
 }};
 
 const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
@@ -1289,8 +1331,8 @@
  */
 
 static void flyvideo_gpio(struct bttv *btv)
-{
-	int gpio,outbits;
+{ 
+	int gpio,outbits,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
 	int tuner=-1,ttype;
 	
 	outbits = btread(BT848_GPIO_OUT_EN);
@@ -1299,29 +1341,54 @@
 	gpio=btread(BT848_GPIO_DATA);
 	btwrite(outbits, BT848_GPIO_OUT_EN);
 	// all cards provide GPIO info, some have an additional eeprom
+	// LR50: GPIO coding can be found lower right CP1 .. CP9
+	//       CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1.
+	//       GPIO14-12: n.c.
+	// LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878)
 	
 	// lowest 3 bytes are remote control codes (no handshake needed)
+        // xxxFFF: No remote control chip soldered
+        // xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered 
+	// Note: Some bits are Audio_Mask !
+
 	ttype=(gpio&0x0f0000)>>16;
 	switch(ttype) {
-	case 0: tuner=4; // None
+	case 0x0: tuner=4; // None
 		break;
-	case 4: tuner=5; // Philips PAL
+	case 0x4: tuner=5; // Philips PAL
 		break;
-	case 6: tuner=37; // LG PAL (newer TAPC series)
+	case 0x6: tuner=37; // LG PAL (newer TAPC series)
 		break;
 	case 0xC: tuner=3; // Philips SECAM(+PAL)
 		break;
 	default:
-		printk(KERN_INFO "bttv%d: flyvideo_gpio: unknown tuner type.\n", btv->nr);
+		printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->nr);
 	}
-	
-	printk(KERN_INFO "bttv%d: Flyvideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", 
-	       btv->nr,
-	       gpio&0x400000? "yes":"no",
-	       gpio&0x800000? "yes":"no", tuner, gpio);
-	
-	btv->tuner_type = tuner;
-	btv->has_radio = gpio&0x400000? 1:0; 
+
+	has_remote          =   gpio & 0x800000;
+	has_radio	    =   gpio & 0x400000;
+	//   unknown                   0x200000;
+	//   unknown2                  0x100000;
+        is_capture_only     = !(gpio & 0x008000); //GPIO15
+	has_tda9820_tda9821 = !(gpio & 0x004000);
+	is_lr90             = !(gpio & 0x002000); // else LR26/LR50 (LR38/LR51 f. capture only)
+        //		        gpio & 0x001000 // output bit for audio routing
+
+	printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", 
+	       btv->nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio); 
+	printk(KERN_INFO "bttv%d: FlyVideo  LR90=%s tda9821/tda9820=%s capture_only=%s\n",
+		btv->nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ", 
+		is_capture_only?"yes":"no ");
+
+	if(tuner!= -1) // only set if known tuner autodetected, else let insmod option through
+		btv->tuner_type = tuner;
+	btv->has_radio = has_radio;  
+
+	// LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
+        // LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
+	// Audio options: from tuner, from tda9821/tda9821(mono,stereo.sap), from tda9874, ext., mute
+	if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio;
+	//todo: if(has_tda9874) btv->audio_hook = fv2000s_audio;
 }
 
 int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
@@ -1329,69 +1396,70 @@
 int miro_fmtuner[]  = { 0,0,0,0,   0,0,0,0,  0,0,0,0,  0,0,0,1,
 			1,1,1,1,   1,1,1,0,  0,0,0,0,  0,0,0,0 };
 
+static void miro_pinnacle_gpio(struct bttv *btv)
+{
+	int id,msp;
+	
+	id  = ((btread(BT848_GPIO_DATA)>>10) & 31) -1;
+	msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
+	btv->tuner_type = miro_tunermap[id];
+	if (0 == (btread(BT848_GPIO_DATA) & 0x20)) {
+		btv->has_radio = 1;
+		if (!miro_fmtuner[id]) {
+			btv->has_matchbox = 1;
+			btv->mbox_we    = (1<<6);
+			btv->mbox_most  = (1<<7);
+			btv->mbox_clk   = (1<<8);
+			btv->mbox_data  = (1<<9);
+			btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
+		}
+	} else {
+		btv->has_radio = 0;
+	}
+	if (-1 != msp) {
+		if (btv->type == BTTV_MIRO)
+			btv->type = BTTV_MIROPRO;
+		if (btv->type == BTTV_PINNACLE)
+			btv->type = BTTV_PINNACLEPRO;
+	}
+	printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
+	       btv->nr, id+1, btv->tuner_type,
+	       !btv->has_radio ? "no" :
+	       (btv->has_matchbox ? "matchbox" : "fmtuner"),
+	       (-1 == msp) ? "no" : "yes");
+}
+
 /* initialization part one -- before registering i2c bus */
 void __devinit bttv_init_card1(struct bttv *btv)
 {
         if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878)
                 boot_msp34xx(btv,5);
-	if (btv->type == BTTV_VOODOOTV_FM)
-		boot_msp34xx(btv,20);
+        if (btv->type == BTTV_VOODOOTV_FM)
+                boot_msp34xx(btv,20);
 }
 
-/* initialization part one -- after registering i2c bus */
+/* initialization part two -- after registering i2c bus */
 void __devinit bttv_init_card2(struct bttv *btv)
 {
-	/* miro/pinnacle */
+        btv->tuner_type = -1;
+
+        /* miro/pinnacle */
         if (btv->type == BTTV_MIRO      ||
-	    btv->type == BTTV_MIROPRO   ||
-	    btv->type == BTTV_PINNACLE  ||
-	    btv->type == BTTV_PINNACLEPRO) {
-		int id,msp;
-		id  = ((btread(BT848_GPIO_DATA)>>10) & 31) -1;
-		msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
-		btv->tuner_type = miro_tunermap[id];
-		if (0 == (btread(BT848_GPIO_DATA) & 0x20)) {
-			btv->has_radio = 1;
-			if (!miro_fmtuner[id]) {
-				btv->has_matchbox = 1;
-				btv->mbox_we    = (1<<6);
-				btv->mbox_most  = (1<<7);
-				btv->mbox_clk   = (1<<8);
-				btv->mbox_data  = (1<<9);
-				btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
-			}
-		} else {
-			btv->has_radio = 0;
-		}
-		if (-1 != msp) {
-			if (btv->type == BTTV_MIRO)
-				btv->type = BTTV_MIROPRO;
-			if (btv->type == BTTV_PINNACLE)
-				btv->type = BTTV_PINNACLEPRO;
-		}
-		if (bttv_verbose)
-			printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d "
-			       "radio=%s stereo=%s\n",
-			       btv->nr, id+1, btv->tuner_type,
-			       !btv->has_radio ? "no" :
-				   (btv->has_matchbox ? "matchbox" : "fmtuner"),
-			       (-1 == msp) ? "no" : "yes");
-#if 0
-		if (btv->has_matchbox) {
-			if (bttv_verbose)
-				printk(KERN_INFO "Initializing TEA5757...\n");
-			init_tea5757(btv);
-		}
-#endif
-	}
+            btv->type == BTTV_MIROPRO   ||
+            btv->type == BTTV_PINNACLE  ||
+            btv->type == BTTV_PINNACLEPRO) 
+		miro_pinnacle_gpio(btv);
 
 	if (btv->type == BTTV_FLYVIDEO_98    ||
+	    btv->type == BTTV_LIFE_FLYKIT    ||
 	    btv->type == BTTV_FLYVIDEO       ||
 	    btv->type == BTTV_TYPHOON_TVIEW  ||
 	    btv->type == BTTV_CHRONOS_VS2    ||
 	    btv->type == BTTV_FLYVIDEO_98FM  ||
 	    btv->type == BTTV_FLYVIDEO2000   ||
-	    btv->type == BTTV_FLYVIDEO98EZ)
+	    btv->type == BTTV_FLYVIDEO98EZ   ||
+	    btv->type == BTTV_CONFERENCETV   ||
+	    btv->type == BTTV_LIFETEC_9415)
 		flyvideo_gpio(btv);
 
         if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) {
@@ -1418,13 +1486,6 @@
 		btv->mbox_mask    = 0x38;
 	}
 
-	if (btv->type == BTTV_LIFETEC_9415) {
-		if (btread(BT848_GPIO_DATA) & 0x4000)
-			printk("bttv%d: lifetec: tv mono/fm stereo card\n", btv->nr);
-		else
-			printk("bttv%d: lifetec: stereo(TDA9821) card\n",btv->nr);
-	}
-
 	if (btv->type == BTTV_MAGICTVIEW061) {
 		if(btv->cardid == 0x4002144f) {
 			btv->has_radio=1;
@@ -1465,16 +1526,21 @@
                 }
         }
 
-	/* tuner configuration (from card list / insmod option) */
+	/* tuner configuration (from card list / autodetect / insmod option) */
  	if (-1 != bttv_tvcards[btv->type].tuner_type)
-                btv->tuner_type = bttv_tvcards[btv->type].tuner_type;
+		if( -1 == btv->tuner_type) 
+                	btv->tuner_type = bttv_tvcards[btv->type].tuner_type;
 	if (-1 != tuner[btv->nr])
 		btv->tuner_type = tuner[btv->nr];
 	if (btv->tuner_type != -1)
 		bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
+	printk("bttv%d: using tuner=%d\n",btv->nr,btv->tuner_type);
 
 	if (bttv_tvcards[btv->type].has_radio)
 		btv->has_radio=1;
+
+	if (bttv_tvcards[btv->type].audio_hook)
+		btv->audio_hook=bttv_tvcards[btv->type].audio_hook;
 
 	/* try to detect audio/fader chips */
 	if (!bttv_tvcards[btv->type].no_msp34xx &&
diff -Nru a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
--- a/drivers/media/video/bttv-driver.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/media/video/bttv-driver.c	Tue Jul 16 16:49:43 2002
@@ -80,7 +80,7 @@
 
 
 /* insmod args */
-MODULE_PARM(radio,"1-4i");
+MODULE_PARM(radio,"1-" __MODULE_STRING(BTTV_MAX) "i");
 MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
 MODULE_PARM(bigendian,"i");
 MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
@@ -762,7 +762,7 @@
 	btand(~(3<<5), BT848_IFORM);
 	schedule_timeout(HZ/10);
 #endif
-        
+
 	if (input==bttv_tvcards[btv->type].svhs)  {
 		btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
 		btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
@@ -789,10 +789,11 @@
 static int
 audio_mux(struct bttv *btv, int mode)
 {
-	int val,mux;
+	int val,mux,i2c_mux,signal;
 	
 	btaor(bttv_tvcards[btv->type].gpiomask,
 	      ~bttv_tvcards[btv->type].gpiomask,BT848_GPIO_OUT_EN);
+	signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
 
 	switch (mode) {
 	case AUDIO_MUTE:
@@ -808,16 +809,19 @@
 		btv->audio &= AUDIO_MUTE;
 		btv->audio |= mode;
 	}
-	dprintk("bttv%d: audio mux: mode=%d audio=%d\n",
-		btv->nr,mode,btv->audio);
+	i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio;
+	if (btv->opt_automute && !signal && !btv->radio_user)
+		mux = AUDIO_OFF;
+	printk("bttv%d: amux: mode=%d audio=%d signal=%s mux=%d/%d irq=%s\n",
+	       btv->nr, mode, btv->audio, signal ? "yes" : "no",
+	       mux, i2c_mux, in_interrupt() ? "yes" : "no");
 
-	mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio;
 	val = bttv_tvcards[btv->type].audiomux[mux];
 	btaor(val,~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
 	if (bttv_gpio)
 		bttv_gpio_tracking(btv,audio_modes[mux]);
 	if (!in_interrupt())
-		bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(mux));
+		bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(i2c_mux));
 	return 0;
 }
 
@@ -830,6 +834,8 @@
 	c.norm    = btv->tvnorm;
 	c.channel = btv->input;
 	bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
+	if (btv->type == BTTV_VOODOOTV_FM)
+		bttv_tda9880_setnorm(btv,c.norm);
 }
 
 static int
@@ -931,8 +937,8 @@
 	if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) {
 		memset(&va,0,sizeof(va));
 		bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-		if (bttv_tvcards[btv->type].audio_hook)
-			bttv_tvcards[btv->type].audio_hook(btv,&va,0);
+		if (btv->audio_hook)
+			btv->audio_hook(btv,&va,0);
 	}
 	switch (c->id) {
 	case V4L2_CID_BRIGHTNESS:
@@ -998,8 +1004,8 @@
 	if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) {
 		memset(&va,0,sizeof(va));
 		bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-		if (bttv_tvcards[btv->type].audio_hook)
-			bttv_tvcards[btv->type].audio_hook(btv,&va,0);
+		if (btv->audio_hook)
+			btv->audio_hook(btv,&va,0);
 	}
 	switch (c->id) {
 	case V4L2_CID_BRIGHTNESS:
@@ -1069,8 +1075,8 @@
 	}
 	if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) {
 		bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
-		if (bttv_tvcards[btv->type].audio_hook)
-			bttv_tvcards[btv->type].audio_hook(btv,&va,1);
+		if (btv->audio_hook)
+			btv->audio_hook(btv,&va,1);
 	}
 	return 0;
 }
@@ -1161,35 +1167,6 @@
 	return retval;
 }
 
-static void
-bttv_stop_streaming(struct bttv *btv, struct bttv_fh *fh)
-{
-	unsigned long flags;
-	int i;
-
-	/* remove queued buffers from list */
-	spin_lock_irqsave(&btv->s_lock,flags);
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (NULL == fh->bufs[i])
-			continue;
-		if (fh->bufs[i]->vb.state == STATE_QUEUED) {
-			list_del(&fh->bufs[i]->vb.queue);
-			fh->bufs[i]->vb.state = STATE_ERROR;
-		}
-	}
-	spin_unlock_irqrestore(&btv->s_lock,flags);
-
-	/* free all buffers + clear queue */
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (NULL == fh->bufs[i])
-			continue;
-		bttv_dma_free(fh->btv,fh->bufs[i]);
-	}
-	INIT_LIST_HEAD(&fh->stream);
-	free_btres(btv,fh,RESOURCE_STREAMING);
-	bttv_field_count(btv);
-}
-
 /* ----------------------------------------------------------------------- */
 /* video4linux (1) interface                                               */
 
@@ -1218,26 +1195,28 @@
 		buf->vb.size = (width * height * fmt->depth) >> 3;
 		if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
 			return -EINVAL;
+		field = bttv_buffer_field(btv, field, VBUF_FIELD_EVEN,
+					  btv->tvnorm, height);
 	}
-
+	
 	/* alloc + fill struct bttv_buffer (if changed) */
 	if (buf->vb.width != width || buf->vb.height != height ||
+	    buf->vb.field != field ||
 	    buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
 		buf->vb.width  = width;
 		buf->vb.height = height;
+		buf->vb.field  = field;
 		buf->tvnorm    = btv->tvnorm;
 		buf->fmt       = fmt;
 		redo_dma_risc = 1;
 	}
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
-		field = bttv_buffer_field(btv, field, VBUF_FIELD_EVEN,
-					  btv->tvnorm, height);
-		if (field != buf->vb.field)
-			redo_dma_risc = 1;
+#if 0
+	if (STATE_NEEDS_INIT == buf->vb.state)
 		if (redo_dma_risc)
 			bttv_dma_free(btv,buf);
 	}
+#endif
 
 	/* alloc risc memory */
 	if (STATE_NEEDS_INIT == buf->vb.state) {
@@ -1258,18 +1237,55 @@
 	return rc;
 }
 
-static void
-bttv_queue_buffer(struct bttv *btv, struct bttv_buffer *buf)
+static int
+buffer_setup(struct file *file, int *count, int *size)
 {
-	unsigned long flags;
+	struct bttv_fh *fh = file->private_data;
 	
+	*size = fh->buf.fmt->depth*fh->buf.vb.width*fh->buf.vb.height >> 3;
+	if (0 == *count)
+		*count = gbuffers;
+	while (*size * *count > gbuffers * gbufsize)
+		(*count)--;
+	return 0;
+}
+
+static int
+buffer_prepare(struct file *file, struct videobuf_buffer *vb, int field)
+{
+	struct bttv_buffer *buf = (struct bttv_buffer*)vb;
+	struct bttv_fh *fh = file->private_data;
+
+	return bttv_prepare_buffer(fh->btv,buf,fh->buf.fmt,
+				   fh->buf.vb.width,fh->buf.vb.height,field);
+}
+
+static void
+buffer_queue(struct file *file, struct videobuf_buffer *vb)
+{
+	struct bttv_buffer *buf = (struct bttv_buffer*)vb;
+	struct bttv_fh *fh = file->private_data;
+
 	buf->vb.state = STATE_QUEUED;
-	spin_lock_irqsave(&btv->s_lock,flags);
-	list_add_tail(&buf->vb.queue,&btv->capture);
-	bttv_set_dma(btv, 0x03, 1);
-	spin_unlock_irqrestore(&btv->s_lock,flags);
+	list_add_tail(&buf->vb.queue,&fh->btv->capture);
+	bttv_set_dma(fh->btv, 0x03, 1);
 }
 
+static void buffer_release(struct file *file, struct videobuf_buffer *vb)
+{
+	struct bttv_buffer *buf = (struct bttv_buffer*)vb;
+	struct bttv_fh *fh = file->private_data;
+
+	bttv_dma_free(fh->btv,buf);
+}
+
+static struct videobuf_queue_ops bttv_qops = {
+	buf_setup:    buffer_setup,
+	buf_prepare:  buffer_prepare,
+	buf_queue:    buffer_queue,
+	buf_release:  buffer_release,
+};
+
 static const char *v4l1_ioctls[] = {
 	"?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
 	"CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
@@ -1413,8 +1429,8 @@
 		bttv_call_i2c_clients(btv,cmd,v);
 
 		/* card specific hooks */
-		if (bttv_tvcards[btv->type].audio_hook)
-			bttv_tvcards[btv->type].audio_hook(btv,v,0);
+		if (btv->audio_hook)
+			btv->audio_hook(btv,v,0);
 
 		up(&btv->lock);
 		return 0;
@@ -1432,8 +1448,8 @@
 		bttv_call_i2c_clients(btv,cmd,v);
 
 		/* card specific hooks */
-		if (bttv_tvcards[btv->type].audio_hook)
-			bttv_tvcards[btv->type].audio_hook(btv,v,1);
+		if (btv->audio_hook)
+			btv->audio_hook(btv,v,1);
 		
 		up(&btv->lock);
 		return 0;
@@ -1533,8 +1549,8 @@
 			struct video_audio va;
 			memset(&va, 0, sizeof(struct video_audio));
 			bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-			if (bttv_tvcards[btv->type].audio_hook)
-				bttv_tvcards[btv->type].audio_hook(btv,&va,0);
+			if (btv->audio_hook)
+				btv->audio_hook(btv,&va,0);
 			if(va.mode & VIDEO_SOUND_STEREO)
 				t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
 			if(va.mode & VIDEO_SOUND_LANG1)
@@ -1564,8 +1580,8 @@
 			else if (t->audmode == V4L2_TUNER_MODE_LANG2)
 				va.mode = VIDEO_SOUND_LANG2;
 			bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
-			if (bttv_tvcards[btv->type].audio_hook)
-				bttv_tvcards[btv->type].audio_hook(btv,&va,1);
+			if (btv->audio_hook)
+				btv->audio_hook(btv,&va,1);
 		}
 		up(&btv->lock);
 		return 0;
@@ -1616,7 +1632,7 @@
 				      clips, n);
 	bttv_sort_clips(clips,nclips);
 	
-	down(&fh->lock);
+	down(&fh->q.lock);
 	if (fh->ov.clips)
 		kfree(fh->ov.clips);
 	fh->ov.clips   = clips;
@@ -1634,27 +1650,20 @@
 	if (check_btres(fh, RESOURCE_OVERLAY)) {
 		struct bttv_buffer *new;
 		
-		new = videobuf_alloc(sizeof(*new),V4L2_BUF_TYPE_CAPTURE);
+		new = videobuf_alloc(sizeof(*new));
 		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
 		retval = bttv_switch_overlay(btv,fh,new);
 	}
-	up(&fh->lock);
+	up(&fh->q.lock);
 	return retval;
 }
 
-static void release_buffer(struct file *file, struct videobuf_buffer *vb)
-{
-	struct bttv_buffer *buf = (struct bttv_buffer*)vb;
-	struct bttv_fh *fh = file->private_data;
-
-	bttv_dma_free(fh->btv,buf);
-}
-
 static int bttv_do_ioctl(struct inode *inode, struct file *file,
 			 unsigned int cmd, void *arg)
 {
 	struct bttv_fh *fh  = file->private_data;
 	struct bttv    *btv = fh->btv;
+	unsigned long flags;
 	int retval;
 
 	if (bttv_debug > 1) {
@@ -1723,7 +1732,7 @@
 		fmt = format_by_palette(pic->palette);
 		if (NULL == fmt)
 			return -EINVAL;
-		down(&fh->lock);
+		down(&fh->q.lock);
 		retval = -EINVAL;
 		if (fmt->depth != pic->depth && !sloppy)
 			goto fh_unlock_and_return;
@@ -1744,7 +1753,7 @@
 		bt848_contrast(btv,pic->contrast);
 		bt848_hue(btv,pic->hue);
 		bt848_sat(btv,pic->colour);
-		up(&fh->lock);
+		up(&fh->q.lock);
                 return 0;
 	}
 
@@ -1796,7 +1805,7 @@
 			fbuf->height * fbuf->bytesperline;
 		if (0 == find_videomem((unsigned long)fbuf->base,end))
 			return -EINVAL;
-		down(&fh->lock);
+		down(&fh->q.lock);
 		retval = -EINVAL;
 		if (sloppy) {
 			/* also set the default palette -- for backward
@@ -1836,7 +1845,7 @@
 				goto fh_unlock_and_return;
 		}
 		btv->fbuf = *fbuf;
-		up(&fh->lock);
+		up(&fh->q.lock);
 		return 0;
 	}
 
@@ -1863,11 +1872,10 @@
 		if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
 			return -EBUSY;
 		
-		down(&fh->lock);
+		down(&fh->q.lock);
 		if (*on) {
 			fh->ov.tvnorm = btv->tvnorm;
-			new = videobuf_alloc(sizeof(*new),
-					     V4L2_BUF_TYPE_CAPTURE);
+			new = videobuf_alloc(sizeof(*new));
 			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
 		} else {
 			new = NULL;
@@ -1875,7 +1883,7 @@
 
 		/* switch over */
 	        retval = bttv_switch_overlay(btv,fh,new);
-		up(&fh->lock);
+		up(&fh->q.lock);
 		return retval;
 	}
 
@@ -1886,12 +1894,8 @@
 
 		if (!mmap)
 			return -EINVAL;
-		down(&fh->lock);
-		retval = videobuf_mmap_setup
-			(file,(struct videobuf_buffer**)fh->bufs,
-			 sizeof(struct bttv_buffer),
-			 gbuffers,gbufsize,V4L2_BUF_TYPE_CAPTURE,
-			 release_buffer);
+		down(&fh->q.lock);
+		retval = videobuf_mmap_setup(file,&fh->q,gbuffers,gbufsize);
 		if (retval < 0)
 			goto fh_unlock_and_return;
 		memset(mbuf,0,sizeof(*mbuf));
@@ -1899,7 +1903,7 @@
 		mbuf->size   = gbuffers * gbufsize;
 		for (i = 0; i < gbuffers; i++)
 			mbuf->offsets[i] = i * gbufsize;
-		up(&fh->lock);
+		up(&fh->q.lock);
 		return 0;
 	}
 	case VIDIOCMCAPTURE:
@@ -1910,9 +1914,9 @@
 		if (vm->frame >= VIDEO_MAX_FRAME)
 			return -EINVAL;
 
-		down(&fh->lock);
+		down(&fh->q.lock);
 		retval = -EINVAL;
-		buf = fh->bufs[vm->frame];
+		buf = (struct bttv_buffer *)fh->q.bufs[vm->frame];
 		if (NULL == buf)
 			goto fh_unlock_and_return;
 		if (0 == buf->vb.baddr)
@@ -1926,8 +1930,10 @@
 					     vm->width,vm->height,0);
 		if (0 != retval)
 			goto fh_unlock_and_return;
-		bttv_queue_buffer(btv,buf);
-		up(&fh->lock);
+		spin_lock_irqsave(&btv->s_lock,flags);
+		buffer_queue(file,&buf->vb);
+		spin_unlock_irqrestore(&btv->s_lock,flags);
+		up(&fh->q.lock);
 		return 0;
 	}
 	case VIDIOCSYNC:
@@ -1938,9 +1944,9 @@
 		if (*frame >= VIDEO_MAX_FRAME)
 			return -EINVAL;
 
-		down(&fh->lock);
+		down(&fh->q.lock);
 		retval = -EINVAL;
-		buf = fh->bufs[*frame];
+		buf = (struct bttv_buffer *)fh->q.bufs[*frame];
 		if (NULL == buf)
 			goto fh_unlock_and_return;
 		retval = videobuf_waiton(&buf->vb,0,1);
@@ -1958,7 +1964,7 @@
 			retval = -EINVAL;
 			break;
 		}
-		up(&fh->lock);
+		up(&fh->q.lock);
 		return retval;
 	}
 
@@ -2056,7 +2062,7 @@
 			/* FIXME -- not implemented yet */
 			return -EINVAL;
 
-		down(&fh->lock);
+		down(&fh->q.lock);
 		/* fixup format */
 		if (f->fmt.pix.width  > bttv_tvnorms[btv->tvnorm].swidth)
 			f->fmt.pix.width = bttv_tvnorms[btv->tvnorm].swidth;
@@ -2087,7 +2093,7 @@
 		f->fmt.pix.depth = fmt->depth;
 		f->fmt.pix.sizeimage =
 			(fh->buf.vb.width * fh->buf.vb.height * fmt->depth)/8;
-		up(&fh->lock);
+		up(&fh->q.lock);
 		return 0;
 	}
 
@@ -2130,7 +2136,7 @@
 		if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
 			return -EINVAL;
 
-		down(&fh->lock);
+		down(&fh->q.lock);
 		retval = -EINVAL;
 		if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
 			if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
@@ -2167,13 +2173,12 @@
 			if (check_btres(fh, RESOURCE_OVERLAY)) {
 				struct bttv_buffer *new;
 		
-				new = videobuf_alloc(sizeof(*new),
-						     V4L2_BUF_TYPE_CAPTURE);
+				new = videobuf_alloc(sizeof(*new));
 				bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
 				retval = bttv_switch_overlay(btv,fh,new);
 			}
 		}
-		up(&fh->lock);
+		up(&fh->q.lock);
 		return retval;
 	}
 	case VIDIOC_G_WIN:
@@ -2198,154 +2203,32 @@
 	}
 
 	case VIDIOC_REQBUFS:
-	{
-		struct v4l2_requestbuffers *req = arg;
-		int size,count;
-
 		if (!mmap)
 			return -EINVAL;
-		if ((req->type & V4L2_BUF_TYPE_field) != V4L2_BUF_TYPE_CAPTURE)
-			return -EINVAL;
-		if (req->count < 0)
-			return -EINVAL;
+		return videobuf_reqbufs(file,&fh->q,arg);
 
-		down(&fh->lock);
-		retval = -EINVAL;
-		if (NULL == fh->buf.fmt    ||
-		    0 == fh->buf.vb.width  ||
-		    0 == fh->buf.vb.height)
-			goto fh_unlock_and_return;
-
-		size = (fh->buf.vb.width*fh->buf.vb.height*fh->buf.fmt->depth) >> 3;
-		size = (size + PAGE_SIZE - 1) & PAGE_MASK;
-		count = req->count;
-		if (count > VIDEO_MAX_FRAME)
-			count = VIDEO_MAX_FRAME;
-		while (size * count > gbuffers * gbufsize)
-			count--;
-		retval = videobuf_mmap_setup(file,
-					     (struct videobuf_buffer**)fh->bufs,
-					     sizeof(struct bttv_buffer),
-					     count,size,V4L2_BUF_TYPE_CAPTURE,
-					     release_buffer);
-		if (retval < 0)
-			goto fh_unlock_and_return;
-		req->type  = V4L2_BUF_TYPE_CAPTURE;
-		req->count = count;
-		up(&fh->lock);
-		return 0;
-	}
 	case VIDIOC_QUERYBUF:
-	{
-		struct v4l2_buffer *b = arg;
+		return videobuf_querybuf(&fh->q,arg);
 
-		if ((b->type & V4L2_BUF_TYPE_field) != V4L2_BUF_TYPE_CAPTURE)
-			return -EINVAL;
-		if (b->index < 0 || b->index > VIDEO_MAX_FRAME)
-			return -EINVAL;
-		if (NULL == fh->bufs[b->index])
-			return -EINVAL;
-		videobuf_status(b,&fh->bufs[b->index]->vb);
-		return 0;
-	}
 	case VIDIOC_QBUF:
-	{
-		struct v4l2_buffer *b = arg;
-		struct bttv_buffer *buf;
-		int field = 0;
-
-		if ((b->type & V4L2_BUF_TYPE_field) != V4L2_BUF_TYPE_CAPTURE)
-			return -EINVAL;
-		if (b->index < 0 || b->index > VIDEO_MAX_FRAME)
-			return -EINVAL;
+		return videobuf_qbuf(file,&fh->q,arg);
 
-		down(&fh->lock);
-		retval = -EINVAL;
-		buf = fh->bufs[b->index];
-		if (NULL == buf)
-			goto fh_unlock_and_return;
-		if (0 == buf->vb.baddr)
-			goto fh_unlock_and_return;
-		if (buf->vb.state == STATE_QUEUED ||
-		    buf->vb.state == STATE_ACTIVE)
-			goto fh_unlock_and_return;
-
-		if (b->flags & V4L2_BUF_FLAG_TOPFIELD)
-			field |= VBUF_FIELD_ODD;
-		if (b->flags & V4L2_BUF_FLAG_BOTFIELD)
-		        field |= VBUF_FIELD_EVEN;
-		retval = bttv_prepare_buffer(btv,buf,fh->buf.fmt,
-					     fh->buf.vb.width,fh->buf.vb.height,field);
-		if (0 != retval)
-			goto fh_unlock_and_return;
-
-		list_add_tail(&buf->vb.stream,&fh->stream);
-		if (check_btres(fh, RESOURCE_STREAMING))
-			bttv_queue_buffer(btv,buf);
-		up(&fh->lock);
-		return 0;
-	}
 	case VIDIOC_DQBUF:
-	{
-		struct v4l2_buffer *b = arg;
-		struct bttv_buffer *buf;
+		return videobuf_dqbuf(file,&fh->q,arg);
 
-		if ((b->type & V4L2_BUF_TYPE_field) != V4L2_BUF_TYPE_CAPTURE)
-			return -EINVAL;
-
-		down(&fh->lock);
-		retval = -EINVAL;
-		if (list_empty(&fh->stream))
-			goto fh_unlock_and_return;
-		buf = list_entry(fh->stream.next, struct bttv_buffer, vb.stream);
-		retval = videobuf_waiton(&buf->vb,0,1);
-		if (retval < 0)
-			goto fh_unlock_and_return;
-		switch (buf->vb.state) {
-		case STATE_ERROR:
-			retval = -EIO;
-			/* fall through */
-		case STATE_DONE:
-			videobuf_dma_pci_sync(btv->dev,&buf->vb.dma);
-			buf->vb.state = STATE_IDLE;
-			break;
-		default:
-			retval = -EINVAL;
-			goto fh_unlock_and_return;
-		}
-		list_del(&buf->vb.stream);
-		memset(b,0,sizeof(*b));
-		videobuf_status(b,&buf->vb);
-		up(&fh->lock);
-		return retval;
-	}
 	case VIDIOC_STREAMON:
-	{
-		struct list_head *list;
-		struct bttv_buffer *buf;
-		
 		if (!check_alloc_btres(btv,fh,RESOURCE_STREAMING))
 			return -EBUSY;
 		bttv_field_count(btv);
-		down(&fh->lock);
-		list_for_each(list,&fh->stream) {
-			buf = list_entry(list, struct bttv_buffer, vb.stream);
-			if (buf->vb.state == STATE_PREPARED)
-				bttv_queue_buffer(btv,buf);
-		}
-		up(&fh->lock);
-		return 0;
-	}
+		return videobuf_streamon(file,&fh->q);
+
 	case VIDIOC_STREAMOFF:
-	{
-		down(&fh->lock);
-		retval = -EINVAL;
-		if (!check_btres(fh, RESOURCE_STREAMING))
-			goto fh_unlock_and_return;
-		bttv_stop_streaming(btv,fh);
-		up(&fh->lock);
+		retval = videobuf_streamoff(file,&fh->q);
+		if (retval < 0)
+			return retval;
+		free_btres(btv,fh,RESOURCE_STREAMING);
+		bttv_field_count(btv);
 		return 0;
-	}
 
 	case VIDIOC_QUERYCTRL:
 	{
@@ -2370,8 +2253,8 @@
 			struct video_audio va;
 			memset(&va,0,sizeof(va));
 			bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-			if (bttv_tvcards[btv->type].audio_hook)
-				bttv_tvcards[btv->type].audio_hook(btv,&va,0);
+			if (btv->audio_hook)
+				btv->audio_hook(btv,&va,0);
 			switch (bttv_ctls[i].id) {
 			case V4L2_CID_AUDIO_VOLUME:
 				if (!(va.flags & VIDEO_AUDIO_VOLUME))
@@ -2428,7 +2311,7 @@
 	return 0;
 
  fh_unlock_and_return:
-	up(&fh->lock);
+	up(&fh->q.lock);
 	return retval;
 }
 
@@ -2438,23 +2321,7 @@
 	return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
 }
 
-/* start capture to a kernel bounce buffer */
-static int bttv_read_capture(struct bttv_fh *fh)
-{
-	struct bttv *btv = fh->btv;
-	int rc;
-	
-	dprintk("bttv%d: read start\n",btv->nr);
-	rc = bttv_prepare_buffer(btv,&fh->read_buf,fh->buf.fmt,
-				 fh->buf.vb.width,fh->buf.vb.height,0);
-	if (0 != rc)
-		return rc;
-
-	bttv_queue_buffer(btv,&fh->read_buf);
-	fh->read_off = 0;
-	return 0;
-}
-
+#if 0
 /*
  * blocking read for a complete video frame
  * => no kernel bounce buffer needed.
@@ -2467,87 +2334,42 @@
 
         /* setup stuff */
 	dprintk("bttv%d: read zerocopy\n",btv->nr);
-        fh->read_buf.vb.baddr = (unsigned long)data;
-        fh->read_buf.vb.bsize = count;
-        rc = bttv_prepare_buffer(btv,&fh->read_buf,fh->buf.fmt,
+        fh->q.read_buf->baddr = (unsigned long)data;
+        fh->q.read_buf->bsize = count;
+        rc = bttv_prepare_buffer(btv,fh->q.read_buf,fh->buf.fmt,
 				 fh->buf.vb.width,fh->buf.vb.height,0);
         if (0 != rc)
 		goto done;
 	
         /* start capture & wait */
-        bttv_queue_buffer(btv,&fh->read_buf);
-        rc = videobuf_waiton(&fh->read_buf.vb,0,1);
+        bttv_queue_buffer(btv,fh->q.read_buf);
+        rc = videobuf_waiton(fh->q.read_buf,0,1);
         if (0 == rc) {
-		videobuf_dma_pci_sync(btv->dev,&fh->read_buf.vb.dma);
-                rc = fh->read_buf.vb.size;
+		videobuf_dma_pci_sync(btv->dev,&fh->q.read_buf->dma);
+                rc = fh->q.read_buf->size;
 	}
 
  done:
 	/* cleanup */
-	bttv_dma_free(btv,&fh->read_buf);
-	fh->read_buf.vb.baddr = 0;
-	fh->read_buf.vb.size = 0;
+	bttv_dma_free(btv,fh->q.read_buf);
+	fh->q.read_buf->baddr = 0;
+	fh->q.read_buf->size = 0;
 	return rc;
 }
+#endif
 
 
 static ssize_t bttv_read(struct file *file, char *data,
 			 size_t count, loff_t *ppos)
 {
 	struct bttv_fh *fh = file->private_data;
-	struct bttv *btv = fh->btv;
-	int rc, bytes, size;
 
-	if (btv->errors)
-		bttv_reinit_bt848(btv);
-	if (locked_btres(btv,RESOURCE_STREAMING))
+	if (fh->btv->errors)
+		bttv_reinit_bt848(fh->btv);
+	if (locked_btres(fh->btv,RESOURCE_STREAMING))
 		return -EBUSY;
 
-	down(&fh->lock);
-	size = fh->buf.fmt->depth*fh->buf.vb.width*fh->buf.vb.height >> 3;
-	if (-1 == fh->read_off  &&  count >= size  &&
-	    !(file->f_flags & O_NONBLOCK)) {
-		rc = bttv_read_zerocopy(fh,btv,data,count,ppos);
-		if (rc >= 0)
-			/* ok, all done */
-			goto unlock_out;
-		/* fallback to kernel bounce buffer on failures */
-	}
-	
-	if (-1 == fh->read_off) {
-		/* need to capture a new frame */
-		rc = bttv_read_capture(fh);
-		if (0 != rc)
-			goto unlock_out;
-	}
-
-	/* wait until capture is done */
-        rc = videobuf_waiton(&fh->read_buf.vb, file->f_flags & O_NONBLOCK,1);
-	if (0 != rc)
-		goto unlock_out;
-
-	/* copy to userspace */
-	bytes = count;
-	if (bytes > fh->read_buf.vb.size - fh->read_off)
-		bytes = fh->read_buf.vb.size - fh->read_off;
-	rc = -EFAULT;
-	if (copy_to_user(data,fh->read_buf.vb.dma.vmalloc +
-			 fh->read_off,bytes))
-		goto unlock_out;
-
-	rc = bytes;
-	fh->read_off += bytes;
-	dprintk("bttv%d: read %d bytes\n",btv->nr,bytes);
-	if (fh->read_off == fh->read_buf.vb.size) {
-		/* all data copied, cleanup */
-		dprintk("bttv%d: read done\n",btv->nr);
-		bttv_dma_free(btv,&fh->read_buf);
-		fh->read_off = -1;
-	}
-
- unlock_out:
-	up(&fh->lock);
-	return rc;
+	return videobuf_read_one(file, &fh->q, data, count, ppos);
 }
 
 static unsigned int bttv_poll(struct file *file, poll_table *wait)
@@ -2555,24 +2377,34 @@
 	struct bttv_fh *fh = file->private_data;
 	struct bttv_buffer *buf;
 
-	if (check_alloc_btres(fh->btv,fh,RESOURCE_STREAMING)) {
+	if (check_btres(fh,RESOURCE_STREAMING)) {
 		/* streaming capture */
-		if (list_empty(&fh->stream))
+		if (list_empty(&fh->q.stream))
 			return POLLERR;
-		buf = list_entry(fh->stream.next,struct bttv_buffer,vb.stream);
+		buf = list_entry(fh->q.stream.next,struct bttv_buffer,vb.stream);
 	} else {
 		/* read() capture */
-		down(&fh->lock);
-		if (-1 == fh->read_off) {
+		down(&fh->q.lock);
+		if (NULL == fh->q.read_buf) {
 			/* need to capture a new frame */
-			if (locked_btres(fh->btv,RESOURCE_STREAMING) ||
-			    0 != bttv_read_capture(fh)) {
-				up(&fh->lock);
+			if (locked_btres(fh->btv,RESOURCE_STREAMING)) {
+				up(&fh->q.lock);
+				return POLLERR;
+			}
+			fh->q.read_buf = videobuf_alloc(fh->q.msize);
+			if (NULL == fh->q.read_buf) {
+				up(&fh->q.lock);
+				return POLLERR;
+			}
+			if (0 != fh->q.ops->buf_prepare(file,fh->q.read_buf,0)) {
+				up(&fh->q.lock);
 				return POLLERR;
 			}
+			fh->q.ops->buf_queue(file,fh->q.read_buf);
+			fh->q.read_off = 0;
 		}
-		up(&fh->lock);
-		buf = &fh->read_buf;
+		up(&fh->q.lock);
+		buf = (struct bttv_buffer*)fh->q.read_buf;
 	}
 	
 	poll_wait(file, &buf->vb.done, wait);
@@ -2608,11 +2440,9 @@
 		return -ENOMEM;
 	file->private_data = fh;
 	*fh = btv->init;
-        init_MUTEX(&fh->lock);
-	INIT_LIST_HEAD(&fh->stream);
-	init_waitqueue_head(&fh->read_buf.vb.done);
-	fh->read_off = -1;
-
+	videobuf_queue_init(&fh->q, &bttv_qops, btv->dev, &btv->s_lock,
+			    V4L2_BUF_TYPE_CAPTURE,sizeof(struct bttv_buffer));
+	
 	i2c_vidiocschan(btv);
         return 0;
 }
@@ -2625,9 +2455,15 @@
 	/* turn off overlay, stop outstanding captures */
 	if (check_btres(fh, RESOURCE_OVERLAY))
 		bttv_switch_overlay(btv,fh,NULL);
-	if (check_btres(fh, RESOURCE_STREAMING))
-		bttv_stop_streaming(btv,fh);
-	bttv_dma_free(btv,&fh->read_buf);
+	if (check_btres(fh, RESOURCE_STREAMING)) {
+		videobuf_streamoff(file,&fh->q);
+		free_btres(btv,fh,RESOURCE_STREAMING);
+		bttv_field_count(btv);
+	}
+	if (fh->q.read_buf) {
+		buffer_release(file,fh->q.read_buf);
+		kfree(fh->q.read_buf);
+	}
 
 	file->private_data = NULL;
 	kfree(fh);
@@ -2638,14 +2474,12 @@
 bttv_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct bttv_fh *fh = file->private_data;
-	int err;
 
 	if (!mmap)
 		return -EINVAL;
-	down(&fh->lock);
-	err = videobuf_mmap_mapper(vma,(struct videobuf_buffer**)fh->bufs);
-	up(&fh->lock);
-	return err;
+	dprintk("mmap 0x%lx+%ld\n",vma->vm_start,
+		vma->vm_end - vma->vm_start);
+	return videobuf_mmap_mapper(vma,&fh->q);
 }
 
 static struct file_operations bttv_fops =
@@ -2786,7 +2620,7 @@
 static struct video_device radio_template =
 {
 	name:     "bt848/878 radio",
-	type:     VID_TYPE_TUNER|VID_TYPE_TELETEXT,
+	type:     VID_TYPE_TUNER,
 	hardware: VID_HARDWARE_BT848,
 	fops:     &radio_fops,
 	minor:    -1,
@@ -3075,12 +2909,8 @@
                 if ((astat & BT848_INT_RISCI)  &&  (stat & (1<<28)))
 			bttv_irq_switch_fields(btv);
 
-		if ((astat & BT848_INT_HLOCK)  &&  btv->opt_automute) {
-			if ((dstat & BT848_DSTATUS_HLOC) || btv->radio_user)
-				audio_mux(btv, AUDIO_UNMUTE);
-			else
-				audio_mux(btv, AUDIO_MUTE);
-		}
+		if ((astat & BT848_INT_HLOCK)  &&  btv->opt_automute)
+			audio_mux(btv, -1);
 
 		if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
 			printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->nr,
@@ -3175,9 +3005,8 @@
         init_waitqueue_head(&btv->gpioq);
         INIT_LIST_HEAD(&btv->capture);
         INIT_LIST_HEAD(&btv->vcapture);
-
-        init_MUTEX(&btv->vbi.lock);
-	INIT_LIST_HEAD(&btv->vbi.stream);
+	videobuf_queue_init(&btv->vbi.q, &vbi_qops, btv->dev, &btv->s_lock,
+			    V4L2_BUF_TYPE_VBI,sizeof(struct bttv_buffer));
 
 	btv->timeout.function = bttv_irq_timeout;
 	btv->timeout.data     = (unsigned long)btv;
diff -Nru a/drivers/media/video/bttv-vbi.c b/drivers/media/video/bttv-vbi.c
--- a/drivers/media/video/bttv-vbi.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/media/video/bttv-vbi.c	Tue Jul 16 16:49:43 2002
@@ -69,8 +69,21 @@
 	return 0;
 }
 
-static int vbi_buffer_prepare(struct bttv *btv, struct bttv_buffer *buf)
+static int vbi_buffer_setup(struct file *file, int *count, int *size)
 {
+	struct bttv *btv = file->private_data;
+
+	if (0 == *count)
+		*count = vbibufs;
+	*size = btv->vbi.lines * 2 * 2048;
+	return 0;
+}
+
+static int vbi_buffer_prepare(struct file *file, struct videobuf_buffer *vb,
+			      int fields)
+{
+	struct bttv *btv = file->private_data;
+	struct bttv_buffer *buf = (struct bttv_buffer*)vb;
 	int rc;
 	
 	buf->vb.size = btv->vbi.lines * 2 * 2048;
@@ -84,7 +97,8 @@
 			goto fail;
 	}
 	buf->vb.state = STATE_PREPARED;
-	dprintk("buf prepare ok: odd=%p even=%p\n",&buf->odd,&buf->even);
+	dprintk("buf prepare %p: odd=%p even=%p\n",
+		vb,&buf->odd,&buf->even);
 	return 0;
 
  fail:
@@ -93,94 +107,35 @@
 }
 
 static void
-vbi_buffer_queue(struct bttv *btv, struct bttv_buffer *buf)
+vbi_buffer_queue(struct file *file, struct videobuf_buffer *vb)
 {
-	unsigned long flags;
+	struct bttv *btv = file->private_data;
+	struct bttv_buffer *buf = (struct bttv_buffer*)vb;
 	
+	dprintk("queue %p\n",vb);
 	buf->vb.state = STATE_QUEUED;
-	spin_lock_irqsave(&btv->s_lock,flags);
 	list_add_tail(&buf->vb.queue,&btv->vcapture);
 	bttv_set_dma(btv,0x0c,1);
-	spin_unlock_irqrestore(&btv->s_lock,flags);
 }
 
 static void vbi_buffer_release(struct file *file, struct videobuf_buffer *vb)
 {
 	struct bttv *btv = file->private_data;
 	struct bttv_buffer *buf = (struct bttv_buffer*)vb;
-
+	
+	dprintk("free %p\n",vb);
 	bttv_dma_free(btv,buf);
 }
 
-static void
-vbi_cancel_all(struct bttv *btv)
-{
-	unsigned long flags;
-	int i;
-
-	/* remove queued buffers from list */
-	spin_lock_irqsave(&btv->s_lock,flags);
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (NULL == btv->vbi.bufs[i])
-			continue;
-		if (btv->vbi.bufs[i]->vb.state == STATE_QUEUED) {
-			list_del(&btv->vbi.bufs[i]->vb.queue);
-			btv->vbi.bufs[i]->vb.state = STATE_ERROR;
-		}
-	}
-	spin_unlock_irqrestore(&btv->s_lock,flags);
-
-	/* free all buffers + clear queue */
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (NULL == btv->vbi.bufs[i])
-			continue;
-		bttv_dma_free(btv,btv->vbi.bufs[i]);
-	}
-	INIT_LIST_HEAD(&btv->vbi.stream);
-}
+struct videobuf_queue_ops vbi_qops = {
+	buf_setup:    vbi_buffer_setup,
+	buf_prepare:  vbi_buffer_prepare,
+	buf_queue:    vbi_buffer_queue,
+	buf_release:  vbi_buffer_release,
+};
 
 /* ----------------------------------------------------------------------- */
 
-static int vbi_read_start(struct file *file, struct bttv *btv)
-{
-	int err,size,count,i;
-	
-	if (vbibufs < 2 || vbibufs > VIDEO_MAX_FRAME)
-		vbibufs = 2;
-
-	count = vbibufs;
-	size  = btv->vbi.lines * 2 * 2048;
-	err = videobuf_mmap_setup(file,
-				  (struct videobuf_buffer**)btv->vbi.bufs,
-				  sizeof(struct bttv_buffer),
-				  count,size,V4L2_BUF_TYPE_VBI,
-				  vbi_buffer_release);
-	if (err)
-		return err;
-	for (i = 0; i < count; i++) {
-		err = vbi_buffer_prepare(btv,btv->vbi.bufs[i]);
-		if (err)
-			return err;
-		list_add_tail(&btv->vbi.bufs[i]->vb.stream,&btv->vbi.stream);
-		vbi_buffer_queue(btv,btv->vbi.bufs[i]);
-	}
-	btv->vbi.reading = 1;
-	return 0;
-}
-
-static void vbi_read_stop(struct bttv *btv)
-{
-	int i;
-
-	vbi_cancel_all(btv);
-	INIT_LIST_HEAD(&btv->vbi.stream);
-	for (i = 0; i < vbibufs; i++) {
-		kfree(btv->vbi.bufs[i]);
-		btv->vbi.bufs[i] = NULL;
-	}
-	btv->vbi.reading = 0;
-}
-
 static void vbi_setlines(struct bttv *btv, int lines)
 {
 	int vdelay;
@@ -234,7 +189,6 @@
 	struct bttv *btv = NULL;
 	int i;
 
-
 	for (i = 0; i < bttv_num; i++) {
 		if (bttvs[i].vbi_dev.minor == minor) {
 			btv = &bttvs[i];
@@ -244,18 +198,18 @@
 	if (NULL == btv)
 		return -ENODEV;
 
-	down(&btv->vbi.lock);
+	down(&btv->vbi.q.lock);
 	if (btv->vbi.users) {
-		up(&btv->vbi.lock);
+		up(&btv->vbi.q.lock);
 		return -EBUSY;
 	}
 	dprintk("open minor=%d\n",minor);
 	file->private_data = btv;
 	btv->vbi.users++;
-	bttv_field_count(btv);
 	vbi_setlines(btv,VBI_DEFLINES);
+	bttv_field_count(btv);
 	
-	up(&btv->vbi.lock);
+	up(&btv->vbi.q.lock);
 	
 	return 0;
 }
@@ -264,15 +218,15 @@
 {
 	struct bttv    *btv = file->private_data;
 
-	down(&btv->vbi.lock);
-	if (btv->vbi.reading) {
-		vbi_read_stop(btv);
-		btv->vbi.read_buf = NULL;
-	}
+	if (btv->vbi.q.streaming)
+		videobuf_streamoff(file,&btv->vbi.q);
+	down(&btv->vbi.q.lock);
+	if (btv->vbi.q.reading)
+		videobuf_read_stop(file,&btv->vbi.q);
 	btv->vbi.users--;
 	bttv_field_count(btv);
 	vbi_setlines(btv,0);
-	up(&btv->vbi.lock);
+	up(&btv->vbi.q.lock);
 	return 0;
 }
 
@@ -280,10 +234,6 @@
 			unsigned int cmd, void *arg)
 {
 	struct bttv *btv = file->private_data;
-#ifdef HAVE_V4L2
-	unsigned long flags;
-	int err;
-#endif
 	
 	if (btv->errors)
 		bttv_reinit_bt848(btv);
@@ -334,7 +284,7 @@
 	{
 		struct v4l2_format *f = arg;
 
-		if (btv->vbi.reading || btv->vbi.streaming)
+		if (btv->vbi.q.reading || btv->vbi.q.streaming)
 			return -EBUSY;
 		vbi_setlines(btv,f->fmt.vbi.count[0]);
 		vbi_fmt(btv,f);
@@ -342,145 +292,22 @@
 	}
 
 	case VIDIOC_REQBUFS:
-	{
-		struct v4l2_requestbuffers *req = arg;
-		int size,count;
+		return videobuf_reqbufs(file,&btv->vbi.q,arg);
 
-		if ((req->type & V4L2_BUF_TYPE_field) != V4L2_BUF_TYPE_VBI)
-			return -EINVAL;
-		if (req->count < 1)
-			return -EINVAL;
-
-		down(&btv->vbi.lock);
-		err = -EINVAL;
-
-		size  = btv->vbi.lines * 2 * 2048;
-		size  = (size + PAGE_SIZE - 1) & PAGE_MASK;
-		count = req->count;
-		if (count > VIDEO_MAX_FRAME)
-			count = VIDEO_MAX_FRAME;
-		err = videobuf_mmap_setup(file,
-					  (struct videobuf_buffer**)btv->vbi.bufs,
-					  sizeof(struct bttv_buffer),
-					  count,size,V4L2_BUF_TYPE_CAPTURE,
-					  vbi_buffer_release);
-		if (err < 0)
-			goto fh_unlock_and_return;
-		req->type  = V4L2_BUF_TYPE_VBI;
-		req->count = count;
-		up(&btv->vbi.lock);
-		return 0;
-	}
 	case VIDIOC_QUERYBUF:
-	{
-		struct v4l2_buffer *b = arg;
+		return videobuf_querybuf(&btv->vbi.q, arg);
 
-		if ((b->type & V4L2_BUF_TYPE_field) != V4L2_BUF_TYPE_VBI)
-			return -EINVAL;
-		if (b->index < 0 || b->index > VIDEO_MAX_FRAME)
-			return -EINVAL;
-		if (NULL == btv->vbi.bufs[b->index])
-			return -EINVAL;
-		videobuf_status(b,&btv->vbi.bufs[b->index]->vb);
-		return 0;
-	}
 	case VIDIOC_QBUF:
-	{
-		struct v4l2_buffer *b = arg;
-		struct bttv_buffer *buf;
-		
-		if ((b->type & V4L2_BUF_TYPE_field) != V4L2_BUF_TYPE_VBI)
-			return -EINVAL;
-		if (b->index < 0 || b->index > VIDEO_MAX_FRAME)
-			return -EINVAL;
-
-		down(&btv->vbi.lock);
-		err = -EINVAL;
-		buf = btv->vbi.bufs[b->index];
-		if (NULL == buf)
-			goto fh_unlock_and_return;
-		if (0 == buf->vb.baddr)
-			goto fh_unlock_and_return;
-		if (buf->vb.state == STATE_QUEUED ||
-		    buf->vb.state == STATE_ACTIVE)
-			goto fh_unlock_and_return;
-		err = vbi_buffer_prepare(btv,buf);
-		if (0 != err)
-			goto fh_unlock_and_return;
-
-		list_add_tail(&buf->vb.stream,&btv->vbi.stream);
-		if (btv->vbi.streaming)
-			vbi_buffer_queue(btv,buf);
-		up(&btv->vbi.lock);
-		return 0;
-	}
-	case VIDIOC_DQBUF:
-	{
-		struct v4l2_buffer *b = arg;
-		struct bttv_buffer *buf;
+		return videobuf_qbuf(file, &btv->vbi.q, arg);
 
-		if ((b->type & V4L2_BUF_TYPE_field) != V4L2_BUF_TYPE_VBI)
-			return -EINVAL;
+	case VIDIOC_DQBUF:
+		return videobuf_dqbuf(file, &btv->vbi.q, arg);
 
-		down(&btv->vbi.lock);
-		err = -EINVAL;
-		if (list_empty(&btv->vbi.stream))
-			goto fh_unlock_and_return;
-		buf = list_entry(btv->vbi.stream.next,
-				 struct bttv_buffer, vb.stream);
-		err = videobuf_waiton(&buf->vb,0,1);
-		if (err < 0)
-			goto fh_unlock_and_return;
-		switch (buf->vb.state) {
-		case STATE_ERROR:
-			err = -EIO;
-			/* fall through */
-		case STATE_DONE:
-			videobuf_dma_pci_sync(btv->dev,&buf->vb.dma);
-			buf->vb.state = STATE_IDLE;
-			break;
-		default:
-			err = -EINVAL;
-			goto fh_unlock_and_return;
-		}
-		list_del(&buf->vb.stream);
-		memset(b,0,sizeof(*b));
-		videobuf_status(b,&buf->vb);
-		up(&btv->vbi.lock);
-		return err;
-	}
 	case VIDIOC_STREAMON:
-	{
-		struct list_head *list;
-		struct bttv_buffer *buf;
+		return videobuf_streamon(file, &btv->vbi.q);
 
-		down(&btv->vbi.lock);
-		err = -EBUSY;
-		if (btv->vbi.reading)
-			goto fh_unlock_and_return;
-		spin_lock_irqsave(&btv->s_lock,flags);
-		list_for_each(list,&btv->vbi.stream) {
-			buf = list_entry(list, struct bttv_buffer, vb.stream);
-			if (buf->vb.state == STATE_PREPARED)
-				vbi_buffer_queue(btv,buf);
-		}
-		spin_unlock_irqrestore(&btv->s_lock,flags);
-		btv->vbi.streaming = 1;
-		up(&btv->vbi.lock);
-		return 0;
-	}
 	case VIDIOC_STREAMOFF:
-	{
-		down(&btv->vbi.lock);
-		err = -EINVAL;
-		if (!btv->vbi.streaming)
-			goto fh_unlock_and_return;
-		vbi_cancel_all(btv);
-		INIT_LIST_HEAD(&btv->vbi.stream);
-		btv->vbi.streaming = 0;
-		up(&btv->vbi.lock);
-		return 0;
-	}
+		return videobuf_streamoff(file, &btv->vbi.q);
 
 	case VIDIOC_ENUMSTD:
 	case VIDIOC_G_STD:
@@ -499,12 +326,6 @@
 		return -ENOIOCTLCMD;
 	}
 	return 0;
-
-#ifdef HAVE_V4L2
- fh_unlock_and_return:
-	up(&btv->vbi.lock);
-	return err;
-#endif
 }
 
 static int vbi_ioctl(struct inode *inode, struct file *file,
@@ -516,123 +337,30 @@
 static ssize_t vbi_read(struct file *file, char *data,
 			size_t count, loff_t *ppos)
 {
-	unsigned int *fc;
 	struct bttv *btv = file->private_data;
-	int err, bytes, retval = 0;
 
 	if (btv->errors)
 		bttv_reinit_bt848(btv);
-	down(&btv->vbi.lock);
-	if (!btv->vbi.reading) {
-		retval = vbi_read_start(file,btv);
-		if (retval < 0)
-			goto done;
-	}
-
-	while (count > 0) {
-		/* get / wait for data */
-		if (NULL == btv->vbi.read_buf) {
-			btv->vbi.read_buf = list_entry(btv->vbi.stream.next,
-						       struct bttv_buffer,
-						       vb.stream);
-			list_del(&btv->vbi.read_buf->vb.stream);
-			btv->vbi.read_off = 0;
-		}
-		err = videobuf_waiton(&btv->vbi.read_buf->vb,
-				      file->f_flags & O_NONBLOCK,1);
-		if (err < 0) {
-			if (0 == retval)
-				retval = err;
-			break;
-		}
-
-#if 1
-		/* dirty, undocumented hack -- pass the frame counter
-		 * within the last four bytes of each vbi data block.
-		 * We need that one to maintain backward compatibility
-		 * to all vbi decoding software out there ... */
-		fc  = (unsigned int*)btv->vbi.read_buf->vb.dma.vmalloc;
-		fc += (btv->vbi.read_buf->vb.size>>2) -1;
-		*fc = btv->vbi.read_buf->vb.field_count >> 1;
-#endif
-
-		/* copy stuff */
-		bytes = count;
-		if (bytes > btv->vbi.read_buf->vb.size - btv->vbi.read_off)
-			bytes = btv->vbi.read_buf->vb.size - btv->vbi.read_off;
-		if (copy_to_user(data + retval,btv->vbi.read_buf->vb.dma.vmalloc +
-				 btv->vbi.read_off,bytes)) {
-			if (0 == retval)
-				retval = -EFAULT;
-			break;
-		}
-		count             -= bytes;
-		retval            += bytes;
-		btv->vbi.read_off += bytes;
-		dprintk("read: %d bytes\n",bytes);
-
-		/* requeue buffer when done with copying */
-		if (btv->vbi.read_off == btv->vbi.read_buf->vb.size) {
-			list_add_tail(&btv->vbi.read_buf->vb.stream,
-				      &btv->vbi.stream);
-			vbi_buffer_queue(btv,btv->vbi.read_buf);
-			btv->vbi.read_buf = NULL;
-		}
-	}
- done:
-	up(&btv->vbi.lock);
-	return retval;
+	dprintk("read %d\n",count);
+	return videobuf_read_stream(file, &btv->vbi.q, data, count, ppos, 1);
 }
 
 static unsigned int vbi_poll(struct file *file, poll_table *wait)
 {
 	struct bttv *btv = file->private_data;
-	struct bttv_buffer *buf = NULL;
-	unsigned int rc = 0;
-
-	down(&btv->vbi.lock);
-	if (btv->vbi.streaming) {
-		if (!list_empty(&btv->vbi.stream))
-			buf = list_entry(btv->vbi.stream.next,
-					 struct bttv_buffer, vb.stream);
-	} else {
-		if (!btv->vbi.reading)
-			vbi_read_start(file,btv);
-		if (!btv->vbi.reading) {
-			rc = POLLERR;
-		} else if (NULL == btv->vbi.read_buf) {
-			btv->vbi.read_buf = list_entry(btv->vbi.stream.next,
-						       struct bttv_buffer,
-						       vb.stream);
-			list_del(&btv->vbi.read_buf->vb.stream);
-			btv->vbi.read_off = 0;
-		}
-		buf = btv->vbi.read_buf;
-	}
-	if (!buf)
-		rc = POLLERR;
 
-	if (0 == rc) {
-		poll_wait(file, &buf->vb.done, wait);
-		if (buf->vb.state == STATE_DONE ||
-		    buf->vb.state == STATE_ERROR)
-			rc = POLLIN|POLLRDNORM;
-	}
-	up(&btv->vbi.lock);
-	return rc;
+	dprintk("poll%s\n","");
+	return videobuf_poll_stream(file, &btv->vbi.q, wait);
 }
 
 static int
 vbi_mmap(struct file *file, struct vm_area_struct * vma)
 {
 	struct bttv *btv = file->private_data;
-	int err;
-
-	down(&btv->vbi.lock);
-	err = videobuf_mmap_mapper
-		(vma,(struct videobuf_buffer**)btv->vbi.bufs);
-	up(&btv->vbi.lock);
-	return err;
+	
+	dprintk("mmap 0x%lx+%ld\n",vma->vm_start,
+		vma->vm_end - vma->vm_start);
+	return videobuf_mmap_mapper(vma, &btv->vbi.q);
 }
 
 static struct file_operations vbi_fops =
diff -Nru a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
--- a/drivers/media/video/bttvp.h	Tue Jul 16 16:49:42 2002
+++ b/drivers/media/video/bttvp.h	Tue Jul 16 16:49:42 2002
@@ -24,7 +24,7 @@
 #ifndef _BTTVP_H_
 #define _BTTVP_H_
 
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,8,38)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,8,42)
 
 #include <linux/types.h>
 #include <linux/wait.h>
@@ -127,40 +127,20 @@
 };
 
 struct bttv_vbi {
-        struct semaphore           lock;
-	int                        users;
-	int                        lines;
-
-	/* mmap */
-	int                        streaming;
-	struct bttv_buffer         *bufs[VIDEO_MAX_FRAME];
-	struct list_head           stream;
-
-	/* read */
-	int                        reading;
-	int                        read_off;
-	struct bttv_buffer         *read_buf;
+	int                      users;
+	int                      lines;
+	struct videobuf_queue    q;
 };
 
 struct bttv_fh {
 	struct bttv              *btv;
-
-	/* locking */
+	struct videobuf_queue    q;
 	int resources;
-	struct semaphore lock;
-
-	/* keep current driver settings */
+	
+	/* current settings */
 	const struct bttv_format *ovfmt;
 	struct bttv_overlay      ov;
 	struct bttv_buffer       buf;
-
-	/* for read() capture */
-	struct bttv_buffer       read_buf;
-	int                      read_off;
-
-	/* mmap()'ed buffers */
-	struct bttv_buffer       *bufs[VIDEO_MAX_FRAME];
-	struct list_head stream; /* v4l2 QBUF/DQBUF */
 };
 
 /* ---------------------------------------------------------- */
@@ -221,6 +201,8 @@
 /* bttv-vbi.c                                                 */
 
 extern struct video_device bttv_vbi_template;
+extern struct videobuf_queue_ops vbi_qops;
+
 
 /* ---------------------------------------------------------- */
 /* bttv-driver.c                                              */
@@ -277,7 +259,8 @@
 	/* gpio interface */
 	wait_queue_head_t gpioq;
 	int shutdown;
-
+	void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
+	
 	/* i2c layer */
 	struct i2c_adapter         i2c_adap;
 	struct i2c_algo_bit_data   i2c_algo;
diff -Nru a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
--- a/drivers/media/video/msp3400.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/media/video/msp3400.c	Tue Jul 16 16:49:41 2002
@@ -1266,6 +1266,7 @@
 
 	if (-1 == msp3400c_reset(c)) {
 		kfree(msp);
+		kfree(c);
 		dprintk("msp3400: no chip found\n");
 		return -1;
 	}
@@ -1275,6 +1276,7 @@
 		rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
 	if ((-1 == rev1) || (0 == rev1 && 0 == rev2)) {
 		kfree(msp);
+		kfree(c);
 		printk("msp3400: error while reading chip version\n");
 		return -1;
 	}
diff -Nru a/drivers/media/video/pms.c b/drivers/media/video/pms.c
--- a/drivers/media/video/pms.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/media/video/pms.c	Tue Jul 16 16:49:42 2002
@@ -11,7 +11,7 @@
  *
  *	Most of this code is directly derived from his userspace driver.
  *	His driver works so send any reports to alan@redhat.com unless the
- *	userspace driver also doesnt work for you...
+ *	userspace driver also doesn't work for you...
  */
 
 #include <linux/module.h>
diff -Nru a/drivers/media/video/tuner.c b/drivers/media/video/tuner.c
--- a/drivers/media/video/tuner.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/media/video/tuner.c	Tue Jul 16 16:49:43 2002
@@ -215,7 +215,8 @@
           16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
         { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
           16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
-	
+	{ "Philips PAL/SECAM multi (FM1216ME)", Philips, PAL,
+	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
 };
 #define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
 
@@ -253,7 +254,7 @@
 	return (tuner_getstatus (c) & TUNER_STEREO);
 }
 
-
+#if 0 /* unused */
 static int tuner_islocked (struct i2c_client *c)
 {
         return (tuner_getstatus (c) & TUNER_FL);
@@ -264,12 +265,12 @@
         return (tuner_getstatus (c) & TUNER_AFC) - 2;
 }
 
-#if 0 /* unused */
 static int tuner_mode (struct i2c_client *c)
 {
         return (tuner_getstatus (c) & TUNER_MODE) >> 3;
 }
 #endif
+
 // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
 static int mt2032_init(struct i2c_client *c)
 {
@@ -651,8 +652,9 @@
 		default:
 			config |= TEMIC_SET_PAL_BG;
 			break;
-		break;
 		}
+		break;
+
 	case TUNER_PHILIPS_FQ1216ME:
 		config &= ~0x0f;
 		switch (pal[0]) {
@@ -672,8 +674,8 @@
 		case 'G':
 			config |= PHILIPS_SET_PAL_BGDK;
 			break;
-		break;
 		}
+		break;
 	}
 
 	
@@ -703,6 +705,8 @@
 		buffer[2] = tun->config;
 		buffer[3] = config;
 	}
+	dprintk("tuner: tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		buffer[0],buffer[1],buffer[2],buffer[3]);
 
         if (4 != (rc = i2c_master_send(c,buffer,4)))
                 printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
@@ -720,12 +724,10 @@
 
 static void set_radio_freq(struct i2c_client *c, int freq)
 {
-	u8 config;
-	u16 div;
 	struct tunertype *tun;
 	struct tuner *t = (struct tuner*)c->data;
         unsigned char buffer[4];
-	int rc;
+	int rc,div;
 
 	if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {
 		printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n",
@@ -744,35 +746,27 @@
 	}
 
 	tun=&tuners[t->type];
-	config = 0xa4 /* 0xa5 */; /* bit 0 is AFC (set) vs. RF-Signal (clear) */
-	div=freq + (int)(16*10.7);
-  	div&=0x7fff;
-
+	div = freq + (int)(16*10.7);
         buffer[0] = (div>>8) & 0x7f;
         buffer[1] = div      & 0xff;
-        buffer[2] = tun->config;
-        buffer[3] = config;
-        if (4 != (rc = i2c_master_send(c,buffer,4)))
-                printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
+	buffer[2] = tun->config;
+	switch (t->type) {
+	case TUNER_PHILIPS_FM1216ME:
+		buffer[3] = 0x19;
+		break;
+	default:
+		buffer[3] = 0xa4;
+		break;
+	}
 
-	if (debug) {
-		current->state   = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ/10);
-		
-		if (tuner_islocked (c))
-			printk ("tuner: PLL locked\n");
-		else
-			printk ("tuner: PLL not locked\n");
+	dprintk("tuner: radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		buffer[0],buffer[1],buffer[2],buffer[3]);
 
-		if (config & 1) {
-			printk ("tuner: AFC: %d\n", tuner_afcstatus(c));
-		} else {
-			printk ("tuner: Signal: %d\n", tuner_signal(c));
-		}
-	}
+        if (4 != (rc = i2c_master_send(c,buffer,4)))
+                printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
 }
-/* ---------------------------------------------------------------------- */
 
+/* ---------------------------------------------------------------------- */
 
 static int tuner_attach(struct i2c_adapter *adap, int addr,
 			unsigned short flags, int kind)
@@ -824,6 +818,7 @@
 	this_adap = 0;
 	switch (adap->id) {
 	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
 	case I2C_ALGO_SAA7134:
 		printk("tuner: probing %s i2c adapter [id=0x%x]\n",
 		       adap->name,adap->id);
diff -Nru a/drivers/media/video/tuner.h b/drivers/media/video/tuner.h
--- a/drivers/media/video/tuner.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/media/video/tuner.h	Tue Jul 16 16:49:41 2002
@@ -62,6 +62,7 @@
 #define TUNER_TEMIC_4012FY5	35	/* 4012 FY5 (3X 0971, 1099)*/
 #define TUNER_TEMIC_4136FY5	36	/* 4136 FY5 (3X 7708, 7746)*/
 #define TUNER_LG_PAL_NEW_TAPC   37
+#define TUNER_PHILIPS_FM1216ME  38
 
 
 
diff -Nru a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
--- a/drivers/media/video/tvaudio.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/media/video/tvaudio.c	Tue Jul 16 16:49:42 2002
@@ -1070,10 +1070,46 @@
 #define TDA8425_S1         0x08  /* switch functions */
                                  /* values for those registers: */
 #define TDA8425_S1_OFF     0xEE  /* audio off (mute on) */
-#define TDA8425_S1_ON      0xCE  /* audio on (mute off) - "linear stereo" mode */
+#define TDA8425_S1_CH1     0xCE  /* audio channel 1 (mute off) - "linear stereo" mode */
+#define TDA8425_S1_CH2     0xCF  /* audio channel 2 (mute off) - "linear stereo" mode */
+#define TDA8425_S1_MU      0x20  /* mute bit */
+#define TDA8425_S1_STEREO  0x18  /* stereo bits */
+#define TDA8425_S1_STEREO_SPATIAL 0x18 /* spatial stereo */
+#define TDA8425_S1_STEREO_LINEAR  0x08 /* linear stereo */
+#define TDA8425_S1_STEREO_PSEUDO  0x10 /* pseudo stereo */
+#define TDA8425_S1_STEREO_MONO    0x00 /* forced mono */
+#define TDA8425_S1_ML      0x06        /* language selector */
+#define TDA8425_S1_ML_SOUND_A 0x02     /* sound a */
+#define TDA8425_S1_ML_SOUND_B 0x04     /* sound b */
+#define TDA8425_S1_ML_STEREO  0x06     /* stereo */
+#define TDA8425_S1_IS      0x01        /* channel selector */
 
-static int tda8425_shift10(int val) { return val >> 10 | 0xc0; }
-static int tda8425_shift12(int val) { return val >> 12 | 0xf0; }
+
+static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; }
+static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
+
+static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
+{
+	int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
+	
+	if (mode & VIDEO_SOUND_LANG1) {
+		s1 |= TDA8425_S1_ML_SOUND_A;
+		s1 |= TDA8425_S1_STEREO_PSEUDO;
+
+	} else if (mode & VIDEO_SOUND_LANG2) {
+		s1 |= TDA8425_S1_ML_SOUND_B;
+		s1 |= TDA8425_S1_STEREO_PSEUDO;
+		
+	} else {
+		s1 |= TDA8425_S1_ML_STEREO;
+		
+		if (mode & VIDEO_SOUND_MONO)
+			s1 |= TDA8425_S1_STEREO_MONO;
+		if (mode & VIDEO_SOUND_STEREO)
+			s1 |= TDA8425_S1_STEREO_SPATIAL;
+	}
+	chip_write(chip,TDA8425_S1,s1);
+}
 
 
 /* ---------------------------------------------------------------------- */
@@ -1190,8 +1226,8 @@
 		registers:  11,
 		flags:      CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
 
-		leftreg:    TDA9855_VR,
-		rightreg:   TDA9855_VL,
+		leftreg:    TDA9855_VL,
+		rightreg:   TDA9855_VR,
 		bassreg:    TDA9855_BA,
 		treblereg:  TDA9855_TR,
 		volfunc:    tda9855_volume,
@@ -1258,8 +1294,10 @@
 		treblefunc: tda8425_shift12,
 
 		inputreg:   TDA8425_S1,
-		inputmap:   { TDA8425_S1_ON, TDA8425_S1_ON, TDA8425_S1_ON },
+		inputmap:   { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },
 		inputmute:  TDA8425_S1_OFF,
+
+		setmode:    tda8425_setmode,
 	},
 	{
 		name:       "pic16c54 (PV951)",
@@ -1338,8 +1376,8 @@
 		chip_cmd(chip,"init",&desc->init);
 
 	if (desc->flags & CHIP_HAS_VOLUME) {
-		chip->left   = desc->leftinit   ? desc->leftinit   : 65536;
-		chip->right  = desc->rightinit  ? desc->rightinit  : 65536;
+		chip->left   = desc->leftinit   ? desc->leftinit   : 65535;
+		chip->right  = desc->rightinit  ? desc->rightinit  : 65535;
 		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
 		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
 	}
@@ -1367,9 +1405,14 @@
 
 static int chip_probe(struct i2c_adapter *adap)
 {
-	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+	switch (adap->id) {
+	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
 		return i2c_probe(adap, &addr_data, chip_attach);
-	return 0;
+	default:
+		/* ignore this i2c bus */
+		return 0;
+	}
 }
 
 static int chip_detach(struct i2c_client *client)
diff -Nru a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
--- a/drivers/media/video/tvmixer.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/media/video/tvmixer.c	Tue Jul 16 16:49:42 2002
@@ -254,7 +254,13 @@
 	int i,minor;
 
 	/* TV card ??? */
-	if (client->adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848)) {
+	switch (client->adapter->id) {
+	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
+		/* ok, have a look ... */
+		break;
+	default:
+		/* ignore that one */
 		if (debug)
 			printk("tvmixer: %s is not a tv card\n",
 			       client->adapter->name);
diff -Nru a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
--- a/drivers/media/video/video-buf.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/media/video/video-buf.c	Tue Jul 16 16:49:42 2002
@@ -207,14 +207,13 @@
 
 /* --------------------------------------------------------------------- */
 
-void* videobuf_alloc(int size, int type)
+void* videobuf_alloc(int size)
 {
 	struct videobuf_buffer *vb;
 
 	vb = kmalloc(size,GFP_KERNEL);
 	if (NULL != vb) {
 		memset(vb,0,size);
-		vb->type = type;
 		init_waitqueue_head(&vb->done);
 	}
 	return vb;
@@ -273,12 +272,63 @@
 	return 0;
 }
 
+/* --------------------------------------------------------------------- */
+
+void
+videobuf_queue_init(struct videobuf_queue *q,
+		    struct videobuf_queue_ops *ops,
+		    struct pci_dev *pci,
+		    spinlock_t *irqlock,
+		    int type,
+		    int msize)
+{
+	memset(q,0,sizeof(*q));
+
+	q->irqlock = irqlock;
+	q->pci     = pci;
+	q->type    = type;
+	q->msize   = msize;
+	q->ops     = ops;
+
+	init_MUTEX(&q->lock);
+	INIT_LIST_HEAD(&q->stream);
+}
+
+void
+videobuf_queue_cancel(struct file *file, struct videobuf_queue *q)
+{
+	unsigned long flags;
+	int i;
+
+	/* remove queued buffers from list */
+	spin_lock_irqsave(q->irqlock,flags);
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		if (q->bufs[i]->state == STATE_QUEUED) {
+			list_del(&q->bufs[i]->queue);
+			q->bufs[i]->state = STATE_ERROR;
+		}
+	}
+	spin_unlock_irqrestore(q->irqlock,flags);
+
+	/* free all buffers + clear queue */
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		q->ops->buf_release(file,q->bufs[i]);
+	}
+	INIT_LIST_HEAD(&q->stream);
+}
+
+/* --------------------------------------------------------------------- */
+
 #ifdef HAVE_V4L2
-extern void
-videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb)
+void
+videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, int type)
 {
 	b->index  = vb->i;
-	b->type   = vb->type;
+	b->type   = type;
 	b->offset = vb->boff;
 	b->length = vb->bsize;
 	b->flags  = 0;
@@ -309,8 +359,440 @@
 	b->bytesused = vb->size;
 	b->sequence  = vb->field_count >> 1;
 }
+
+int
+videobuf_reqbufs(struct file *file, struct videobuf_queue *q,
+		 struct v4l2_requestbuffers *req)
+{
+	int size,count,retval;
+
+	if ((req->type & V4L2_BUF_TYPE_field) != q->type)
+		return -EINVAL;
+	if (req->count < 1)
+		return -EINVAL;
+
+	down(&q->lock);
+	count = req->count;
+	if (count > VIDEO_MAX_FRAME)
+		count = VIDEO_MAX_FRAME;
+	size = 0;
+	q->ops->buf_setup(file,&count,&size);
+	size = PAGE_ALIGN(size);
+
+	retval = videobuf_mmap_setup(file,q,count,size);
+	if (retval < 0)
+		goto done;
+	req->type  = q->type;
+	req->count = count;
+
+ done:
+	up(&q->lock);
+	return retval;
+}
+
+int
+videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
+{
+	if ((b->type & V4L2_BUF_TYPE_field) != q->type)
+		return -EINVAL;
+	if (b->index < 0 || b->index >= VIDEO_MAX_FRAME)
+		return -EINVAL;
+	if (NULL == q->bufs[b->index])
+		return -EINVAL;
+	videobuf_status(b,q->bufs[b->index],q->type);
+	return 0;
+}
+
+int
+videobuf_qbuf(struct file *file, struct videobuf_queue *q,
+	      struct v4l2_buffer *b)
+{
+	struct videobuf_buffer *buf;
+	unsigned long flags;
+	int field = 0;
+	int retval;
+
+	down(&q->lock);
+	retval = -EBUSY;
+	if (q->reading)
+		goto done;
+	retval = -EINVAL;
+	if ((b->type & V4L2_BUF_TYPE_field) != q->type)
+		goto done;
+	if (b->index < 0 || b->index >= VIDEO_MAX_FRAME)
+		goto done;
+	buf = q->bufs[b->index];
+	if (NULL == buf)
+		goto done;
+	if (0 == buf->baddr)
+		goto done;
+	if (buf->state == STATE_QUEUED ||
+	    buf->state == STATE_ACTIVE)
+		goto done;
+
+	if (b->flags & V4L2_BUF_FLAG_TOPFIELD)
+		field |= VBUF_FIELD_ODD;
+	if (b->flags & V4L2_BUF_FLAG_BOTFIELD)
+		field |= VBUF_FIELD_EVEN;
+	retval = q->ops->buf_prepare(file,buf,field);
+	if (0 != retval)
+		goto done;
+	
+	list_add_tail(&buf->stream,&q->stream);
+	if (q->streaming) {
+		spin_lock_irqsave(q->irqlock,flags);
+		q->ops->buf_queue(file,buf);
+		spin_unlock_irqrestore(q->irqlock,flags);
+	}
+	retval = 0;
+	
+ done:
+	up(&q->lock);
+	return retval;
+}
+
+int
+videobuf_dqbuf(struct file *file, struct videobuf_queue *q,
+	       struct v4l2_buffer *b)
+{
+	struct videobuf_buffer *buf;
+	int retval;
+	
+	down(&q->lock);
+	retval = -EBUSY;
+	if (q->reading)
+		goto done;
+	retval = -EINVAL;
+	if ((b->type & V4L2_BUF_TYPE_field) != q->type)
+		goto done;
+	if (list_empty(&q->stream))
+		goto done;
+	buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
+	retval = videobuf_waiton(buf,1,1);
+	if (retval < 0)
+		goto done;
+	switch (buf->state) {
+	case STATE_ERROR:
+		retval = -EIO;
+		/* fall through */
+	case STATE_DONE:
+		videobuf_dma_pci_sync(q->pci,&buf->dma);
+		buf->state = STATE_IDLE;
+		break;
+	default:
+		retval = -EINVAL;
+		goto done;
+	}
+	list_del(&buf->stream);
+	memset(b,0,sizeof(*b));
+	videobuf_status(b,buf,q->type);
+
+ done:
+	up(&q->lock);
+	return retval;
+}
 #endif /* HAVE_V4L2 */
 
+int videobuf_streamon(struct file *file, struct videobuf_queue *q)
+{
+	struct videobuf_buffer *buf;
+	struct list_head *list;
+	unsigned long flags;
+	int retval;
+	
+	down(&q->lock);
+	retval = -EBUSY;
+	if (q->reading)
+		goto done;
+	retval = 0;
+	if (q->streaming)
+		goto done;
+	q->streaming = 1;
+	spin_lock_irqsave(q->irqlock,flags);
+	list_for_each(list,&q->stream) {
+		buf = list_entry(list, struct videobuf_buffer, stream);
+		if (buf->state == STATE_PREPARED)
+			q->ops->buf_queue(file,buf);
+	}
+	spin_unlock_irqrestore(q->irqlock,flags);
+
+ done:
+	up(&q->lock);
+	return retval;
+}
+
+int videobuf_streamoff(struct file *file, struct videobuf_queue *q)
+{
+	int retval = -EINVAL;
+
+	down(&q->lock);
+	if (!q->streaming)
+		goto done;
+	videobuf_queue_cancel(file,q);
+	q->streaming = 0;
+	retval = 0;
+
+ done:
+	up(&q->lock);
+	return retval;
+}
+
+static ssize_t
+videobuf_read_zerocopy(struct file *file, struct videobuf_queue *q,
+		       char *data, size_t count, loff_t *ppos)
+{
+        int retval;
+
+        /* setup stuff */
+	retval = -ENOMEM;
+	q->read_buf = videobuf_alloc(q->msize);
+	if (NULL == q->read_buf)
+		goto done;
+
+	q->read_buf->baddr = (unsigned long)data;
+        q->read_buf->bsize = count;
+	retval = q->ops->buf_prepare(file,q->read_buf,0);
+	if (0 != retval)
+		goto done;
+	
+        /* start capture & wait */
+	q->ops->buf_queue(file,q->read_buf);
+        retval = videobuf_waiton(q->read_buf,0,0);
+        if (0 == retval) {
+		videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
+                retval = q->read_buf->size;
+	}
+
+ done:
+	/* cleanup */
+	q->ops->buf_release(file,q->read_buf);
+	kfree(q->read_buf);
+	q->read_buf = NULL;
+	return retval;
+}
+
+ssize_t videobuf_read_one(struct file *file, struct videobuf_queue *q,
+			  char *data, size_t count, loff_t *ppos)
+{
+	int retval, bytes, size, nbufs;
+
+	down(&q->lock);
+
+	nbufs = 1; size = 0;
+	q->ops->buf_setup(file,&nbufs,&size);
+	if (NULL == q->read_buf  &&
+	    count >= size        &&
+	    !(file->f_flags & O_NONBLOCK)) {
+		retval = videobuf_read_zerocopy(file,q,data,count,ppos);
+		if (retval >= 0)
+			/* ok, all done */
+			goto done;
+		/* fallback to kernel bounce buffer on failures */
+	}
+
+	if (NULL == q->read_buf) {
+		/* need to capture a new frame */
+		retval = -ENOMEM;
+		q->read_buf = videobuf_alloc(q->msize);
+		if (NULL == q->read_buf)
+			goto done;
+		retval = q->ops->buf_prepare(file,q->read_buf,0);
+		if (0 != retval)
+			goto done;
+		q->ops->buf_queue(file,q->read_buf);
+		q->read_off = 0;
+	}
+
+	/* wait until capture is done */
+        retval = videobuf_waiton(q->read_buf, file->f_flags & O_NONBLOCK, 1);
+	if (0 != retval)
+		goto done;
+	videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
+
+	/* copy to userspace */
+	bytes = count;
+	if (bytes > q->read_buf->size - q->read_off)
+		bytes = q->read_buf->size - q->read_off;
+	retval = -EFAULT;
+	if (copy_to_user(data, q->read_buf->dma.vmalloc+q->read_off, bytes))
+		goto done;
+
+	retval = bytes;
+	q->read_off += bytes;
+	if (q->read_off == q->read_buf->size) {
+		/* all data copied, cleanup */
+		q->ops->buf_release(file,q->read_buf);
+		kfree(q->read_buf);
+		q->read_buf = NULL;
+	}
+
+ done:
+	up(&q->lock);
+	return retval;
+}
+
+int videobuf_read_start(struct file *file, struct videobuf_queue *q)
+{
+	unsigned long flags;
+	int count = 0, size = 0;
+	int err, i;
+
+	q->ops->buf_setup(file,&count,&size);
+	if (count < 2)
+		count = 2;
+	if (count > VIDEO_MAX_FRAME)
+		count = VIDEO_MAX_FRAME;
+	size = PAGE_ALIGN(size);
+
+	err = videobuf_mmap_setup(file, q, count, size);
+	if (err)
+		return err;
+	for (i = 0; i < count; i++) {
+		err = q->ops->buf_prepare(file,q->bufs[i],0);
+		if (err)
+			return err;
+		list_add_tail(&q->bufs[i]->stream, &q->stream);
+	}
+	spin_lock_irqsave(q->irqlock,flags);
+	for (i = 0; i < count; i++)
+		q->ops->buf_queue(file,q->bufs[i]);
+	spin_unlock_irqrestore(q->irqlock,flags);
+	q->reading = 1;
+	return 0;
+}
+
+void videobuf_read_stop(struct file *file, struct videobuf_queue *q)
+{
+	int i;
+	
+	videobuf_queue_cancel(file,q);
+	INIT_LIST_HEAD(&q->stream);
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		kfree(q->bufs[i]);
+		q->bufs[i] = NULL;
+	}
+	q->read_buf = NULL;
+	q->reading  = 0;
+}
+
+ssize_t videobuf_read_stream(struct file *file, struct videobuf_queue *q,
+			     char *data, size_t count, loff_t *ppos,
+			     int vbihack)
+{
+	unsigned int *fc;
+	int err, bytes, retval;
+	unsigned long flags;
+	
+	down(&q->lock);
+	retval = -EBUSY;
+	if (q->streaming)
+		goto done;
+	if (!q->reading) {
+		retval = videobuf_read_start(file,q);
+		if (retval < 0)
+			goto done;
+	}
+
+	retval = 0;
+	while (count > 0) {
+		/* get / wait for data */
+		if (NULL == q->read_buf) {
+			q->read_buf = list_entry(q->stream.next,
+						 struct videobuf_buffer,
+						 stream);
+			list_del(&q->read_buf->stream);
+			q->read_off = 0;
+		}
+		err = videobuf_waiton(q->read_buf,
+				      file->f_flags & O_NONBLOCK,1);
+		if (err < 0) {
+			if (0 == retval)
+				retval = err;
+			break;
+		}
+
+		if (vbihack) {
+			/* dirty, undocumented hack -- pass the frame counter
+			 * within the last four bytes of each vbi data block.
+			 * We need that one to maintain backward compatibility
+			 * to all vbi decoding software out there ... */
+			fc  = (unsigned int*)q->read_buf->dma.vmalloc;
+			fc += (q->read_buf->size>>2) -1;
+			*fc = q->read_buf->field_count >> 1;
+		}
+
+		/* copy stuff */
+		bytes = count;
+		if (bytes > q->read_buf->size - q->read_off)
+			bytes = q->read_buf->size - q->read_off;
+		if (copy_to_user(data + retval,
+				 q->read_buf->dma.vmalloc + q->read_off,
+				 bytes)) {
+			if (0 == retval)
+				retval = -EFAULT;
+			break;
+		}
+		count       -= bytes;
+		retval      += bytes;
+		q->read_off += bytes;
+
+		/* requeue buffer when done with copying */
+		if (q->read_off == q->read_buf->size) {
+			list_add_tail(&q->read_buf->stream,
+				      &q->stream);
+			spin_lock_irqsave(q->irqlock,flags);
+			q->ops->buf_queue(file,q->read_buf);
+			spin_unlock_irqrestore(q->irqlock,flags);
+			q->read_buf = NULL;
+		}
+	}
+
+ done:
+	up(&q->lock);
+	return retval;
+}
+
+unsigned int videobuf_poll_stream(struct file *file,
+				  struct videobuf_queue *q,
+				  poll_table *wait)
+{
+	struct videobuf_buffer *buf = NULL;
+	unsigned int rc = 0;
+
+	down(&q->lock);
+	if (q->streaming) {
+		if (!list_empty(&q->stream))
+			buf = list_entry(q->stream.next,
+					 struct videobuf_buffer, stream);
+	} else {
+		if (!q->reading)
+			videobuf_read_start(file,q);
+		if (!q->reading) {
+			rc = POLLERR;
+		} else if (NULL == q->read_buf) {
+			q->read_buf = list_entry(q->stream.next,
+						 struct videobuf_buffer,
+						 stream);
+			list_del(&q->read_buf->stream);
+			q->read_off = 0;
+		}
+		buf = q->read_buf;
+	}
+	if (!buf)
+		rc = POLLERR;
+
+	if (0 == rc) {
+		poll_wait(file, &buf->done, wait);
+		if (buf->state == STATE_DONE ||
+		    buf->state == STATE_ERROR)
+			rc = POLLIN|POLLRDNORM;
+	}
+	up(&q->lock);
+	return rc;
+}
+
 /* --------------------------------------------------------------------- */
 
 static void
@@ -331,14 +813,15 @@
 	if (0 == map->count) {
 		dprintk(1,"munmap %p\n",map);
 		for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-			if (NULL == map->buflist[i])
+			if (NULL == map->q->bufs[i])
 				continue;
-			if (map->buflist[i]->map != map)
+			if (map->q->bufs[i])
+				;
+			if (map->q->bufs[i]->map != map)
 				continue;
-			map->buflist[i]->map   = NULL;
-			map->buflist[i]->baddr = 0;
-			if (map->buflist[i]->free)
-				map->buflist[i]->free(vma->vm_file,map->buflist[i]);
+			map->q->bufs[i]->map   = NULL;
+			map->q->bufs[i]->baddr = 0;
+			map->q->ops->buf_release(vma->vm_file,map->q->bufs[i]);
 		}
 		kfree(map);
 	}
@@ -376,108 +859,114 @@
 	nopage:   videobuf_vm_nopage,
 };
 
-int videobuf_mmap_setup(struct file *file, struct videobuf_buffer **buflist,
-			int msize, int bcount, int bsize, int type,
-			videobuf_buffer_free free)
+int videobuf_mmap_setup(struct file *file, struct videobuf_queue *q,
+			int bcount, int bsize)
 {
 	int i,err;
 
-	err = videobuf_mmap_free(file,buflist);
+	err = videobuf_mmap_free(file,q);
 	if (0 != err)
 		return err;
 	
 	for (i = 0; i < bcount; i++) {
-		buflist[i] = videobuf_alloc(msize,type);
-		buflist[i]->i     = i;
-		buflist[i]->boff  = bsize * i;
-		buflist[i]->bsize = bsize;
-		buflist[i]->free  = free;
+		q->bufs[i] = videobuf_alloc(q->msize);
+		q->bufs[i]->i     = i;
+		q->bufs[i]->boff  = bsize * i;
+		q->bufs[i]->bsize = bsize;
 	}
 	dprintk(1,"mmap setup: %d buffers, %d bytes each\n",
 		bcount,bsize);
 	return 0;
 }
 
-int videobuf_mmap_free(struct file *file, struct videobuf_buffer **buflist)
+int videobuf_mmap_free(struct file *file, struct videobuf_queue *q)
 {
 	int i;
 
 	for (i = 0; i < VIDEO_MAX_FRAME; i++)
-		if (buflist[i] && buflist[i]->map)
+		if (q->bufs[i] && q->bufs[i]->map)
 			return -EBUSY;
 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (NULL == buflist[i])
+		if (NULL == q->bufs[i])
 			continue;
-		if (buflist[i]->free)
-			buflist[i]->free(file,buflist[i]);
-		kfree(buflist[i]);
-		buflist[i] = NULL;
+		q->ops->buf_release(file,q->bufs[i]);
+		kfree(q->bufs[i]);
+		q->bufs[i] = NULL;
 	}
 	return 0;
 }
 
 int videobuf_mmap_mapper(struct vm_area_struct *vma,
-			struct videobuf_buffer **buflist)
+			 struct videobuf_queue *q)
 {
 	struct videobuf_mapping *map;
-	int first,last,size,i;
+	int first,last,size,i,retval;
 
+	down(&q->lock);
+	retval = -EINVAL;
 	if (!(vma->vm_flags & VM_WRITE)) {
 		dprintk(1,"mmap app bug: PROT_WRITE please\n");
-		return -EINVAL;
+		goto done;
 	}
 	if (!(vma->vm_flags & VM_SHARED)) {
 		dprintk(1,"mmap app bug: MAP_SHARED please\n");
-		return -EINVAL;
+		goto done;
 	}
 
 	/* look for first buffer to map */
 	for (first = 0; first < VIDEO_MAX_FRAME; first++) {
-		if (NULL == buflist[first])
+		if (NULL == q->bufs[first])
 			continue;
-		if (buflist[first]->boff  == (vma->vm_pgoff << PAGE_SHIFT))
+		if (q->bufs[first]->boff  == (vma->vm_pgoff << PAGE_SHIFT))
 			break;
 	}
 	if (VIDEO_MAX_FRAME == first) {
 		dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
 			(vma->vm_pgoff << PAGE_SHIFT));
-		return -EINVAL;
+		goto done;
 	}
 
 	/* look for last buffer to map */
 	for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
-		if (NULL == buflist[last])
+		if (NULL == q->bufs[last])
 			continue;
-		if (buflist[last]->map)
-			return -EBUSY;
-		size += buflist[last]->bsize;
+		if (q->bufs[last]->map) {
+			retval = -EBUSY;
+			goto done;
+		}
+		size += q->bufs[last]->bsize;
 		if (size == (vma->vm_end - vma->vm_start))
 			break;
 	}
 	if (VIDEO_MAX_FRAME == last) {
 		dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n",
 			(vma->vm_end - vma->vm_start));
-		return -EINVAL;
+		goto done;
 	}
 
 	/* create mapping + update buffer list */
+	retval = -ENOMEM;
 	map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
 	if (NULL == map)
-		return -ENOMEM;
-	for (size = 0, i = first; i <= last; size += buflist[i++]->bsize) {
-		buflist[i]->map   = map;
-		buflist[i]->baddr = vma->vm_start + size;
+		goto done;
+	for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) {
+		q->bufs[i]->map   = map;
+		q->bufs[i]->baddr = vma->vm_start + size;
 	}
 	map->count   = 1;
 	map->start   = vma->vm_start;
 	map->end     = vma->vm_end;
-	map->buflist = buflist;
+	map->q       = q;
 	vma->vm_ops  = &videobuf_vm_ops;
 	vma->vm_flags |= VM_DONTEXPAND;
 	vma->vm_private_data = map;
 	dprintk(1,"mmap %p: %08lx-%08lx pgoff %08lx bufs %d-%d\n",
 		map,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);
-	return 0;
+	retval = 0;
+
+ done:
+	up(&q->lock);
+	return retval;
 }
 
 /* --------------------------------------------------------------------- */
@@ -495,9 +984,25 @@
 EXPORT_SYMBOL_GPL(videobuf_alloc);
 EXPORT_SYMBOL_GPL(videobuf_waiton);
 EXPORT_SYMBOL_GPL(videobuf_iolock);
+
+EXPORT_SYMBOL_GPL(videobuf_queue_init);
+EXPORT_SYMBOL_GPL(videobuf_queue_cancel);
+
 #ifdef HAVE_V4L2
 EXPORT_SYMBOL_GPL(videobuf_status);
+EXPORT_SYMBOL_GPL(videobuf_reqbufs);
+EXPORT_SYMBOL_GPL(videobuf_querybuf);
+EXPORT_SYMBOL_GPL(videobuf_qbuf);
+EXPORT_SYMBOL_GPL(videobuf_dqbuf);
 #endif
+EXPORT_SYMBOL_GPL(videobuf_streamon);
+EXPORT_SYMBOL_GPL(videobuf_streamoff);
+
+EXPORT_SYMBOL_GPL(videobuf_read_start);
+EXPORT_SYMBOL_GPL(videobuf_read_stop);
+EXPORT_SYMBOL_GPL(videobuf_read_stream);
+EXPORT_SYMBOL_GPL(videobuf_read_one);
+EXPORT_SYMBOL_GPL(videobuf_poll_stream);
 
 EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
 EXPORT_SYMBOL_GPL(videobuf_mmap_free);
diff -Nru a/drivers/media/video/video-buf.h b/drivers/media/video/video-buf.h
--- a/drivers/media/video/video-buf.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/media/video/video-buf.h	Tue Jul 16 16:49:41 2002
@@ -103,15 +103,14 @@
  */
 
 struct videobuf_buffer;
-typedef void (*videobuf_buffer_free)(struct file *file,
-				     struct videobuf_buffer *vb);
+struct videobuf_queue;
 
 struct videobuf_mapping {
 	int count;
 	int highmem_ok;
 	unsigned long start;
 	unsigned long end;
-	struct videobuf_buffer **buflist;
+	struct videobuf_queue *q;
 };
 
 #define VBUF_FIELD_EVEN  1
@@ -132,7 +131,6 @@
 	int                     i;
 
 	/* info about the buffer */
-	int                     type;
 	int                     width;
 	int                     height;
 	long                    size;
@@ -146,7 +144,6 @@
 	unsigned long  bsize;            /* buffer size */
 	unsigned long  baddr;            /* buffer addr (userland ptr!) */
 	struct videobuf_mapping *map;
-	videobuf_buffer_free    free;
 
 	/* touched by irq handler */
 	struct list_head        queue;
@@ -157,19 +154,76 @@
 #endif
 };
 
-void* videobuf_alloc(int size, int type);
+struct videobuf_queue_ops {
+	int (*buf_setup)(struct file *file, int *count, int *size);
+	int (*buf_prepare)(struct file *file,struct videobuf_buffer *vb,
+			   int field);
+	void (*buf_queue)(struct file *file,struct videobuf_buffer *vb);
+	void (*buf_release)(struct file *file,struct videobuf_buffer *vb);
+};
+
+struct videobuf_queue {
+        struct semaphore           lock;
+	spinlock_t                 *irqlock;
+	struct pci_dev             *pci;
+
+	int                        type;
+	int                        msize;
+	struct videobuf_buffer     *bufs[VIDEO_MAX_FRAME];
+	struct videobuf_queue_ops  *ops;
+
+	/* capture via mmap() + ioctl(QBUF/DQBUF) */
+	int                        streaming;
+	struct list_head           stream;
+
+	/* capture via read() */
+	int                        reading;
+	int                        read_off;
+	struct videobuf_buffer     *read_buf;
+};
+
+void* videobuf_alloc(int size);
 int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr);
 int videobuf_iolock(struct pci_dev *pci, struct videobuf_buffer *vb);
+
+void videobuf_queue_init(struct videobuf_queue *q,
+			 struct videobuf_queue_ops *ops,
+			 struct pci_dev *pci, spinlock_t *irqlock,
+			 int type, int msize);
+void videobuf_queue_cancel(struct file *file, struct videobuf_queue *q);
+
 #ifdef HAVE_V4L2
-void videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb);
+void videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
+		     int type);
+int videobuf_reqbufs(struct file *file, struct videobuf_queue *q,
+		     struct v4l2_requestbuffers *req);
+int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b);
+int videobuf_qbuf(struct file *file, struct videobuf_queue *q,
+		  struct v4l2_buffer *b);
+int videobuf_dqbuf(struct file *file, struct videobuf_queue *q,
+		   struct v4l2_buffer *b);
 #endif
+int videobuf_streamon(struct file *file, struct videobuf_queue *q);
+int videobuf_streamoff(struct file *file, struct videobuf_queue *q);
 
-int videobuf_mmap_setup(struct file *file, struct videobuf_buffer **buflist,
-			int msize, int bcount, int bsize, int type,
-			videobuf_buffer_free free);
-int videobuf_mmap_free(struct file *file, struct videobuf_buffer **buflist);
+int videobuf_read_start(struct file *file, struct videobuf_queue *q);
+void videobuf_read_stop(struct file *file, struct videobuf_queue *q);
+ssize_t videobuf_read_stream(struct file *file, struct videobuf_queue *q,
+			     char *data, size_t count, loff_t *ppos,
+			     int vbihack);
+ssize_t videobuf_read_one(struct file *file, struct videobuf_queue *q,
+			  char *data, size_t count, loff_t *ppos);
+unsigned int videobuf_poll_stream(struct file *file,
+				  struct videobuf_queue *q,
+				  poll_table *wait);
+
+int videobuf_mmap_setup(struct file *file, struct videobuf_queue *q,
+			int bcount, int bsize);
+int videobuf_mmap_free(struct file *file, struct videobuf_queue *q);
 int videobuf_mmap_mapper(struct vm_area_struct *vma,
-			 struct videobuf_buffer **buflist);
+			 struct videobuf_queue *q);
+
+/* --------------------------------------------------------------------- */
 
 /*
  * Local variables:
diff -Nru a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c
--- a/drivers/mtd/devices/blkmtd.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/mtd/devices/blkmtd.c	Tue Jul 16 16:49:41 2002
@@ -222,7 +222,7 @@
     return err;
   }
 
-  /* Pre 2.4.4 doesnt have space for the block list in the kiobuf */ 
+  /* Pre 2.4.4 doesn't have space for the block list in the kiobuf */ 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
   blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
   if(blocks == NULL) {
@@ -316,7 +316,7 @@
     return 0;
   }
 
-  /* Pre 2.4.4 doesnt have space for the block list in the kiobuf */ 
+  /* Pre 2.4.4 doesn't have space for the block list in the kiobuf */ 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
   blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
   if(blocks == NULL) {
@@ -355,7 +355,7 @@
       int sectorcnt = item->pagecnt << (PAGE_SHIFT - item->rawdevice->sector_bits);
       int max_sectors = KIO_MAX_SECTORS >> (item->rawdevice->sector_bits - 9);
 
-      /* If we are writing to the last page on the device and it doesnt end
+      /* If we are writing to the last page on the device and it doesn't end
        * on a page boundary, subtract the number of sectors that dont exist.
        */
       if(item->rawdevice->partial_last_page && 
diff -Nru a/drivers/mtd/maps/Config.in b/drivers/mtd/maps/Config.in
--- a/drivers/mtd/maps/Config.in	Tue Jul 16 16:49:42 2002
+++ b/drivers/mtd/maps/Config.in	Tue Jul 16 16:49:42 2002
@@ -47,7 +47,7 @@
 fi
 
 if [ "$CONFIG_SUPERH" = "y" ]; then
-   dep_tristate '  CFI Flash device mapped on Hitachi SolutionEngine' CONFIG_MTD_SOLUTIONENGINE $CONFIG_MTD_CFI $CONFIG_SH $CONFIG_MTD_REDBOOT_PARTS
+   dep_tristate '  CFI Flash device mapped on Hitachi SolutionEngine' CONFIG_MTD_SOLUTIONENGINE $CONFIG_MTD_CFI $CONFIG_SUPERH $CONFIG_MTD_REDBOOT_PARTS
 fi
 
 if [ "$CONFIG_ARM" = "y" ]; then
diff -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c
--- a/drivers/net/3c509.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/net/3c509.c	Tue Jul 16 16:49:41 2002
@@ -1259,9 +1259,9 @@
 #ifdef __ISAPNP__
 MODULE_PARM(nopnp, "i");
 MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
+MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
 #endif	/* __ISAPNP__ */
 MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B) ISA/PnP ethernet driver");
-MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
 MODULE_LICENSE("GPL");
 
 int
diff -Nru a/drivers/net/aironet4500_rid.c b/drivers/net/aironet4500_rid.c
--- a/drivers/net/aironet4500_rid.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/net/aironet4500_rid.c	Tue Jul 16 16:49:42 2002
@@ -20,7 +20,7 @@
 #define awc_RID_gen_RidLen 				{(const struct aironet4500_rid_selector *)&aironet4500_RID_Select_General_Config,0x0000, 8,1,1,1,0, 0xffffffff,0x0000, "Length of RID" }
 #define awc_RID_gen_OperatingMode_adhoc 		{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0000,"Opmode IBSS Adhoc operation" } // Without AP
 #define awc_RID_gen_OperatingMode_Infrastructure 	{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0001,"Opmode Infrastructure Station operation" }// With AP
-#define awc_RID_gen_OperatingMode_AP			{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0002,"Opmode Access Point" } // Aironet doesnt release info on use 
+#define awc_RID_gen_OperatingMode_AP			{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0002,"Opmode Access Point" } // Aironet doesn't release info on use 
 #define awc_RID_gen_OperatingMode_AP_and_repeater 	{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0003,"Opmode Access Point and Repeater" } // no info
 #define awc_RID_gen_OperatingMode_No_payload_modify	{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000100,0x0100,"Opmode Payload without modify" } 
 #define awc_RID_gen_OperatingMode_LLC_802_3_convert	{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000100,0x0000,"Opmode LLC -> 802.3 convert" }
diff -Nru a/drivers/net/bonding.c b/drivers/net/bonding.c
--- a/drivers/net/bonding.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/net/bonding.c	Tue Jul 16 16:49:42 2002
@@ -176,6 +176,16 @@
  *              Steve Mead <steve.mead at comdev dot cc>
  *     - Port Gleb Natapov's multicast support patchs from 2.4.12
  *       to 2.4.18 adding support for multicast.
+ *
+ * 2002/06/17 - Tony Cureington <tony.cureington * hp_com>
+ *     - corrected uninitialized pointer (ifr.ifr_data) in bond_check_dev_link;
+ *       actually changed function to use ETHTOOL, then MIIPHY, and finally
+ *       MIIREG to determine the link status
+ *     - fixed bad ifr_data pointer assignments in bond_ioctl
+ *     - corrected mode 1 being reported as active-backup in bond_get_info;
+ *       also added text to distinguish type of load balancing (rr or xor)
+ *     - change arp_ip_target module param from "1-12s" (array of 12 ptrs)
+ *       to "s" (a single ptr)
  */
 
 #include <linux/config.h>
@@ -210,6 +220,9 @@
 #include <linux/smp.h>
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+
 
 /* monitor all links that often (in milliseconds). <=0 disables monitoring */
 #ifndef BOND_LINK_MON_INTERV
@@ -253,7 +266,7 @@
 MODULE_PARM(mode, "i");
 MODULE_PARM(arp_interval, "i");
 MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
-MODULE_PARM(arp_ip_target, "1-12s");
+MODULE_PARM(arp_ip_target, "s");
 MODULE_PARM_DESC(arp_ip_target, "arp target in n.n.n.n form");
 MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor");
 MODULE_PARM(updelay, "i");
@@ -386,21 +399,51 @@
 {
 	static int (* ioctl)(struct net_device *, struct ifreq *, int);
 	struct ifreq ifr;
-	u16 *data = (u16 *)&ifr.ifr_data;
-		
-	/* data[0] automagically filled by the ioctl */
-	data[1] = 1; /* MII location 1 reports Link Status */
+	struct mii_ioctl_data mii;
+	struct ethtool_value etool;
+
+	if ((ioctl = dev->do_ioctl) != NULL)  { /* ioctl to access MII */
+		/* TODO: set pointer to correct ioctl on a per team member */
+		/*       bases to make this more efficient. that is, once  */
+		/*       we determine the correct ioctl, we will always    */
+		/*       call it and not the others for that team          */
+		/*       member.                                           */
+
+		/* try SOICETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */
+		/* for a period of time; we need to encourage link status  */
+		/* be reported by network drivers in real time; if the     */
+		/* value is cached, the mmimon module parm may have no     */
+		/* effect...                                               */
+	        etool.cmd = ETHTOOL_GLINK;
+	        ifr.ifr_data = (char*)&etool;
+		if (ioctl(dev, &ifr, SIOCETHTOOL) == 0) {
+			if (etool.data == 1) {
+				return(MII_LINK_READY);
+			} 
+			else { 
+				return(0);
+			} 
+		}
+
+		ifr.ifr_data = (char*)&mii;
+                /* try MIIPHY first then, if that doesn't work, try MIIREG */
+		if (ioctl(dev, &ifr, SIOCGMIIPHY) == 0) {
+			/* now, mii.phy_id contains info about link status :
+			- mii.phy_id & 0x04 means link up
+			- mii.phy_id & 0x20 means end of auto-negociation
+			*/
+			return mii.phy_id;
+		}
+
+		mii.reg_num = 1; /* the MII register we want to read */  
+		if (ioctl(dev, &ifr, SIOCGMIIREG) == 0) {
+			/* mii.val_out contians the same link info as phy_id */
+			/* above                                             */
+			return mii.val_out;
+		}
 
-	if (((ioctl = dev->do_ioctl) != NULL) &&  /* ioctl to access MII */
-	    (ioctl(dev, &ifr, SIOCGMIIPHY) == 0)) {
-		/* now, data[3] contains info about link status :
-		   - data[3] & 0x04 means link up
-		   - data[3] & 0x20 means end of auto-negociation
-		*/
-		return data[3];
-	} else {
-		return MII_LINK_READY;  /* spoof link up ( we can't check it) */
 	}
+	return MII_LINK_READY;  /* spoof link up ( we can't check it) */
 }
 
 static u16 bond_check_mii_link(bonding_t *bond)
@@ -1707,7 +1750,7 @@
 
 	switch (cmd) {
 	case SIOCGMIIPHY:
-		data = (u16 *)&ifr->ifr_data;
+		data = (u16 *)ifr->ifr_data;
 		if (data == NULL) {
 			return -EINVAL;
 		}
@@ -1718,7 +1761,7 @@
 		 * We do this again just in case we were called by SIOCGMIIREG
 		 * instead of SIOCGMIIPHY.
 		 */
-		data = (u16 *)&ifr->ifr_data;
+		data = (u16 *)ifr->ifr_data;
 		if (data == NULL) {
 			return -EINVAL;
 		}
@@ -2035,7 +2078,28 @@
 		link = bond_check_mii_link(bond);
 
 		len += sprintf(buf + len, "Bonding Mode: ");
-		len += sprintf(buf + len, "%s\n", mode ? "active-backup" : "load balancing");
+
+		switch (mode) {
+			case BOND_MODE_ACTIVEBACKUP:
+				len += sprintf(buf + len, "%s\n", 
+						"active-backup");
+			break;
+
+			case BOND_MODE_ROUNDROBIN:
+				len += sprintf(buf + len, "%s\n", 
+						"load balancing (round-robin)");
+			break;
+
+			case BOND_MODE_XOR:
+				len += sprintf(buf + len, "%s\n", 
+						"load balancing (xor)");
+			break;
+
+			default:
+				len += sprintf(buf + len, "%s\n", 
+						"unknown");
+			break;
+		}
 
 		if (mode == BOND_MODE_ACTIVEBACKUP) {
 			read_lock_irqsave(&bond->lock, flags);
@@ -2282,7 +2346,32 @@
 	}
 	memset(dev_bonds, 0, max_bonds*sizeof(struct net_device));
 
+	if (updelay < 0) {
+		printk(KERN_WARNING 
+		       "bonding_init(): updelay module parameter (%d), "
+		       "not in range 0-%d, so it was reset to 0\n",
+		       updelay, INT_MAX);
+		updelay = 0;
+	}
+
+	if (downdelay < 0) {
+		printk(KERN_WARNING 
+		       "bonding_init(): downdelay module parameter (%d), "
+		       "not in range 0-%d, so it was reset to 0\n",
+		       downdelay, INT_MAX);
+		downdelay = 0;
+	}
+
+	if (arp_interval < 0) {
+		printk(KERN_WARNING 
+		       "bonding_init(): arp_interval module parameter (%d), "
+		       "not in range 0-%d, so it was reset to %d\n",
+		       arp_interval, INT_MAX, BOND_LINK_ARP_INTERV);
+		arp_interval = BOND_LINK_ARP_INTERV;
+	}
+
 	if (arp_ip_target) {
+		/* TODO: check and log bad ip address */
 		if (my_inet_aton(arp_ip_target, &arp_target) == 0)  {
 			arp_interval = 0;
 		}
diff -Nru a/drivers/net/bsd_comp.c b/drivers/net/bsd_comp.c
--- a/drivers/net/bsd_comp.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/net/bsd_comp.c	Tue Jul 16 16:49:42 2002
@@ -65,6 +65,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/string.h>
 
 #include <linux/ppp_defs.h>
 
diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c
--- a/drivers/net/eepro100.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/net/eepro100.c	Tue Jul 16 16:49:43 2002
@@ -524,8 +524,6 @@
 static int eepro100_init_one(struct pci_dev *pdev,
 		const struct pci_device_id *ent);
 static void eepro100_remove_one (struct pci_dev *pdev);
-static int eepro100_suspend (struct pci_dev *pdev, u32 state);
-static int eepro100_resume (struct pci_dev *pdev);
 
 static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len);
 static int mdio_read(long ioaddr, int phy_id, int location);
diff -Nru a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
--- a/drivers/net/irda/irda-usb.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/net/irda/irda-usb.c	Tue Jul 16 16:49:42 2002
@@ -273,7 +273,7 @@
                       frame, IRDA_USB_SPEED_MTU,
                       speed_bulk_callback, self);
 	urb->transfer_buffer_length = USB_IRDA_HEADER;
-	urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
+	urb->transfer_flags = USB_ASYNC_UNLINK;
 	urb->timeout = MSECS_TO_JIFFIES(100);
 
 	/* Irq disabled -> GFP_ATOMIC */
@@ -410,7 +410,7 @@
 	urb->transfer_buffer_length = skb->len;
 	/* Note : unlink *must* be Asynchronous because of the code in 
 	 * irda_usb_net_timeout() -> call in irq - Jean II */
-	urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
+	urb->transfer_flags = USB_ASYNC_UNLINK;
 	/* This flag (USB_ZERO_PACKET) indicates that what we send is not
 	 * a continuous stream of data but separate packets.
 	 * In this case, the USB layer will insert an empty USB frame (TD)
@@ -736,7 +736,6 @@
 		      usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), 
 		      skb->data, skb->truesize,
                       irda_usb_receive, skb);
-	urb->transfer_flags = USB_QUEUE_BULK;
 	/* Note : unlink *must* be synchronous because of the code in 
 	 * irda_usb_net_close() -> free the skb - Jean II */
 	urb->status = 0;
diff -Nru a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
--- a/drivers/net/ppp_deflate.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/net/ppp_deflate.c	Tue Jul 16 16:49:42 2002
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/string.h>
 
 #include <linux/ppp_defs.h>
 #include <linux/ppp-comp.h>
diff -Nru a/drivers/net/sunhme.c b/drivers/net/sunhme.c
--- a/drivers/net/sunhme.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/net/sunhme.c	Tue Jul 16 16:49:42 2002
@@ -2201,7 +2201,7 @@
 	 */
 	if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) {
 		if (request_irq(dev->irq, &happy_meal_interrupt,
-				SA_SHIRQ, "HAPPY MEAL", (void *)dev)) {
+				SA_SHIRQ, dev->name, (void *)dev)) {
 			HMD(("EAGAIN\n"));
 #ifdef __sparc__
 			printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n",
diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/net/tg3.c	Tue Jul 16 16:49:42 2002
@@ -52,8 +52,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"0.99"
-#define DRV_MODULE_RELDATE	"Jun 11, 2002"
+#define DRV_MODULE_VERSION	"0.99-NAPI"
+#define DRV_MODULE_RELDATE	"Jun 20, 2002"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -404,7 +404,8 @@
 		break;
 
 	default:
-		printk(KERN_WARNING "%s: Invalid power state (%d) requested.\n",
+		printk(KERN_WARNING PFX "%s: Invalid power state (%d) "
+		       "requested.\n",
 		       tp->dev->name, state);
 		return -EINVAL;
 	};
@@ -490,9 +491,9 @@
 static void tg3_link_report(struct tg3 *tp)
 {
 	if (!netif_carrier_ok(tp->dev)) {
-		printk("%s: Link is down.\n", tp->dev->name);
+		printk(KERN_INFO PFX "%s: Link is down.\n", tp->dev->name);
 	} else {
-		printk("%s: Link is up at %d Mbps, %s duplex.\n",
+		printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
 		       tp->dev->name,
 		       (tp->link_config.active_speed == SPEED_1000 ?
 			1000 :
@@ -501,7 +502,8 @@
 		       (tp->link_config.active_duplex == DUPLEX_FULL ?
 			"full" : "half"));
 
-		printk("%s: Flow control is %s for TX and %s for RX.\n",
+		printk(KERN_INFO PFX "%s: Flow control is %s for TX and "
+		       "%s for RX.\n",
 		       tp->dev->name,
 		       (tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "on" : "off",
 		       (tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "on" : "off");
@@ -1725,7 +1727,7 @@
 #if TG3_VLAN_TAG_USED
 static int tg3_vlan_rx(struct tg3 *tp, struct sk_buff *skb, u16 vlan_tag)
 {
-	return vlan_hwaccel_rx(skb, tp->vlgrp, vlan_tag);
+	return vlan_hwaccel_receive_skb(skb, tp->vlgrp, vlan_tag);
 }
 #endif
 
@@ -1753,16 +1755,18 @@
  * If both the host and chip were to write into the same ring, cache line
  * eviction could occur since both entities want it in an exclusive state.
  */
-static void tg3_rx(struct tg3 *tp)
+static int tg3_rx(struct tg3 *tp, int budget)
 {
 	u32 work_mask;
 	u32 rx_rcb_ptr = tp->rx_rcb_ptr;
 	u16 hw_idx, sw_idx;
+	int received;
 
 	hw_idx = tp->hw_status->idx[0].rx_producer;
 	sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE;
 	work_mask = 0;
-	while (sw_idx != hw_idx) {
+	received = 0;
+	while (sw_idx != hw_idx && budget > 0) {
 		struct tg3_rx_buffer_desc *desc = &tp->rx_rcb[sw_idx];
 		unsigned int len;
 		struct sk_buff *skb;
@@ -1860,9 +1864,11 @@
 				    desc->err_vlan & RXD_VLAN_MASK);
 		} else
 #endif
-			netif_rx(skb);
+			netif_receive_skb(skb);
 
 		tp->dev->last_rx = jiffies;
+		received++;
+		budget--;
 
 next_pkt:
 		(*post_ptr)++;
@@ -1894,110 +1900,17 @@
 			     sw_idx);
 	}
 #endif
-}
-
-#define PKT_RATE_LOW		22000
-#define PKT_RATE_HIGH		61000
-
-static void tg3_rate_sample(struct tg3 *tp, unsigned long ticks)
-{
-	u32 delta, rx_now, tx_now;
-	int new_vals, do_tx, do_rx;
-
-	rx_now = tp->hw_stats->rx_ucast_packets.low;
-	tx_now = tp->hw_stats->COS_out_packets[0].low;
-
-	delta  = (rx_now - tp->last_rx_count);
-	delta += (tx_now - tp->last_tx_count);
-	delta /= (ticks / tp->coalesce_config.rate_sample_jiffies);
-
-	tp->last_rx_count = rx_now;
-	tp->last_tx_count = tx_now;
-
-	new_vals = 0;
-	do_tx = (tp->tg3_flags & TG3_FLAG_ADAPTIVE_TX) != 0;
-	do_rx = (tp->tg3_flags & TG3_FLAG_ADAPTIVE_RX) != 0;
-	if (delta < tp->coalesce_config.pkt_rate_low) {
-		if (do_rx &&
-		    tp->coalesce_config.rx_max_coalesced_frames !=
-		    tp->coalesce_config.rx_max_coalesced_frames_low) {
-			tp->coalesce_config.rx_max_coalesced_frames =
-				LOW_RXMAX_FRAMES;
-			tp->coalesce_config.rx_coalesce_ticks =
-				LOW_RXCOL_TICKS;
-			new_vals = 1;
-		}
-		if (do_tx &&
-		    tp->coalesce_config.tx_max_coalesced_frames !=
-		    tp->coalesce_config.tx_max_coalesced_frames_low) {
-			tp->coalesce_config.tx_max_coalesced_frames =
-				tp->coalesce_config.tx_max_coalesced_frames_low;
-			tp->coalesce_config.tx_coalesce_ticks =
-				tp->coalesce_config.tx_coalesce_ticks_low;
-			new_vals = 1;
-		}
-	} else if (delta < tp->coalesce_config.pkt_rate_high) {
-		if (do_rx &&
-		    tp->coalesce_config.rx_max_coalesced_frames !=
-		    tp->coalesce_config.rx_max_coalesced_frames_def) {
-			tp->coalesce_config.rx_max_coalesced_frames =
-				tp->coalesce_config.rx_max_coalesced_frames_def;
-			tp->coalesce_config.rx_coalesce_ticks =
-				tp->coalesce_config.rx_coalesce_ticks_def;
-			new_vals = 1;
-		}
-		if (do_tx &&
-		    tp->coalesce_config.tx_max_coalesced_frames !=
-		    tp->coalesce_config.tx_max_coalesced_frames_def) {
-			tp->coalesce_config.tx_max_coalesced_frames =
-				tp->coalesce_config.tx_max_coalesced_frames_def;
-			tp->coalesce_config.tx_coalesce_ticks =
-				tp->coalesce_config.tx_coalesce_ticks_def;
-			new_vals = 1;
-		}
-	} else {
-		if (do_rx &&
-		    tp->coalesce_config.rx_max_coalesced_frames !=
-		    tp->coalesce_config.rx_max_coalesced_frames_high) {
-			tp->coalesce_config.rx_max_coalesced_frames =
-				tp->coalesce_config.rx_max_coalesced_frames_high;
-			tp->coalesce_config.rx_coalesce_ticks =
-				tp->coalesce_config.rx_coalesce_ticks_high;
-			new_vals = 1;
-		}
-		if (do_tx &&
-		    tp->coalesce_config.tx_max_coalesced_frames !=
-		    tp->coalesce_config.tx_max_coalesced_frames_high) {
-			tp->coalesce_config.tx_max_coalesced_frames =
-				tp->coalesce_config.tx_max_coalesced_frames_high;
-			tp->coalesce_config.tx_coalesce_ticks =
-				tp->coalesce_config.tx_coalesce_ticks_high;
-			new_vals = 1;
-		}
-	}
-
-	if (new_vals) {
-		if (do_rx) {
-			tw32(HOSTCC_RXCOL_TICKS,
-			     tp->coalesce_config.rx_coalesce_ticks);
-			tw32(HOSTCC_RXMAX_FRAMES,
-			     tp->coalesce_config.rx_max_coalesced_frames);
-		}
-		if (do_tx) {
-			tw32(HOSTCC_TXCOL_TICKS,
-			     tp->coalesce_config.tx_coalesce_ticks);
-			tw32(HOSTCC_TXMAX_FRAMES,
-			     tp->coalesce_config.tx_max_coalesced_frames);
-		}
-	}
 
-	tp->last_rate_sample = jiffies;
+	return received;
 }
 
-static void tg3_interrupt_main_work(struct tg3 *tp)
+static int tg3_poll(struct net_device *netdev, int *budget)
 {
+	struct tg3 *tp = netdev->priv;
 	struct tg3_hw_status *sblk = tp->hw_status;
-	int did_pkts;
+	int done;
+
+	spin_lock_irq(&tp->lock);
 
 	if (!(tp->tg3_flags &
 	      (TG3_FLAG_USE_LINKCHG_REG |
@@ -2009,50 +1922,65 @@
 		}
 	}
 
-	did_pkts = 0;
+	if (sblk->idx[0].tx_consumer != tp->tx_cons)
+		tg3_tx(tp);
+
+	done = 1;
 	if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) {
-		tg3_rx(tp);
-		did_pkts = 1;
+		int orig_budget = *budget;
+		int work_done;
+
+		if (orig_budget > netdev->quota)
+			orig_budget = netdev->quota;
+
+		work_done = tg3_rx(tp, orig_budget);
+
+		*budget -= work_done;
+		netdev->quota -= work_done;
+
+		if (work_done >= orig_budget)
+			done = 0;
 	}
 
-	if (sblk->idx[0].tx_consumer != tp->tx_cons) {
-		tg3_tx(tp);
-		did_pkts = 1;
+	if (done) {
+		netif_rx_complete(netdev);
+		tg3_enable_ints(tp);
 	}
 
-	if (did_pkts &&
-	    (tp->tg3_flags & (TG3_FLAG_ADAPTIVE_RX | TG3_FLAG_ADAPTIVE_TX))) {
-		unsigned long ticks = jiffies - tp->last_rate_sample;
+	spin_unlock_irq(&tp->lock);
 
-		if (ticks >= tp->coalesce_config.rate_sample_jiffies)
-			tg3_rate_sample(tp, ticks);
-	}
+	return (done ? 0 : 1);
 }
 
-static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static __inline__ void tg3_interrupt_main_work(struct net_device *dev, struct tg3 *tp)
 {
-	struct net_device *dev = dev_id;
-	struct tg3 *tp = dev->priv;
 	struct tg3_hw_status *sblk = tp->hw_status;
+	int work_exists = 0;
 
-	spin_lock(&tp->lock);
-
-	while (sblk->status & SD_STATUS_UPDATED) {
-		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-			     0x00000001);
-		sblk->status &= ~SD_STATUS_UPDATED;
+	if (!(tp->tg3_flags &
+	      (TG3_FLAG_USE_LINKCHG_REG |
+	       TG3_FLAG_POLL_SERDES))) {
+		if (sblk->status & SD_STATUS_LINK_CHG)
+			work_exists = 1;
+	}
+	if (sblk->idx[0].tx_consumer != tp->tx_cons ||
+	    sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
+		work_exists = 1;
 
-		tg3_interrupt_main_work(tp);
+	if (!work_exists)
+		return;
 
-		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-			     0x00000000);
-		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+	if (netif_rx_schedule_prep(dev)) {
+		tw32(TG3PCI_MISC_HOST_CTRL,
+		     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
+		__netif_rx_schedule(dev);
+	} else {
+		printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
+		       dev->name);
 	}
-
-	spin_unlock(&tp->lock);
 }
 
-static void tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *regs)
+static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
 	struct tg3 *tp = dev->priv;
@@ -2061,29 +1989,15 @@
 	spin_lock(&tp->lock);
 
 	if (sblk->status & SD_STATUS_UPDATED) {
-		u32 oldtag;
-
 		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
 			     0x00000001);
-		oldtag = sblk->status_tag;
-
-		while (1) {
-			u32 newtag;
-
-			sblk->status &= ~SD_STATUS_UPDATED;
-			barrier();
+		sblk->status &= ~SD_STATUS_UPDATED;
 
-			tg3_interrupt_main_work(tp);
+		tg3_interrupt_main_work(dev, tp);
 
-			newtag = sblk->status_tag;
-			if (newtag == oldtag) {
-				tw32_mailbox(MAILBOX_INTERRUPT_0 +
-					     TG3_64BIT_REG_LOW,
-					     newtag << 24);
-				break;
-			}
-			oldtag = newtag;
-		}
+		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+			     0x00000000);
+		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 	}
 
 	spin_unlock(&tp->lock);
@@ -2096,7 +2010,7 @@
 {
 	struct tg3 *tp = dev->priv;
 
-	printk(KERN_ERR "%s: transmit timed out, resetting\n",
+	printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
 	       dev->name);
 
 	spin_lock_irq(&tp->lock);
@@ -3638,24 +3552,16 @@
 		udelay(10);
 	}
 
-	tw32(HOSTCC_RXCOL_TICKS,
-	     tp->coalesce_config.rx_coalesce_ticks);
-	tw32(HOSTCC_RXMAX_FRAMES,
-	     tp->coalesce_config.rx_max_coalesced_frames);
-	tw32(HOSTCC_RXCOAL_TICK_INT,
-	     tp->coalesce_config.rx_coalesce_ticks_during_int);
-	tw32(HOSTCC_RXCOAL_MAXF_INT,
-	     tp->coalesce_config.rx_max_coalesced_frames_during_int);
-	tw32(HOSTCC_TXCOL_TICKS,
-	     tp->coalesce_config.tx_coalesce_ticks);
-	tw32(HOSTCC_TXMAX_FRAMES,
-	     tp->coalesce_config.tx_max_coalesced_frames);
-	tw32(HOSTCC_TXCOAL_TICK_INT,
-	     tp->coalesce_config.tx_coalesce_ticks_during_int);
-	tw32(HOSTCC_TXCOAL_MAXF_INT,
-	     tp->coalesce_config.tx_max_coalesced_frames_during_int);
+	tw32(HOSTCC_RXCOL_TICKS, 0);
+	tw32(HOSTCC_RXMAX_FRAMES, 1);
+	tw32(HOSTCC_RXCOAL_TICK_INT, 0);
+	tw32(HOSTCC_RXCOAL_MAXF_INT, 1);
+	tw32(HOSTCC_TXCOL_TICKS, LOW_TXCOL_TICKS);
+	tw32(HOSTCC_TXMAX_FRAMES, LOW_RXMAX_FRAMES);
+	tw32(HOSTCC_TXCOAL_TICK_INT, 0);
+	tw32(HOSTCC_TXCOAL_MAXF_INT, 0);
 	tw32(HOSTCC_STAT_COAL_TICKS,
-	     tp->coalesce_config.stats_coalesce_ticks);
+	     DEFAULT_STAT_COAL_TICKS);
 
 	/* Status/statistics block address. */
 	tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH,
@@ -3806,24 +3712,22 @@
 
 	spin_lock_irq(&tp->lock);
 
-	if (!(tp->tg3_flags & TG3_FLAG_TAGGED_IRQ_STATUS)) {
-		/* All of this garbage is because on the 5700 the
-		 * mailbox/status_block protocol the chip uses with
-		 * the cpu is race prone.
-		 */
-		if (tp->hw_status->status & SD_STATUS_UPDATED) {
-			tw32(GRC_LOCAL_CTRL,
-			     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
-		} else {
-			tw32(HOSTCC_MODE,
-			     (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW));
-		}
+	/* All of this garbage is because when using non-tagged
+	 * IRQ status the mailbox/status_block protocol the chip
+	 * uses with the cpu is race prone.
+	 */
+	if (tp->hw_status->status & SD_STATUS_UPDATED) {
+		tw32(GRC_LOCAL_CTRL,
+		     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+	} else {
+		tw32(HOSTCC_MODE,
+		     (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW));
+	}
 
-		if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
-			tg3_halt(tp);
-			tg3_init_rings(tp);
-			tg3_init_hw(tp);
-		}
+	if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
+		tg3_halt(tp);
+		tg3_init_rings(tp);
+		tg3_init_hw(tp);
 	}
 
 	/* This part only runs once per second. */
@@ -3893,12 +3797,8 @@
 	if (err)
 		return err;
 
-	if (tp->tg3_flags & TG3_FLAG_TAGGED_IRQ_STATUS)
-		err = request_irq(dev->irq, tg3_interrupt_tagged,
-				  SA_SHIRQ, dev->name, dev);
-	else
-		err = request_irq(dev->irq, tg3_interrupt,
-				  SA_SHIRQ, dev->name, dev);
+	err = request_irq(dev->irq, tg3_interrupt,
+			  SA_SHIRQ, dev->name, dev);
 
 	if (err) {
 		tg3_free_consistent(tp);
@@ -3914,13 +3814,8 @@
 		tg3_halt(tp);
 		tg3_free_rings(tp);
 	} else {
-		if (tp->tg3_flags & TG3_FLAG_TAGGED_IRQ_STATUS) {
-			tp->timer_offset = HZ;
-			tp->timer_counter = tp->timer_multiplier = 1;
-		} else {
-			tp->timer_offset = HZ / 10;
-			tp->timer_counter = tp->timer_multiplier = 10;
-		}
+		tp->timer_offset = HZ / 10;
+		tp->timer_counter = tp->timer_multiplier = 10;
 
 		init_timer(&tp->timer);
 		tp->timer.expires = jiffies + tp->timer_offset;
@@ -4240,10 +4135,7 @@
 	unsigned long ret;
 
 #if (BITS_PER_LONG == 32)
-	if (val->high != 0)
-		ret = ~0UL;
-	else
-		ret = val->low;
+	ret = val->low;
 #else
 	ret = ((u64)val->high << 32) | ((u64)val->low);
 #endif
@@ -4486,177 +4378,6 @@
 	return orig_p;
 }
 
-static void tg3_to_ethtool_coal(struct tg3 *tp,
-				struct ethtool_coalesce *ecoal)
-{
-	ecoal->rx_coalesce_usecs =
-		tp->coalesce_config.rx_coalesce_ticks_def;
-	ecoal->rx_max_coalesced_frames =
-		tp->coalesce_config.rx_max_coalesced_frames_def;
-	ecoal->rx_coalesce_usecs_irq =
-		tp->coalesce_config.rx_coalesce_ticks_during_int_def;
-	ecoal->rx_max_coalesced_frames_irq =
-		tp->coalesce_config.rx_max_coalesced_frames_during_int_def;
-
-	ecoal->tx_coalesce_usecs =
-		tp->coalesce_config.tx_coalesce_ticks_def;
-	ecoal->tx_max_coalesced_frames =
-		tp->coalesce_config.tx_max_coalesced_frames_def;
-	ecoal->tx_coalesce_usecs_irq =
-		tp->coalesce_config.tx_coalesce_ticks_during_int_def;
-	ecoal->tx_max_coalesced_frames_irq =
-		tp->coalesce_config.tx_max_coalesced_frames_during_int_def;
-
-	ecoal->stats_block_coalesce_usecs =
-		tp->coalesce_config.stats_coalesce_ticks_def;
-
-	ecoal->use_adaptive_rx_coalesce =
-		(tp->tg3_flags & TG3_FLAG_ADAPTIVE_RX) != 0;
-	ecoal->use_adaptive_tx_coalesce =
-		(tp->tg3_flags & TG3_FLAG_ADAPTIVE_TX) != 0;
-
-	ecoal->pkt_rate_low =
-		tp->coalesce_config.pkt_rate_low;
-	ecoal->rx_coalesce_usecs_low =
-		tp->coalesce_config.rx_coalesce_ticks_low;
-	ecoal->rx_max_coalesced_frames_low =
-		tp->coalesce_config.rx_max_coalesced_frames_low;
-	ecoal->tx_coalesce_usecs_low =
-		tp->coalesce_config.tx_coalesce_ticks_low;
-	ecoal->tx_max_coalesced_frames_low =
-		tp->coalesce_config.tx_max_coalesced_frames_low;
-
-	ecoal->pkt_rate_high =
-		tp->coalesce_config.pkt_rate_high;
-	ecoal->rx_coalesce_usecs_high =
-		tp->coalesce_config.rx_coalesce_ticks_high;
-	ecoal->rx_max_coalesced_frames_high =
-		tp->coalesce_config.rx_max_coalesced_frames_high;
-	ecoal->tx_coalesce_usecs_high =
-		tp->coalesce_config.tx_coalesce_ticks_high;
-	ecoal->tx_max_coalesced_frames_high =
-		tp->coalesce_config.tx_max_coalesced_frames_high;
-
-	ecoal->rate_sample_interval =
-		tp->coalesce_config.rate_sample_jiffies / HZ;
-}
-
-static int tg3_from_ethtool_coal(struct tg3 *tp,
-				 struct ethtool_coalesce *ecoal)
-{
-	/* Make sure we are not getting garbage. */
-	if ((ecoal->rx_coalesce_usecs == 0 &&
-	     ecoal->rx_max_coalesced_frames == 0) ||
-	    (ecoal->tx_coalesce_usecs == 0 &&
-	     ecoal->tx_max_coalesced_frames == 0) ||
-	    ecoal->stats_block_coalesce_usecs == 0)
-		return -EINVAL;
-	if (ecoal->use_adaptive_rx_coalesce ||
-	    ecoal->use_adaptive_tx_coalesce) {
-		if (ecoal->pkt_rate_low > ecoal->pkt_rate_high)
-			return -EINVAL;
-		if (ecoal->rate_sample_interval == 0)
-			return -EINVAL;
-		if (ecoal->use_adaptive_rx_coalesce &&
-		    ((ecoal->rx_coalesce_usecs_low == 0 &&
-		      ecoal->rx_max_coalesced_frames_low == 0) ||
-		     (ecoal->rx_coalesce_usecs_high == 0 &&
-		      ecoal->rx_max_coalesced_frames_high == 0)))
-			return -EINVAL;
-		if (ecoal->use_adaptive_tx_coalesce &&
-		    ((ecoal->tx_coalesce_usecs_low == 0 &&
-		      ecoal->tx_max_coalesced_frames_low == 0) ||
-		     (ecoal->tx_coalesce_usecs_high == 0 &&
-		      ecoal->tx_max_coalesced_frames_high == 0)))
-			return -EINVAL;
-	}
-
-	/* Looks good, let it rip. */
-	spin_lock_irq(&tp->lock);
-	tp->coalesce_config.rx_coalesce_ticks =
-		tp->coalesce_config.rx_coalesce_ticks_def =
-		ecoal->rx_coalesce_usecs;
-	tp->coalesce_config.rx_max_coalesced_frames =
-		tp->coalesce_config.rx_max_coalesced_frames_def =
-		ecoal->rx_max_coalesced_frames;
-	tp->coalesce_config.rx_coalesce_ticks_during_int =
-		tp->coalesce_config.rx_coalesce_ticks_during_int_def =
-		ecoal->rx_coalesce_usecs_irq;
-	tp->coalesce_config.rx_max_coalesced_frames_during_int =
-		tp->coalesce_config.rx_max_coalesced_frames_during_int_def =
-		ecoal->rx_max_coalesced_frames_irq;
-	tp->coalesce_config.tx_coalesce_ticks =
-		tp->coalesce_config.tx_coalesce_ticks_def =
-		ecoal->tx_coalesce_usecs;
-	tp->coalesce_config.tx_max_coalesced_frames =
-		tp->coalesce_config.tx_max_coalesced_frames_def =
-		ecoal->tx_max_coalesced_frames;
-	tp->coalesce_config.tx_coalesce_ticks_during_int =
-		tp->coalesce_config.tx_coalesce_ticks_during_int_def =
-		ecoal->tx_coalesce_usecs_irq;
-	tp->coalesce_config.tx_max_coalesced_frames_during_int =
-		tp->coalesce_config.tx_max_coalesced_frames_during_int_def =
-		ecoal->tx_max_coalesced_frames_irq;
-	tp->coalesce_config.stats_coalesce_ticks =
-		tp->coalesce_config.stats_coalesce_ticks_def =
-		ecoal->stats_block_coalesce_usecs;
-
-	if (ecoal->use_adaptive_rx_coalesce)
-		tp->tg3_flags |= TG3_FLAG_ADAPTIVE_RX;
-	else
-		tp->tg3_flags &= ~TG3_FLAG_ADAPTIVE_RX;
-	if (ecoal->use_adaptive_tx_coalesce)
-		tp->tg3_flags |= TG3_FLAG_ADAPTIVE_TX;
-	else
-		tp->tg3_flags &= ~TG3_FLAG_ADAPTIVE_TX;
-
-	tp->coalesce_config.pkt_rate_low = ecoal->pkt_rate_low;
-	tp->coalesce_config.pkt_rate_high = ecoal->pkt_rate_high;
-	tp->coalesce_config.rate_sample_jiffies =
-		ecoal->rate_sample_interval * HZ;
-
-	tp->coalesce_config.rx_coalesce_ticks_low =
-		ecoal->rx_coalesce_usecs_low;
-	tp->coalesce_config.rx_max_coalesced_frames_low =
-		ecoal->rx_max_coalesced_frames_low;
-	tp->coalesce_config.tx_coalesce_ticks_low =
-		ecoal->tx_coalesce_usecs_low;
-	tp->coalesce_config.tx_max_coalesced_frames_low =
-		ecoal->tx_max_coalesced_frames_low;
-
-	tp->coalesce_config.rx_coalesce_ticks_high =
-		ecoal->rx_coalesce_usecs_high;
-	tp->coalesce_config.rx_max_coalesced_frames_high =
-		ecoal->rx_max_coalesced_frames_high;
-	tp->coalesce_config.tx_coalesce_ticks_high =
-		ecoal->tx_coalesce_usecs_high;
-	tp->coalesce_config.tx_max_coalesced_frames_high =
-		ecoal->tx_max_coalesced_frames_high;
-
-	tw32(HOSTCC_RXCOL_TICKS,
-	     tp->coalesce_config.rx_coalesce_ticks_def);
-	tw32(HOSTCC_RXMAX_FRAMES,
-	     tp->coalesce_config.rx_max_coalesced_frames_def);
-	tw32(HOSTCC_RXCOAL_TICK_INT,
-	     tp->coalesce_config.rx_coalesce_ticks_during_int_def);
-	tw32(HOSTCC_RXCOAL_MAXF_INT,
-	     tp->coalesce_config.rx_max_coalesced_frames_during_int_def);
-	tw32(HOSTCC_TXCOL_TICKS,
-	     tp->coalesce_config.tx_coalesce_ticks_def);
-	tw32(HOSTCC_TXMAX_FRAMES,
-	     tp->coalesce_config.tx_max_coalesced_frames_def);
-	tw32(HOSTCC_TXCOAL_TICK_INT,
-	     tp->coalesce_config.tx_coalesce_ticks_during_int_def);
-	tw32(HOSTCC_TXCOAL_MAXF_INT,
-	     tp->coalesce_config.tx_max_coalesced_frames_during_int_def);
-	tw32(HOSTCC_STAT_COAL_TICKS,
-	     tp->coalesce_config.stats_coalesce_ticks_def);
-
-	spin_unlock_irq(&tp->lock);
-
-	return 0;
-}
-
 static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
 {
 	struct tg3 *tp = dev->priv;
@@ -4708,8 +4429,8 @@
 		cmd.phy_address = PHY_ADDR;
 		cmd.transceiver = 0;
 		cmd.autoneg = tp->link_config.autoneg;
-		cmd.maxtxpkt = tp->coalesce_config.tx_max_coalesced_frames_def;
-		cmd.maxrxpkt = tp->coalesce_config.rx_max_coalesced_frames_def;
+		cmd.maxtxpkt = 0;
+		cmd.maxrxpkt = 0;
 		if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
 			return -EFAULT;
 		return 0;
@@ -4761,22 +4482,6 @@
 			tp->link_config.duplex = cmd.duplex;
 		}
 
-		if (cmd.maxtxpkt || cmd.maxrxpkt) {
-			tp->coalesce_config.tx_max_coalesced_frames_def =
-				tp->coalesce_config.tx_max_coalesced_frames =
-				cmd.maxtxpkt;
-			tp->coalesce_config.rx_max_coalesced_frames_def =
-				tp->coalesce_config.rx_max_coalesced_frames =
-				cmd.maxrxpkt;
-
-			/* Coalescing config bits can be updated without
-			 * a full chip reset.
-			 */
-			tw32(HOSTCC_TXMAX_FRAMES,
-			     tp->coalesce_config.tx_max_coalesced_frames);
-			tw32(HOSTCC_RXMAX_FRAMES,
-			     tp->coalesce_config.rx_max_coalesced_frames);
-		}
 		tg3_setup_phy(tp);
 		spin_unlock_irq(&tp->lock);
 
@@ -4873,22 +4578,6 @@
 			return -EFAULT;
 		return 0;
 	}
-	case ETHTOOL_GCOALESCE: {
-		struct ethtool_coalesce ecoal = { ETHTOOL_GCOALESCE };
-
-		tg3_to_ethtool_coal(tp, &ecoal);
-		if (copy_to_user(useraddr, &ecoal, sizeof(ecoal)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SCOALESCE: {
-		struct ethtool_coalesce ecoal;
-
-		if (copy_from_user(&ecoal, useraddr, sizeof(ecoal)))
-			return -EINVAL;
-
-		return tg3_from_ethtool_coal(tp, &ecoal);
-	}
 	case ETHTOOL_GRINGPARAM: {
 		struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
 
@@ -5641,42 +5330,13 @@
 		tp->tg3_flags |= TG3_FLAG_WOL_SPEED_100MB;
 	}
 
-	/* Only 5701 and later support tagged irq status mode. */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) {
-		tp->tg3_flags |= TG3_FLAG_TAGGED_IRQ_STATUS;
-		tp->misc_host_ctrl |= MISC_HOST_CTRL_TAGGED_STATUS;
-
-		/* ??? Due to a glitch Broadcom's driver ALWAYS sets
-		 * ??? these bits in coalesce_mode.  Because MM_GetConfig
-		 * ??? always sets pDevice->UseTaggedStatus correctly
-		 * ??? the following test at tigon3.c:LM_GetAdapterInfo()
-		 * ???
-		 * ???   pDevice->UseTaggedStatus &&
-		 * ???   (pDevice->ChipRevId == T3_CHIP_ID_5700_C0 ||
-		 * ???    T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_AX ||
-		 * ???    T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_BX)
-		 * ???
-		 * ??? will never pass and thus pDevice->CoalesceMode will never
-		 * ??? get set to zero.  For now I'll mirror what I believe is
-		 * ??? the intention of their driver.
-		 * ???
-		 * ??? Update: This is fixed in Broadcom's 2.2.3 and later
-		 * ???         drivers.  All the current 2.0.x drivers still
-		 * ???         have the bug.
-		 */
-		tp->coalesce_mode = (HOSTCC_MODE_CLRTICK_RXBD |
-				     HOSTCC_MODE_CLRTICK_TXBD);
-	} else {
-		tp->coalesce_mode = 0;
-
-		/* If not using tagged status, set the *_during_int
-		 * coalesce default config values to zero.
-		 */
-		tp->coalesce_config.rx_coalesce_ticks_during_int_def = 0;
-		tp->coalesce_config.rx_max_coalesced_frames_during_int_def = 0;
-		tp->coalesce_config.tx_coalesce_ticks_during_int_def = 0;
-		tp->coalesce_config.tx_max_coalesced_frames_during_int_def = 0;
-	}
+	/* Only 5701 and later support tagged irq status mode.
+	 *
+	 * However, since we are using NAPI avoid tagged irq status
+	 * because the interrupt condition is more difficult to
+	 * fully clear in that mode.
+	 */
+	tp->coalesce_mode = 0;
 
 	if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX &&
 	    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
@@ -6121,61 +5781,6 @@
 	tp->link_config.orig_autoneg = AUTONEG_INVALID;
 }
 
-static void __devinit tg3_init_coalesce_config(struct tg3 *tp)
-{
-	tp->coalesce_config.rx_coalesce_ticks_def = DEFAULT_RXCOL_TICKS;
-	tp->coalesce_config.rx_max_coalesced_frames_def = DEFAULT_RXMAX_FRAMES;
-	tp->coalesce_config.rx_coalesce_ticks_during_int_def =
-		DEFAULT_RXCOAL_TICK_INT;
-	tp->coalesce_config.rx_max_coalesced_frames_during_int_def =
-		DEFAULT_RXCOAL_MAXF_INT;
-	tp->coalesce_config.tx_coalesce_ticks_def = DEFAULT_TXCOL_TICKS;
-	tp->coalesce_config.tx_max_coalesced_frames_def = DEFAULT_TXMAX_FRAMES;
-	tp->coalesce_config.tx_coalesce_ticks_during_int_def =
-		DEFAULT_TXCOAL_TICK_INT;
-	tp->coalesce_config.tx_max_coalesced_frames_during_int_def =
-		DEFAULT_TXCOAL_MAXF_INT;
-	tp->coalesce_config.stats_coalesce_ticks_def =
-		DEFAULT_STAT_COAL_TICKS;
-
-	tp->coalesce_config.rx_coalesce_ticks_low =
-		LOW_RXCOL_TICKS;
-	tp->coalesce_config.rx_max_coalesced_frames_low =
-		LOW_RXMAX_FRAMES;
-	tp->coalesce_config.tx_coalesce_ticks_low =
-		LOW_TXCOL_TICKS;
-	tp->coalesce_config.tx_max_coalesced_frames_low =
-		LOW_TXMAX_FRAMES;
-
-	tp->coalesce_config.rx_coalesce_ticks_high =
-		HIGH_RXCOL_TICKS;
-	tp->coalesce_config.rx_max_coalesced_frames_high =
-		HIGH_RXMAX_FRAMES;
-	tp->coalesce_config.tx_coalesce_ticks_high =
-		HIGH_TXCOL_TICKS;
-	tp->coalesce_config.tx_max_coalesced_frames_high =
-		HIGH_TXMAX_FRAMES;
-
-	/* Active == default */
-	tp->coalesce_config.rx_coalesce_ticks =
-		tp->coalesce_config.rx_coalesce_ticks_def;
-	tp->coalesce_config.rx_max_coalesced_frames =
-		tp->coalesce_config.rx_max_coalesced_frames_def;
-	tp->coalesce_config.tx_coalesce_ticks =
-		tp->coalesce_config.tx_coalesce_ticks_def;
-	tp->coalesce_config.tx_max_coalesced_frames =
-		tp->coalesce_config.tx_max_coalesced_frames_def;
-	tp->coalesce_config.stats_coalesce_ticks =
-		tp->coalesce_config.stats_coalesce_ticks_def;
-
-	tp->coalesce_config.rate_sample_jiffies = (1 * HZ);
-	tp->coalesce_config.pkt_rate_low = 22000;
-	tp->coalesce_config.pkt_rate_high = 61000;
-
-	tp->tg3_flags |= TG3_FLAG_ADAPTIVE_RX;
-	tp->tg3_flags &= ~(TG3_FLAG_ADAPTIVE_TX);
-}
-
 static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
 {
 	tp->bufmgr_config.mbuf_read_dma_low_water =
@@ -6333,8 +5938,6 @@
 
 	tg3_init_link_config(tp);
 
-	tg3_init_coalesce_config(tp);
-
 	tg3_init_bufmgr_config(tp);
 
 	tp->rx_pending = TG3_DEF_RX_RING_PENDING;
@@ -6351,6 +5954,8 @@
 	dev->set_mac_address = tg3_set_mac_addr;
 	dev->do_ioctl = tg3_ioctl;
 	dev->tx_timeout = tg3_tx_timeout;
+	dev->poll = tg3_poll;
+	dev->weight = 64;
 	dev->watchdog_timeo = TG3_TX_TIMEOUT;
 	dev->change_mtu = tg3_change_mtu;
 	dev->irq = pdev->irq;
diff -Nru a/drivers/net/tg3.h b/drivers/net/tg3.h
--- a/drivers/net/tg3.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/net/tg3.h	Tue Jul 16 16:49:41 2002
@@ -1687,45 +1687,6 @@
 	u8				orig_autoneg;
 };
 
-struct tg3_coalesce_config {
-	/* Current settings. */
-	u32		rx_coalesce_ticks;
-	u32		rx_max_coalesced_frames;
-	u32		rx_coalesce_ticks_during_int;
-	u32		rx_max_coalesced_frames_during_int;
-	u32		tx_coalesce_ticks;
-	u32		tx_max_coalesced_frames;
-	u32		tx_coalesce_ticks_during_int;
-	u32		tx_max_coalesced_frames_during_int;
-	u32		stats_coalesce_ticks;
-
-	/* Default settings. */
-	u32		rx_coalesce_ticks_def;
-	u32		rx_max_coalesced_frames_def;
-	u32		rx_coalesce_ticks_during_int_def;
-	u32		rx_max_coalesced_frames_during_int_def;
-	u32		tx_coalesce_ticks_def;
-	u32		tx_max_coalesced_frames_def;
-	u32		tx_coalesce_ticks_during_int_def;
-	u32		tx_max_coalesced_frames_during_int_def;
-	u32		stats_coalesce_ticks_def;
-
-	/* Adaptive RX/TX coalescing parameters. */
-	u32		rate_sample_jiffies;
-	u32		pkt_rate_low;
-	u32		pkt_rate_high;
-
-	u32		rx_coalesce_ticks_low;
-	u32		rx_max_coalesced_frames_low;
-	u32		tx_coalesce_ticks_low;
-	u32		tx_max_coalesced_frames_low;
-
-	u32		rx_coalesce_ticks_high;
-	u32		rx_max_coalesced_frames_high;
-	u32		tx_coalesce_ticks_high;
-	u32		tx_max_coalesced_frames_high;
-};
-
 struct tg3_bufmgr_config {
 	u32		mbuf_read_dma_low_water;
 	u32		mbuf_mac_rx_low_water;
@@ -1772,8 +1733,7 @@
 #define TG3_FLAG_POLL_SERDES		0x00000080
 #define TG3_FLAG_PHY_RESET_ON_INIT	0x00000100
 #define TG3_FLAG_PCIX_TARGET_HWBUG	0x00000200
-#define TG3_FLAG_TAGGED_IRQ_STATUS	0x00000400
-#define TG3_FLAG_WOL_SPEED_100MB	0x00000800
+#define TG3_FLAG_WOL_SPEED_100MB	0x00000400
 #define TG3_FLAG_WOL_ENABLE		0x00001000
 #define TG3_FLAG_NVRAM			0x00002000
 #define TG3_FLAG_NVRAM_BUFFERED		0x00004000
@@ -1802,7 +1762,6 @@
 	u32				timer_offset;
 
 	struct tg3_link_config		link_config;
-	struct tg3_coalesce_config	coalesce_config;
 	struct tg3_bufmgr_config	bufmgr_config;
 
 	u32				rx_pending;
diff -Nru a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
--- a/drivers/net/wan/syncppp.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/net/wan/syncppp.c	Tue Jul 16 16:49:42 2002
@@ -796,7 +796,7 @@
 		printk (">\n");
 	}
 	sp->obytes += skb->len;
-	/* Control is high priority so it doesnt get queued behind data */
+	/* Control is high priority so it doesn't get queued behind data */
 	skb->priority=TC_PRIO_CONTROL;
 	skb->dev = dev;
 	dev_queue_xmit(skb);
diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
--- a/drivers/net/wireless/airo.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/net/wireless/airo.c	Tue Jul 16 16:49:41 2002
@@ -32,6 +32,7 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/in.h>
+#include <linux/tqueue.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -263,7 +264,7 @@
 
 /* This is a kind of sloppy hack to get this information to OUT4500 and
    IN4500.  I would be extremely interested in the situation where this
-   doesnt work though!!! */
+   doesn't work though!!! */
 static int do8bitIO = 0;
 
 /* Return codes */
@@ -3652,7 +3653,7 @@
 	struct net_device_list *next;
 } *airo_devices = 0;
 
-/* Since the card doesnt automatically switch to the right WEP mode,
+/* Since the card doesn't automatically switch to the right WEP mode,
    we will make it do it.  If the card isn't associated, every secs we
    will switch WEP modes to see if that will help.  If the card is
    associated we will check every minute to see if anything has
diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c
--- a/drivers/pci/probe.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/pci/probe.c	Tue Jul 16 16:49:41 2002
@@ -252,8 +252,6 @@
 	return child;
 }
 
-unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus);
-
 /*
  * If it's a bridge, configure it and scan the bus behind it.
  * For CardBus bridges, we don't scan behind as the devices will
diff -Nru a/drivers/sbus/char/Config.in b/drivers/sbus/char/Config.in
--- a/drivers/sbus/char/Config.in	Tue Jul 16 16:49:41 2002
+++ b/drivers/sbus/char/Config.in	Tue Jul 16 16:49:41 2002
@@ -2,7 +2,7 @@
 comment 'Misc Linux/SPARC drivers'
 tristate '/dev/openprom device support' CONFIG_SUN_OPENPROMIO
 tristate 'Mostek real time clock support' CONFIG_SUN_MOSTEK_RTC
-if [ "$ARCH" = "sparc64" ]; then
+if [ "$CONFIG_SPARC64" = "y" ]; then
    if [ "$CONFIG_PCI" = "y" ]; then
       tristate 'Siemens SAB82532 serial support' CONFIG_SAB82532
    fi
@@ -14,7 +14,7 @@
    tristate 'Videopix Frame Grabber (EXPERIMENTAL)' CONFIG_SUN_VIDEOPIX
    tristate 'Aurora Multiboard 1600se (EXPERIMENTAL)' CONFIG_SUN_AURORA
 
-   if [ "$ARCH" = "sparc" ]; then
+   if [ "$CONFIG_SPARC32" = "y" ]; then
       tristate 'Tadpole TS102 Microcontroller support (EXPERIMENTAL)' CONFIG_TADPOLE_TS102_UCTRL
 
       tristate 'JavaStation OS Flash SIMM (EXPERIMENTAL)' CONFIG_SUN_JSFLASH
diff -Nru a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
--- a/drivers/scsi/aic7xxx_old.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/scsi/aic7xxx_old.c	Tue Jul 16 16:49:42 2002
@@ -3070,7 +3070,7 @@
        * we check data_cmnd[0].  This catches the conditions for st.c, but
        * I'm still not sure if request.cmd is valid for sg devices.
        */
-      if ( (rq_data_dir(&cmd->request) == WRITE) || (cmd->data_cmnd[0] == WRITE_6) ||
+      if ( (rq_data_dir(cmd->request) == WRITE) || (cmd->data_cmnd[0] == WRITE_6) ||
            (cmd->data_cmnd[0] == WRITE_FILEMARKS) )
       {
         sp->w_total++;
@@ -4280,7 +4280,7 @@
       {
         printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
           "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
-          (rq_data_dir(&cmd->request) == WRITE) ? "wrote" : "read", actual,
+          (rq_data_dir(cmd->request) == WRITE) ? "wrote" : "read", actual,
           hscb->residual_SG_segment_count);
         printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb),
           hscb->target_status);
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/scsi/ide-scsi.c	Tue Jul 16 16:49:41 2002
@@ -236,22 +236,26 @@
 
 static int idescsi_end_request(struct ata_device *drive, struct request *rq, int uptodate)
 {
+	unsigned long flags;
 	struct Scsi_Host *host = drive->driver_data;
 	idescsi_scsi_t *scsi = idescsi_private(host);
 	struct atapi_packet_command *pc = (struct atapi_packet_command *) rq->special;
 	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
 	u8 *scsi_buf;
-	unsigned long flags;
 
 	if (!(rq->flags & REQ_PC)) {
-		ata_end_request(drive, rq, uptodate);
+		__ata_end_request(drive, rq, uptodate, 0);
 		return 0;
 	}
 
+	spin_lock_irqsave(drive->channel->lock, flags);
+
 	blkdev_dequeue_request(rq);
 	drive->rq = NULL;
 	end_that_request_last(rq);
 
+	spin_unlock_irqrestore(drive->channel->lock, flags);
+
 	if (rq->errors >= ERROR_MAX) {
 		pc->s.scsi_cmd->result = DID_ERROR << 16;
 		if (log)
@@ -273,9 +277,7 @@
 		}
 	}
 	host = pc->s.scsi_cmd->host;
-	spin_lock_irqsave(host->host_lock, flags);
 	pc->s.done(pc->s.scsi_cmd);
-	spin_unlock_irqrestore(host->host_lock, flags);
 	idescsi_free_bio(rq->bio);
 	kfree(pc); kfree(rq);
 	scsi->pc = NULL;
@@ -293,8 +295,6 @@
  */
 static ide_startstop_t idescsi_pc_intr(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	struct Scsi_Host *host = drive->driver_data;
 	idescsi_scsi_t *scsi = idescsi_private(host);
 	u8 ireason;
@@ -322,21 +322,19 @@
 		if (drive->status & ERR_STAT)
 			rq->errors++;
 		idescsi_end_request(drive, rq, 1);
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 	bcount = IN_BYTE (IDE_BCOUNTH_REG) << 8 | IN_BYTE (IDE_BCOUNTL_REG);
 	ireason = IN_BYTE (IDE_IREASON_REG);
 
 	if (ireason & IDESCSI_IREASON_COD) {
 		printk (KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
-		return ide_stopped;
+		return ATA_OP_FINISHED;
 	}
 	if (ireason & IDESCSI_IREASON_IO) {
 		temp = pc->actually_transferred + bcount;
 		if ( temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
-				unsigned long flags;
-				struct ata_channel *ch = drive->channel;
 				printk (KERN_ERR "ide-scsi: The scsi wants to send us more data than expected - discarding data\n");
 				temp = pc->buffer_size - pc->actually_transferred;
 				if (temp) {
@@ -350,15 +348,10 @@
 				pc->actually_transferred += temp;
 				pc->current_position += temp;
 				atapi_discard_data(drive,bcount - temp);
-				/* FIXME: this locking should encompass the above register
-				 * file access too.
-				 */
 
-				spin_lock_irqsave(ch->lock, flags);
 				ata_set_handler(drive, idescsi_pc_intr, get_timeout(pc), NULL);
-				spin_unlock_irqrestore(ch->lock, flags);
 
-				return ide_started;
+				return ATA_OP_CONTINUES;
 			}
 #ifdef DEBUG
 			printk (KERN_NOTICE "ide-scsi: The scsi wants to send us more data than expected - allowing transfer\n");
@@ -381,48 +374,38 @@
 	pc->actually_transferred+=bcount;				/* Update the current position */
 	pc->current_position+=bcount;
 
-	/* FIXME: this locking should encompass the above register
-	 * file access too.
-	 */
-
-	spin_lock_irqsave(ch->lock, flags);
-	ata_set_handler(drive, idescsi_pc_intr, get_timeout(pc), NULL);	/* And set the interrupt handler again */
-	spin_unlock_irqrestore(ch->lock, flags);
+	/* And set the interrupt handler again */
+	ata_set_handler(drive, idescsi_pc_intr, get_timeout(pc), NULL);
 
-	return ide_started;
+	return ATA_OP_CONTINUES;
 }
 
 static ide_startstop_t idescsi_transfer_pc(struct ata_device *drive, struct request *rq)
 {
-	unsigned long flags;
-	struct ata_channel *ch = drive->channel;
 	struct Scsi_Host *host = drive->driver_data;
 	idescsi_scsi_t *scsi = idescsi_private(host);
 	struct atapi_packet_command *pc = scsi->pc;
 	u8 ireason;
-	ide_startstop_t startstop;
 	int ret;
 
-	/* FIXME: Move this lock upwards.
-	 */
-	spin_lock_irqsave(ch->lock, flags);
-	if (ata_status_poll(drive, DRQ_STAT, BUSY_STAT,
-				WAIT_READY, rq, &startstop)) {
+	ret = ata_status_poll(drive, DRQ_STAT, BUSY_STAT,
+				WAIT_READY, rq);
+	if (ret != ATA_OP_READY) {
 		printk (KERN_ERR "ide-scsi: Strange, packet command initiated yet DRQ isn't asserted\n");
-		ret = startstop;
-	} else {
-		ireason = IN_BYTE(IDE_IREASON_REG);
 
-		if ((ireason & (IDESCSI_IREASON_IO | IDESCSI_IREASON_COD)) != IDESCSI_IREASON_COD) {
-			printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n");
-			ret = ide_stopped;
-		} else {
-			ata_set_handler(drive, idescsi_pc_intr, get_timeout(pc), NULL);
-			atapi_write(drive, scsi->pc->c, 12);
-			ret = ide_started;
-		}
+		return ret;
+	}
+
+	ireason = IN_BYTE(IDE_IREASON_REG);
+
+	if ((ireason & (IDESCSI_IREASON_IO | IDESCSI_IREASON_COD)) != IDESCSI_IREASON_COD) {
+		printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n");
+		ret = ATA_OP_FINISHED;
+	} else {
+		ata_set_handler(drive, idescsi_pc_intr, get_timeout(pc), NULL);
+		atapi_write(drive, scsi->pc->c, 12);
+		ret = ATA_OP_CONTINUES;
 	}
-	spin_unlock_irqrestore(ch->lock, flags);
 
 	return ret;
 }
@@ -457,19 +440,10 @@
 		udma_start(drive, rq);
 	}
 	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
-		unsigned long flags;
-		struct ata_channel *ch = drive->channel;
-
-		/* FIXME: this locking should encompass the above register
-		 * file access too.
-		 */
-
-		spin_lock_irqsave(ch->lock, flags);
 		ata_set_handler(drive, idescsi_transfer_pc, get_timeout(pc), NULL);
-		spin_unlock_irqrestore(ch->lock, flags);
 
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
-		return ide_started;
+		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
+		return ATA_OP_CONTINUES;
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
 		return idescsi_transfer_pc(drive, rq);
@@ -481,7 +455,6 @@
  */
 static ide_startstop_t idescsi_do_request(struct ata_device *drive, struct request *rq, sector_t block)
 {
-	struct ata_channel *ch = drive->channel;
 	int ret;
 
 #ifdef DEBUG
@@ -496,16 +469,13 @@
 			rq->current_nr_sectors);
 #endif
 
-	/* FIXME: make this unlocking go away*/
-	spin_unlock_irq(ch->lock);
 	if (rq->flags & REQ_PC) {
 		ret = idescsi_issue_pc(drive, rq, (struct atapi_packet_command *) rq->special);
 	} else {
 	    blk_dump_rq_flags(rq, "ide-scsi: unsup command");
 	    idescsi_end_request(drive, rq, 0);
-	    ret = ide_stopped;
+	    ret = ATA_OP_FINISHED;
 	}
-	spin_lock_irq(ch->lock);
 
 	return ret;
 }
@@ -720,9 +690,7 @@
 	rq->flags = REQ_PC;
 	rq->special = (char *) pc;
 	rq->bio = idescsi_dma_bio (drive, pc);
-	spin_unlock_irq(cmd->host->host_lock);
-	ide_do_drive_cmd (drive, rq, ide_end);
-	spin_lock_irq(cmd->host->host_lock);
+	ide_do_drive_cmd(drive, rq, ide_end);
 
 	return 0;
 abort:
diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c
--- a/drivers/scsi/ips.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/scsi/ips.c	Tue Jul 16 16:49:41 2002
@@ -596,6 +596,7 @@
    }
 
    return (1);
+}
 
 __setup("ips=", ips_setup);
 
@@ -632,10 +633,9 @@
          }
       }
    }
+}
 
 #endif
-
-}
 
 /****************************************************************************/
 /*                                                                          */
diff -Nru a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
--- a/drivers/scsi/ncr53c8xx.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/scsi/ncr53c8xx.c	Tue Jul 16 16:49:42 2002
@@ -7184,7 +7184,7 @@
 **
 **	Possible cases:		   hs  sir   msg_in value  send   goto
 **	We try to negotiate:
-**	-> target doesnt't msgin   NEG FAIL  noop   defa.  -      dispatch
+**	-> target doesn't msgin    NEG FAIL  noop   defa.  -      dispatch
 **	-> target rejected our msg NEG FAIL  reject defa.  -      dispatch
 **	-> target answered  (ok)   NEG SYNC  sdtr   set    -      clrack
 **	-> target answered (!ok)   NEG SYNC  sdtr   defa.  REJ--->msg_bad
diff -Nru a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
--- a/drivers/scsi/pluto.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/scsi/pluto.c	Tue Jul 16 16:49:42 2002
@@ -65,7 +65,7 @@
 
 static void __init pluto_detect_scsi_done(Scsi_Cmnd *SCpnt)
 {
-	SCpnt->request.rq_status = RQ_SCSI_DONE;
+	SCpnt->request->rq_status = RQ_SCSI_DONE;
 	PLND(("Detect done %08lx\n", (long)SCpnt))
 	if (atomic_dec_and_test (&fcss))
 		up(&fc_sem);
@@ -160,7 +160,7 @@
 		
 		SCpnt->cmd_len = COMMAND_SIZE(INQUIRY);
 	
-		SCpnt->request.rq_status = RQ_SCSI_BUSY;
+		SCpnt->request->rq_status = RQ_SCSI_BUSY;
 		
 		SCpnt->done = pluto_detect_done;
 		SCpnt->bufflen = 256;
@@ -174,7 +174,7 @@
 	for (retry = 0; retry < 5; retry++) {
 		for (i = 0; i < fcscount; i++) {
 			if (!fcs[i].fc) break;
-			if (fcs[i].cmd.request.rq_status != RQ_SCSI_DONE) {
+			if (fcs[i].cmd.request->rq_status != RQ_SCSI_DONE) {
 				disable_irq(fcs[i].fc->irq);
 				PLND(("queuecommand %d %d\n", retry, i))
 				fcp_scsi_queuecommand (&(fcs[i].cmd), 
diff -Nru a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
--- a/drivers/scsi/seagate.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/scsi/seagate.c	Tue Jul 16 16:49:42 2002
@@ -21,7 +21,7 @@
  * linux 2.1.112, simplified some #defines etc. <pavel@ucw.cz>
  *
  * Aug 2000 - aeb - deleted seagate_st0x_biosparam(). It would try to
- * read the physical disk geometry, a bad mistake. Of course it doesnt
+ * read the physical disk geometry, a bad mistake. Of course it doesn't
  * matter much what geometry one invents, but on large disks it
  * returned 256 (or more) heads, causing all kind of failures.
  * Of course this means that people might see a different geometry now,
diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/scsi/sg.c	Tue Jul 16 16:49:42 2002
@@ -19,7 +19,7 @@
  */
 #include <linux/config.h>
 #ifdef CONFIG_PROC_FS
- static char * sg_version_str = "Version: 3.5.25 (20020504)";
+ static char * sg_version_str = "Version: 3.5.26 (20020708)";
 #endif
  static int sg_version_num = 30525; /* 2 digits for each component */
 /*
@@ -77,12 +77,12 @@
 #endif /* LINUX_VERSION_CODE */
 
 #define SG_ALLOW_DIO_DEF 0
-#define SG_ALLOW_DIO_CODE	/* compile out be commenting this define */
+/* #define SG_ALLOW_DIO_CODE */	/* compile out be commenting this define */
 #ifdef SG_ALLOW_DIO_CODE
 #include <linux/iobuf.h>
+#define SG_NEW_KIOVEC 0	/* use alloc_kiovec(), not alloc_kiovec_sz() */
 #endif
 
-#define SG_NEW_KIOVEC 0	/* use alloc_kiovec(), not alloc_kiovec_sz() */
 
 #define SG_MAX_DEVS_MASK ((1U << KDEV_MINOR_BITS) - 1)
 
@@ -138,8 +138,10 @@
     unsigned bufflen;           /* Size of (aggregate) data buffer */
     unsigned b_malloc_len;      /* actual len malloc'ed in buffer */
     void * buffer;              /* Data buffer or scatter list + mem_src_arr */
+#ifdef SG_ALLOW_DIO_CODE
     struct kiobuf * kiobp;      /* for direct IO information */
     char mapped;                /* indicates kiobp has locked pages */
+#endif
     char buffer_mem_src;        /* heap whereabouts of 'buffer' */
     unsigned char cmd_opcode;   /* first byte of command */
 } Sg_scatter_hold;    /* 24 bytes long on i386 */
@@ -215,7 +217,7 @@
 		      int wr_xf, int * countp, unsigned char ** up);
 static int sg_write_xfer(Sg_request * srp);
 static int sg_read_xfer(Sg_request * srp);
-static void sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer);
+static int sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer);
 static void sg_remove_scat(Sg_scatter_hold * schp);
 static char * sg_get_sgat_msa(Sg_scatter_hold * schp);
 static void sg_build_reserve(Sg_fd * sfp, int req_size);
@@ -240,12 +242,14 @@
 static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
 static void sg_unmap_and(Sg_scatter_hold * schp, int free_also);
 static Sg_device * sg_get_dev(int dev);
-static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp);
-static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp);
 static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp);
 #ifdef CONFIG_PROC_FS
 static int sg_last_dev(void);
 #endif
+#ifdef SG_ALLOW_DIO_CODE
+static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp);
+static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp);
+#endif
 
 static Sg_device ** sg_dev_arr = NULL;
 
@@ -377,10 +381,12 @@
     if ((k = verify_area(VERIFY_WRITE, buf, count)))
         return k;
     if (sfp->force_packid && (count >= SZ_SG_HEADER)) {
-	__copy_from_user(&old_hdr, buf, SZ_SG_HEADER);
+	if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
+	    return -EFAULT;
 	if (old_hdr.reply_len < 0) {
 	    if (count >= SZ_SG_IO_HDR) {
-		__copy_from_user(&new_hdr, buf, SZ_SG_IO_HDR);
+		if (__copy_from_user(&new_hdr, buf, SZ_SG_IO_HDR))
+		    return -EFAULT;
 		req_pack_id = new_hdr.pack_id;
 	    }
 	}
@@ -452,12 +458,15 @@
 
     /* Now copy the result back to the user buffer.  */
     if (count >= SZ_SG_HEADER) {
-	__copy_to_user(buf, &old_hdr, SZ_SG_HEADER);
-        buf += SZ_SG_HEADER;
+	if (__copy_to_user(buf, &old_hdr, SZ_SG_HEADER))
+	    return -EFAULT;
+	buf += SZ_SG_HEADER;
 	if (count > old_hdr.reply_len)
 	    count = old_hdr.reply_len;
-	if (count > SZ_SG_HEADER)
-	    sg_read_oxfer(srp, buf, count - SZ_SG_HEADER);
+	if (count > SZ_SG_HEADER) {
+	    if ((res = sg_read_oxfer(srp, buf, count - SZ_SG_HEADER)))
+		return -EFAULT;
+	}
     }
     else
 	count = (old_hdr.result == 0) ? 0 : -EIO;
@@ -486,13 +495,19 @@
 	    len = (len > sb_len) ? sb_len : len;
 	    if ((err = verify_area(VERIFY_WRITE, hp->sbp, len)))
 		goto err_out;
-	    __copy_to_user(hp->sbp, srp->sense_b, len);
+	    if (__copy_to_user(hp->sbp, srp->sense_b, len)) {
+		err = -EFAULT;
+		goto err_out;
+	    }
 	    hp->sb_len_wr = len;
 	}
     }
     if (hp->masked_status || hp->host_status || hp->driver_status)
 	hp->info |= SG_INFO_CHECK;
-    copy_to_user(buf, hp, SZ_SG_IO_HDR);
+    if (copy_to_user(buf, hp, SZ_SG_IO_HDR)) {
+	err = -EFAULT;
+	goto err_out;
+    }
     err = sg_read_xfer(srp);
 err_out:
     sg_finish_rem_req(srp);
@@ -529,7 +544,8 @@
         return k;  /* protects following copy_from_user()s + get_user()s */
     if (count < SZ_SG_HEADER)
 	return -EIO;
-    __copy_from_user(&old_hdr, buf, SZ_SG_HEADER);
+    if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
+	return -EFAULT;
     blocking = !(filp->f_flags & O_NONBLOCK);
     if (old_hdr.reply_len < 0)
 	return sg_new_write(sfp, buf, count, blocking, 0, NULL);
@@ -587,7 +603,8 @@
     hp->flags = input_size;             /* structure abuse ... */
     hp->pack_id = old_hdr.pack_id;
     hp->usr_ptr = NULL;
-    __copy_from_user(cmnd, buf, cmd_size);
+    if (__copy_from_user(cmnd, buf, cmd_size))
+	return -EFAULT;
     k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
     return (k < 0) ? k : count;
 }
@@ -612,7 +629,10 @@
 	return -EDOM;
     }
     hp = &srp->header;
-    __copy_from_user(hp, buf, SZ_SG_IO_HDR);
+    if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) {
+	sg_remove_request(sfp, srp);
+	return -EFAULT;
+    }
     if (hp->interface_id != 'S') {
 	sg_remove_request(sfp, srp);
 	return -ENOSYS;
@@ -640,7 +660,10 @@
 	sg_remove_request(sfp, srp);
 	return k;  /* protects following copy_from_user()s + get_user()s */
     }
-    __copy_from_user(cmnd, hp->cmdp, hp->cmd_len);
+    if (__copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) {
+	sg_remove_request(sfp, srp);
+	return -EFAULT;
+    }
     if (read_only &&
 	(! sg_allow_access(cmnd[0], sfp->parentdp->device->type))) {
 	sg_remove_request(sfp, srp);
@@ -923,8 +946,8 @@
 		}
 	    }
 	    read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-	    __copy_to_user((void *)arg, rinfo, SZ_SG_REQ_INFO * SG_MAX_QUEUE);
-	    return 0;
+	    return (__copy_to_user((void *)arg, rinfo, 
+			SZ_SG_REQ_INFO * SG_MAX_QUEUE) ? -EFAULT : 0);
 	}
     case SG_EMULATED_HOST:
 	if (sdp->detached)
@@ -972,7 +995,8 @@
 	    unsigned char opcode = WRITE_6;
 	    Scsi_Ioctl_Command * siocp = (void *)arg;
 
-	    copy_from_user(&opcode, siocp->data, 1);
+	    if (copy_from_user(&opcode, siocp->data, 1))
+		return -EFAULT;
 	    if (! sg_allow_access(opcode, sdp->device->type))
 		return -EPERM;
 	}
@@ -1897,7 +1921,8 @@
 		res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
 		if (res) return res;
 		usglen = (num_xfer > usglen) ? usglen : num_xfer;
-		__copy_from_user(p, up, usglen);
+		if (__copy_from_user(p, up, usglen))
+		    return -EFAULT;
 		p += usglen;
 		num_xfer -= usglen;
 		if (num_xfer <= 0)
@@ -1925,20 +1950,32 @@
 		    break;
 		if (ksglen > usglen) {
 		    if (usglen >= num_xfer) {
-			if (ok) __copy_from_user(p, up, num_xfer);
+			if (ok) {
+			   if (__copy_from_user(p, up, num_xfer))
+				return -EFAULT;
+			}
 			return 0;
 		    }
-		    if (ok) __copy_from_user(p, up, usglen);
+		    if (ok) {
+			if (__copy_from_user(p, up, usglen))
+			    return -EFAULT;
+		    }
 		    p += usglen;
 		    ksglen -= usglen;
                     break;
 		}
 		else {
 		    if (ksglen >= num_xfer) {
-			if (ok) __copy_from_user(p, up, num_xfer);
+			if (ok) {
+			    if (__copy_from_user(p, up, num_xfer))
+				return -EFAULT;
+			}
 			return 0;
 		    }
-		    if (ok) __copy_from_user(p, up, ksglen);
+		    if (ok) {
+			if (__copy_from_user(p, up, ksglen))
+			    return -EFAULT;
+		    }
 		    up += ksglen;
 		    usglen -= ksglen;
 		}
@@ -1964,9 +2001,10 @@
 	    count = num_xfer;
     }
     else {
-	__copy_from_user(&u_iovec,
+	if (__copy_from_user(&u_iovec,
 			 (unsigned char *)hp->dxferp + (ind * SZ_SG_IOVEC),
-			 SZ_SG_IOVEC);
+			 SZ_SG_IOVEC))
+	    return -EFAULT;
 	p = (unsigned char *)u_iovec.iov_base;
 	count = (int)u_iovec.iov_len;
     }
@@ -2050,7 +2088,8 @@
 		res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
 		if (res) return res;
 		usglen = (num_xfer > usglen) ? usglen : num_xfer;
-		__copy_to_user(up, p, usglen);
+		if (__copy_to_user(up, p, usglen))
+		    return -EFAULT;
 		p += usglen;
 		num_xfer -= usglen;
 		if (num_xfer <= 0)
@@ -2078,20 +2117,32 @@
 		    break;
 		if (ksglen > usglen) {
 		    if (usglen >= num_xfer) {
-			if (ok) __copy_to_user(up, p, num_xfer);
+			if (ok) {
+			    if (__copy_to_user(up, p, num_xfer))
+				return -EFAULT;
+			}
 			return 0;
 		    }
-		    if (ok) __copy_to_user(up, p, usglen);
+		    if (ok) {
+			if (__copy_to_user(up, p, usglen))
+			    return -EFAULT;
+		    }
 		    p += usglen;
 		    ksglen -= usglen;
 		    break;
 		}
 		else {
 		    if (ksglen >= num_xfer) {
-			if (ok) __copy_to_user(up, p, num_xfer);
+			if (ok) {
+			    if (__copy_to_user(up, p, num_xfer))
+				return -EFAULT;
+			}
 			return 0;
 		    }
-		    if (ok) __copy_to_user(up, p, ksglen);
+		    if (ok) {
+			if (__copy_to_user(up, p, ksglen))
+			    return -EFAULT;
+		    }
 		    up += ksglen;
 		    usglen -= ksglen;
 		}
@@ -2101,14 +2152,14 @@
     return 0;
 }
 
-static void sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer)
+static int sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer)
 {
     Sg_scatter_hold * schp = &srp->data;
 
     SCSI_LOG_TIMEOUT(4, printk("sg_read_oxfer: num_read_xfer=%d\n",
 			       num_read_xfer));
     if ((! outp) || (num_read_xfer <= 0))
-        return;
+        return 0;
     if(schp->k_use_sg > 0) {
         int k, num;
         struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
@@ -2116,11 +2167,13 @@
 	for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
             num = (int)sclp->length;
             if (num > num_read_xfer) {
-                __copy_to_user(outp, sg_scatg2virt(sclp), num_read_xfer);
+                if (__copy_to_user(outp, sg_scatg2virt(sclp), num_read_xfer))
+		    return -EFAULT;
                 break;
             }
             else {
-                __copy_to_user(outp, sg_scatg2virt(sclp), num);
+                if (__copy_to_user(outp, sg_scatg2virt(sclp), num))
+		    return -EFAULT;
                 num_read_xfer -= num;
                 if (num_read_xfer <= 0)
                     break;
@@ -2128,8 +2181,11 @@
             }
         }
     }
-    else
-        __copy_to_user(outp, schp->buffer, num_read_xfer);
+    else {
+        if (__copy_to_user(outp, schp->buffer, num_read_xfer))
+	    return -EFAULT;
+    }
+    return 0;
 }
 
 static void sg_build_reserve(Sg_fd * sfp, int req_size)
@@ -2294,7 +2350,9 @@
         resp->nextrp = NULL;
 	resp->header.duration = jiffies;
         resp->my_cmdp = NULL;
+#ifdef SG_ALLOW_DIO_CODE
 	resp->data.kiobp = NULL;
+#endif
     }
     write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
     return resp;
@@ -2560,6 +2618,7 @@
     return resp;
 }
 
+#ifdef SG_ALLOW_DIO_CODE
 static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp)
 {
 #if SG_NEW_KIOVEC
@@ -2568,6 +2627,7 @@
     return alloc_kiovec(nr, bufp);
 #endif
 }
+#endif
 
 static void sg_low_free(char * buff, int size, int mem_src)
 {
@@ -2604,6 +2664,7 @@
         sg_low_free(buff, size, mem_src);
 }
 
+#ifdef SG_ALLOW_DIO_CODE
 static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp)
 {
 #if SG_NEW_KIOVEC
@@ -2612,6 +2673,7 @@
     free_kiovec(nr, bufp);
 #endif
 }
+#endif
 
 static int sg_ms_to_jif(unsigned int msecs)
 {
@@ -2820,7 +2882,8 @@
     if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
 	return -EACCES;
     num = (count < 10) ? count : 10;
-    copy_from_user(buff, buffer, num);
+    if (copy_from_user(buff, buffer, num))
+	return -EFAULT;
     buff[num] = '\0';
     sg_allow_dio = simple_strtoul(buff, 0, 10) ? 1 : 0;
     return count;
@@ -2847,10 +2910,11 @@
     if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
 	return -EACCES;
     num = (count < 10) ? count : 10;
-    copy_from_user(buff, buffer, num);
+    if (copy_from_user(buff, buffer, num))
+	return -EFAULT;
     buff[num] = '\0';
     k = simple_strtoul(buff, 0, 10);
-    if (k <= 1048576) {
+    if (k <= 1048576) {		/* limit "big buff" to 1 MB */
 	sg_big_buff = k;
 	return count;
     }
diff -Nru a/drivers/sgi/Config.in b/drivers/sgi/Config.in
--- a/drivers/sgi/Config.in	Tue Jul 16 16:49:41 2002
+++ b/drivers/sgi/Config.in	Tue Jul 16 16:49:41 2002
@@ -11,7 +11,7 @@
 bool 'SGI DS1286  RTC support' CONFIG_SGI_DS1286
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then  
-   tristate 'SGI Newport Graphics support' CONFIG_SGI_NEWPORT_GFX
+   tristate 'SGI Newport Graphics support (EXPERIMENTAL)' CONFIG_SGI_NEWPORT_GFX
 fi
 
 endmenu
diff -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c
--- a/drivers/usb/class/bluetty.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/usb/class/bluetty.c	Tue Jul 16 16:49:41 2002
@@ -537,7 +537,6 @@
 				/* build up our urb */
 				FILL_BULK_URB (urb, bluetooth->dev, usb_sndbulkpipe(bluetooth->dev, bluetooth->bulk_out_endpointAddress),
 						urb->transfer_buffer, buffer_size, bluetooth_write_bulk_callback, bluetooth);
-				urb->transfer_flags |= USB_QUEUE_BULK;
 
 				/* send it down the pipe */
 				retval = usb_submit_urb(urb, GFP_KERNEL);
diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
--- a/drivers/usb/class/cdc-acm.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/usb/class/cdc-acm.c	Tue Jul 16 16:49:41 2002
@@ -619,7 +619,7 @@
 			buf += readsize, acm->writesize, acm_write_bulk, acm);
 		acm->writeurb->transfer_flags |= USB_NO_FSBR;
 
-		printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
+		info("ttyACM%d: USB ACM device", minor);
 
 		acm_set_control(acm, acm->ctrlout);
 
diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/core/devio.c	Tue Jul 16 16:49:42 2002
@@ -780,7 +780,7 @@
 
 	if (copy_from_user(&uurb, arg, sizeof(uurb)))
 		return -EFAULT;
-	if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD|USBDEVFS_URB_QUEUE_BULK|
+	if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
 			   USB_NO_FSBR|USB_ZERO_PACKET))
 		return -EINVAL;
 	if (!uurb.buffer)
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/core/hcd.c	Tue Jul 16 16:49:42 2002
@@ -1232,7 +1232,7 @@
 	return 0;
 }
 
-/**
+/*
  * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue)
  *
  * When registering a USB bus through the HCD framework code, use this
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/core/hub.c	Tue Jul 16 16:49:42 2002
@@ -490,8 +490,11 @@
 	list_add(&hub->hub_list, &hub_list);
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 
-	if (usb_hub_configure(hub, endpoint) >= 0)
+	if (usb_hub_configure(hub, endpoint) >= 0) {
+		strcpy (dev->actconfig->interface[i].dev.name,
+			"Hub/Port Status Changes");
 		return hub;
+	}
 
 	err("hub configuration failed for device at %s", dev->devpath);
 
@@ -637,7 +640,8 @@
 	if (portsts) {
 		ret = usb_get_port_status(hub, port + 1, portsts);
 		if (ret < 0)
-			err("%s(%s) failed (err = %d)", __FUNCTION__, hub->devpath, ret);
+			err("%s(%s-%s) failed (err = %d)", __FUNCTION__,
+				hub->bus->bus_name, hub->devpath, ret);
 		else {
 			*status = le16_to_cpu(portsts->wPortStatus);
 			*change = le16_to_cpu(portsts->wPortChange); 
@@ -884,19 +888,11 @@
 		info("new USB device %s-%s, assigned address %d",
 			dev->bus->bus_name, dev->devpath, dev->devnum);
 
-		/* put the device in the global device tree */
+		/* put the device in the global device tree. the hub port
+		 * is the "bus_id"; hubs show in hierarchy like bridges
+		 */
 		dev->dev.parent = &dev->parent->dev;
-		sprintf (&dev->dev.name[0], "USB device %04x:%04x",
-			 dev->descriptor.idVendor,
-			 dev->descriptor.idProduct);
-		/* find the number of the port this device is connected to */
-		sprintf (&dev->dev.bus_id[0], "unknown_port_%03d", dev->devnum);
-		for (i = 0; i < USB_MAXCHILDREN; ++i) {
-			if (dev->parent->children[i] == dev) {
-				sprintf (&dev->dev.bus_id[0], "%02d", i);
-				break;
-			}
-		}
+		sprintf (&dev->dev.bus_id[0], "%d", port + 1);
 
 		/* Run it through the hoops (find a driver, etc) */
 		if (!usb_new_device(dev))
diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
--- a/drivers/usb/core/inode.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/usb/core/inode.c	Tue Jul 16 16:49:41 2002
@@ -162,6 +162,9 @@
 		case S_IFDIR:
 			inode->i_op = &usbfs_dir_inode_operations;
 			inode->i_fop = &simple_dir_operations;
+
+			/* directory inodes start off with i_nlink == 2 (for "." entry) */
+			inode->i_nlink++;
 			break;
 		}
 	}
@@ -317,13 +320,13 @@
 	inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0);
 
 	if (!inode) {
-		dbg("%s: could not get inode!\n",__FUNCTION__);
+		dbg("%s: could not get inode!",__FUNCTION__);
 		return -ENOMEM;
 	}
 
 	root = d_alloc_root(inode);
 	if (!root) {
-		dbg("%s: could not get root dentry!\n",__FUNCTION__);
+		dbg("%s: could not get root dentry!",__FUNCTION__);
 		iput(inode);
 		return -ENOMEM;
 	}
@@ -364,7 +367,7 @@
 	}
 
 	if (!parent) {
-		dbg("Ah! can not find a parent!\n");
+		dbg("Ah! can not find a parent!");
 		return -EFAULT;
 	}
 
@@ -390,7 +393,7 @@
 				error = vfs_mkdir(parent->d_inode,d,mode);
 				break;
 			default:
-				err("cannot create special files\n");
+				err("cannot create special files");
 		}
 		*dentry = d;
 	}
@@ -408,7 +411,7 @@
 	struct dentry *dentry;
 	int error;
 
-	dbg("creating file '%s'\n",name);
+	dbg("creating file '%s'",name);
 
 	error = fs_create_by_name(name,mode,parent,&dentry);
 	if (error) {
@@ -510,7 +513,7 @@
 	mntput(mnt);
 
 go_ahead:
-	dbg("mount_count = %d\n", mount_count);
+	dbg("mount_count = %d", mount_count);
 	return 0;
 }
 
@@ -526,7 +529,7 @@
 
 	spin_unlock (&mount_lock);
 	mntput(mnt);
-	dbg("mount_count = %d\n", mount_count);
+	dbg("mount_count = %d", mount_count);
 }
 
 static int create_special_files (void)
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/core/message.c	Tue Jul 16 16:49:42 2002
@@ -62,7 +62,7 @@
 			    urb->pipe, urb->status, timeout);
 			status = urb->status;
 		} else {
-			printk("usb_control/bulk_msg: timeout\n");
+			warn("usb_control/bulk_msg: timeout");
 			usb_unlink_urb(urb);  // remove urb safely
 			status = -ETIMEDOUT;
 		}
diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
--- a/drivers/usb/core/urb.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/usb/core/urb.c	Tue Jul 16 16:49:43 2002
@@ -105,7 +105,7 @@
  * any transfer flags.
  *
  * Successful submissions return 0; otherwise this routine returns a
- * negative error number.  If the submission is successful, the complete
+ * negative error number.  If the submission is successful, the complete()
  * fuction of the urb will be called when the USB host driver is
  * finished with the urb (either a successful transmission, or some
  * error case.)
@@ -117,8 +117,8 @@
  * driver which issued the request.  The completion handler may then
  * immediately free or reuse that URB.
  *
- * Bulk URBs will be queued if the USB_QUEUE_BULK transfer flag is set
- * in the URB.  This can be used to maximize bandwidth utilization by
+ * Bulk URBs may be queued by submitting an URB to an endpoint before
+ * previous ones complete.  This can maximize bandwidth utilization by
  * letting the USB controller start work on the next URB without any
  * delay to report completion (scheduling and processing an interrupt)
  * and then submit that next request.
@@ -128,16 +128,19 @@
  *
  * Reserved Bandwidth Transfers:
  *
- * Periodic URBs (interrupt or isochronous) are completed repeatedly,
+ * Periodic URBs (interrupt or isochronous) are performed repeatedly.
+ *
+ * For interrupt requests this is (currently) automagically done
  * until the original request is aborted.  When the completion callback
  * indicates the URB has been unlinked (with a special status code),
  * control of that URB returns to the device driver.  Otherwise, the
  * completion handler does not control the URB, and should not change
  * any of its fields.
  *
- * Note that isochronous URBs should be submitted in a "ring" data
- * structure (using urb->next) to ensure that they are resubmitted
- * appropriately.
+ * For isochronous requests, the completion handler is expected to
+ * submit an urb, typically resubmitting its parameter, until drivers
+ * stop wanting data transfers.  (For example, audio playback might have
+ * finished, or a webcam turned off.)
  *
  * If the USB subsystem can't reserve sufficient bandwidth to perform
  * the periodic request, and bandwidth reservation is being done for
@@ -274,17 +277,18 @@
 
 	/* enforce simple/standard policy */
 	allowed = USB_ASYNC_UNLINK;	// affects later unlinks
-	allowed |= USB_NO_FSBR;		// only affects UHCI
 	switch (temp) {
-	case PIPE_CONTROL:
-		allowed |= USB_DISABLE_SPD;
-		break;
 	case PIPE_BULK:
-		allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK
-				| USB_ZERO_PACKET | URB_NO_INTERRUPT;
-		break;
-	case PIPE_INTERRUPT:
-		allowed |= USB_DISABLE_SPD;
+		allowed |= URB_NO_INTERRUPT;
+		if (is_out)
+			allowed |= USB_ZERO_PACKET;
+		/* FALLTHROUGH */
+	case PIPE_CONTROL:
+		allowed |= USB_NO_FSBR;	/* only affects UHCI */
+		/* FALLTHROUGH */
+	default:			/* all non-iso endpoints */
+		if (!is_out)
+			allowed |= URB_SHORT_NOT_OK;
 		break;
 	case PIPE_ISOCHRONOUS:
 		allowed |= USB_ISO_ASAP;
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/core/usb.c	Tue Jul 16 16:49:42 2002
@@ -748,6 +748,110 @@
 
 #endif	/* CONFIG_HOTPLUG */
 
+/* driverfs files */
+
+/* devices have one current configuration, with one
+ * or more interfaces that are used concurrently 
+ */
+static ssize_t
+show_config (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct usb_device	*udev;
+
+	if (off)
+		return 0;
+	udev = list_entry (dev, struct usb_device, dev);
+	return sprintf (buf, "%u\n", udev->actconfig->bConfigurationValue);
+}
+static struct driver_file_entry usb_config_entry = {
+	name:	"configuration",
+	mode:	S_IRUGO,
+	show:	show_config,
+};
+
+/* interfaces have one current setting; alternates
+ * can have different endpoints and class info.
+ */
+static ssize_t
+show_altsetting (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct usb_interface	*interface;
+
+	if (off)
+		return 0;
+	interface = list_entry (dev, struct usb_interface, dev);
+	return sprintf (buf, "%u\n", interface->altsetting->bAlternateSetting);
+}
+static struct driver_file_entry usb_altsetting_entry = {
+	name:	"altsetting",
+	mode:	S_IRUGO,
+	show:	show_altsetting,
+};
+
+/* product driverfs file */
+static ssize_t show_product (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct usb_device *udev;
+	int len;
+
+	if (off)
+		return 0;
+	udev = list_entry (dev, struct usb_device, dev);
+
+	len = usb_string(udev, udev->descriptor.iProduct, buf, PAGE_SIZE); 
+	buf[len] = '\n';
+	buf[len+1] = 0x00;
+	return len+1;
+}
+static struct driver_file_entry usb_product_entry = {
+	name:	"product",
+	mode:	S_IRUGO,
+	show:	show_product,
+};
+
+/* manufacturer driverfs file */
+static ssize_t
+show_manufacturer (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct usb_device *udev;
+	int len;
+
+	if (off)
+		return 0;
+	udev = list_entry (dev, struct usb_device, dev);
+
+	len = usb_string(udev, udev->descriptor.iManufacturer, buf, PAGE_SIZE); 
+	buf[len] = '\n';
+	buf[len+1] = 0x00;
+	return len+1;
+}
+static struct driver_file_entry usb_manufacturer_entry = {
+	name:	"manufacturer",
+	mode:	S_IRUGO,
+	show:	show_manufacturer,
+};
+
+/* serial number driverfs file */
+static ssize_t
+show_serial (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct usb_device *udev;
+	int len;
+
+	if (off)
+		return 0;
+	udev = list_entry (dev, struct usb_device, dev);
+
+	len = usb_string(udev, udev->descriptor.iSerialNumber, buf, PAGE_SIZE); 
+	buf[len] = '\n';
+	buf[len+1] = 0x00;
+	return len+1;
+}
+static struct driver_file_entry usb_serial_entry = {
+	name:	"serial",
+	mode:	S_IRUGO,
+	show:	show_serial,
+};
 
 /*
  * This entrypoint gets called for each new device.
@@ -760,15 +864,35 @@
 	unsigned rejected = 0;
 	unsigned claimed = 0;
 
+	/* FIXME should get called for each new configuration not just the
+	 * first one for a device. switching configs (or altesettings) should
+	 * undo driverfs and HCD state for the previous interfaces.
+	 */
 	for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) {
 		struct usb_interface *interface = &dev->actconfig->interface[ifnum];
+		struct usb_interface_descriptor *desc = interface->altsetting;
 		
 		/* register this interface with driverfs */
 		interface->dev.parent = &dev->dev;
 		interface->dev.bus = &usb_bus_type;
-		sprintf (&interface->dev.bus_id[0], "%03d%03d", dev->devnum,ifnum);
-		sprintf (&interface->dev.name[0], "figure out some name...");
+		sprintf (&interface->dev.bus_id[0], "if%d",
+			interface->altsetting->bInterfaceNumber);
+		if (!desc->iInterface
+				|| usb_string (dev, desc->iInterface,
+					interface->dev.name,
+					sizeof interface->dev.name) <= 0) {
+			/* typically devices won't bother with interface
+			 * descriptions; this is the normal case.  an
+			 * interface's driver might describe it better.
+			 * (also: iInterface is per-altsetting ...)
+			 */
+			sprintf (&interface->dev.name[0],
+				"usb-%s-%s interface %d",
+				dev->bus->bus_name, dev->devpath,
+				interface->altsetting->bInterfaceNumber);
+		}
 		device_register (&interface->dev);
+		device_create_file (&interface->dev, &usb_altsetting_entry);
 
 		/* if this interface hasn't already been claimed */
 		if (!usb_interface_claimed(interface)) {
@@ -1081,10 +1205,6 @@
 	}
 }
 
-/*
- * These are the actual routines to send
- * and receive control messages.
- */
 
 // hub-only!! ... and only exported for reset/reinit path.
 // otherwise used internally, for usb_new_device()
@@ -1096,6 +1216,64 @@
 }
 
 
+/* improve on the default device description, if we can ... and
+ * while we're at it, maybe show the vendor and product strings.
+ */
+static void set_device_description (struct usb_device *dev)
+{
+	char	*buf, *here, *end;
+	int	mfgr = dev->descriptor.iManufacturer;
+	int	prod = dev->descriptor.iProduct;
+
+	/* set default; keep it if there are no strings */
+	sprintf (dev->dev.name, "USB device %04x:%04x",
+		 dev->descriptor.idVendor,
+		 dev->descriptor.idProduct);
+	if (!mfgr && !prod)
+		return;
+
+	if (!(buf = kmalloc(256, GFP_KERNEL)))
+		return;
+	here = dev->dev.name;
+	end = here + sizeof dev->dev.name - 2;
+	*end = 0;
+
+	/* much like pci ... describe as either:
+	 * - both strings:   'product descr (vendor descr)'
+	 * - product only:   'product descr (USB device vvvv:pppp)'
+	 * - vendor only:    'USB device vvvv:pppp (vendor descr)'
+	 * - neither string: 'USB device vvvv:pppp'
+	 */
+	if (prod && usb_string (dev, prod, buf, 256) > 0) {
+		strncpy (here, buf, end - here);
+#ifdef DEBUG
+		printk (KERN_INFO "Product: %s\n", buf);
+#endif
+	} else {
+		buf [0] = 0;
+		prod = -1;
+	}
+	here = strchr (here, 0);
+	if (mfgr && usb_string (dev, mfgr, buf, 256) > 0) {
+		*here++ = ' ';
+		*here++ = '(';
+		strncpy (here, buf, end - here - 1);
+		here = strchr (here, 0);
+		*here++ = ')';
+#ifdef DEBUG
+		printk (KERN_INFO "Manufacturer: %s\n", buf);
+#endif
+	} else {
+		if (prod != -1)
+			snprintf (here, end - here - 1,
+				" (USB device %04x:%04x)",
+				dev->descriptor.idVendor,
+				dev->descriptor.idProduct);
+		/* both strings unavailable, keep the default */
+	}
+	kfree(buf);
+}
+
 /*
  * By the time we get here, the device has gotten a new device ID
  * and is in the default state. We need to identify the thing and
@@ -1193,11 +1371,9 @@
 
 	dbg("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
 		dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
+	set_device_description (dev);
+
 #ifdef DEBUG
-	if (dev->descriptor.iManufacturer)
-		usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
-	if (dev->descriptor.iProduct)
-		usb_show_string(dev, "Product", dev->descriptor.iProduct);
 	if (dev->descriptor.iSerialNumber)
 		usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
 #endif
@@ -1206,6 +1382,13 @@
 	err = device_register (&dev->dev);
 	if (err)
 		return err;
+	device_create_file (&dev->dev, &usb_config_entry);
+	if (dev->descriptor.iManufacturer)
+		device_create_file (&dev->dev, &usb_manufacturer_entry);
+	if (dev->descriptor.iProduct)
+		device_create_file (&dev->dev, &usb_product_entry);
+	if (dev->descriptor.iSerialNumber)
+		device_create_file (&dev->dev, &usb_serial_entry);
 
 	/* now that the basic setup is over, add a /proc/bus/usb entry */
 	usbfs_add_device(dev);
diff -Nru a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
--- a/drivers/usb/host/Makefile	Tue Jul 16 16:49:43 2002
+++ b/drivers/usb/host/Makefile	Tue Jul 16 16:49:43 2002
@@ -7,11 +7,8 @@
 
 obj-$(CONFIG_USB_EHCI_HCD)	+= ehci-hcd.o
 obj-$(CONFIG_USB_OHCI_HCD)	+= ohci-hcd.o
-obj-$(CONFIG_USB_UHCI_HCD)	+= usb-uhci-hcd.o
 obj-$(CONFIG_USB_UHCI_HCD_ALT)	+= uhci-hcd.o
 
-obj-$(CONFIG_USB_UHCI)		+= usb-uhci.o
-obj-$(CONFIG_USB_UHCI_ALT)	+= uhci.o
 obj-$(CONFIG_USB_OHCI)		+= usb-ohci.o usb-ohci-pci.o
 obj-$(CONFIG_USB_OHCI_SA1111)	+= usb-ohci.o usb-ohci-sa1111.o
 obj-$(CONFIG_USB_SL811HS)	+= hc_sl811.o
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/host/ehci-q.c	Tue Jul 16 16:49:42 2002
@@ -170,7 +170,7 @@
 	/* cleanse status if we saw no error */
 	if (likely (urb->status == -EINPROGRESS)) {
 		if (urb->actual_length != urb->transfer_buffer_length
-				&& (urb->transfer_flags & USB_DISABLE_SPD))
+				&& (urb->transfer_flags & URB_SHORT_NOT_OK))
 			urb->status = -EREMOTEIO;
 		else
 			urb->status = 0;
@@ -202,7 +202,7 @@
 
 	if (likely (urb->status == -EINPROGRESS)) {
 		if (urb->actual_length != urb->transfer_buffer_length
-				&& (urb->transfer_flags & USB_DISABLE_SPD))
+				&& (urb->transfer_flags & URB_SHORT_NOT_OK))
 			urb->status = -EREMOTEIO;
 		else
 			urb->status = 0;
@@ -793,7 +793,7 @@
 			last_qtd->hw_next = hw_next;
 
 			/* previous urb allows short rx? maybe optimize. */
-			if (!(last_qtd->urb->transfer_flags & USB_DISABLE_SPD)
+			if (!(last_qtd->urb->transfer_flags & URB_SHORT_NOT_OK)
 					&& (epnum & 0x10)) {
 				// only the last QTD for now
 				last_qtd->hw_alt_next = hw_next;
diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
--- a/drivers/usb/host/ohci-dbg.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/usb/host/ohci-dbg.c	Tue Jul 16 16:49:43 2002
@@ -12,13 +12,14 @@
  
 #ifdef DEBUG
 
-#define pipestring(pipe) ({ char *temp; \
-	switch (usb_pipetype (pipe)) { \
+#define edstring(ed_type) ({ char *temp; \
+	switch (ed_type) { \
 	case PIPE_CONTROL:	temp = "CTRL"; break; \
 	case PIPE_BULK:		temp = "BULK"; break; \
 	case PIPE_INTERRUPT:	temp = "INTR"; break; \
 	default: 		temp = "ISOC"; break; \
 	}; temp;})
+#define pipestring(pipe) edstring(usb_pipetype(pipe))
 
 /* debug| print the main components of an URB     
  * small: 0) header + data packets 1) just header
@@ -35,9 +36,9 @@
 #ifndef	OHCI_VERBOSE_DEBUG
 	if (urb->status != 0)
 #endif
-	dbg("%s:[%4x] dev:%d,ep=%d-%c,%s,flags:%4x,len:%d/%d,stat:%d", 
+	dbg("%s %p dev:%d,ep=%d-%c,%s,flags:%x,len:%d/%d,stat:%d", 
 		    str,
-		    usb_get_current_frame_number (urb->dev), 
+		    urb,
 		    usb_pipedevice (pipe),
 		    usb_pipeendpoint (pipe), 
 		    usb_pipeout (pipe)? 'O': 'I',
@@ -242,21 +243,25 @@
 	ohci_dump_roothub (controller, 1);
 }
 
+static const char data0 [] = "DATA0";
+static const char data1 [] = "DATA1";
+
 static void ohci_dump_td (char *label, struct td *td)
 {
 	u32	tmp = le32_to_cpup (&td->hwINFO);
 
-	dbg ("%s td %p; urb %p index %d; hw next td %08x",
+	dbg ("%s td %p%s; urb %p index %d; hw next td %08x",
 		label, td,
+		(tmp & TD_DONE) ? " (DONE)" : "",
 		td->urb, td->index,
 		le32_to_cpup (&td->hwNextTD));
 	if ((tmp & TD_ISO) == 0) {
-		char	*toggle, *pid;
+		const char	*toggle, *pid;
 		u32	cbp, be;
 
 		switch (tmp & TD_T) {
-		case TD_T_DATA0: toggle = "DATA0"; break;
-		case TD_T_DATA1: toggle = "DATA1"; break;
+		case TD_T_DATA0: toggle = data0; break;
+		case TD_T_DATA1: toggle = data1; break;
 		case TD_T_TOGGLE: toggle = "(CARRY)"; break;
 		default: toggle = "(?)"; break;
 		}
@@ -297,9 +302,9 @@
 	u32	tmp = ed->hwINFO;
 	char	*type = "";
 
-	dbg ("%s: %s, ed %p state 0x%x type %d; next ed %08x",
+	dbg ("%s: %s, ed %p state 0x%x type %s; next ed %08x",
 		ohci->hcd.self.bus_name, label,
-		ed, ed->state, ed->type,
+		ed, ed->state, edstring (ed->type),
 		le32_to_cpup (&ed->hwNextED));
 	switch (tmp & (ED_IN|ED_OUT)) {
 	case ED_OUT: type = "-OUT"; break;
@@ -314,10 +319,10 @@
 		0x000f & (le32_to_cpu (tmp) >> 7),
 		type,
 		0x007f & le32_to_cpu (tmp));
-	dbg ("  tds: head %08x%s%s tail %08x%s",
+	dbg ("  tds: head %08x %s%s tail %08x%s",
 		tmp = le32_to_cpup (&ed->hwHeadP),
+		(ed->hwHeadP & ED_C) ? data1 : data0,
 		(ed->hwHeadP & ED_H) ? " HALT" : "",
-		(ed->hwHeadP & ED_C) ? " CARRY" : "",
 		le32_to_cpup (&ed->hwTailP),
 		verbose ? "" : " (not listing)");
 	if (verbose) {
diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/usb/host/ohci-hcd.c	Tue Jul 16 16:49:41 2002
@@ -197,7 +197,7 @@
 
 	/* allocate the TDs (updating hash chains) */
 	spin_lock_irqsave (&ohci->lock, flags);
-	for (i = 0; i < size; i++) { 
+	for (i = 0; i < size; i++) {
 		urb_priv->td [i] = td_alloc (ohci, SLAB_ATOMIC);
 		if (!urb_priv->td [i]) {
 			urb_priv->length = i;
@@ -208,6 +208,8 @@
 	}	
 
 // FIXME:  much of this switch should be generic, move to hcd code ...
+// ... and what's not generic can't really be handled this way.
+// need to consider periodicity for both types!
 
 	/* allocate and claim bandwidth if needed; ISO
 	 * needs start frame index if it was't provided.
@@ -247,14 +249,14 @@
 
 	spin_unlock_irqrestore (&ohci->lock, flags);
 
-	return 0;	
+	return 0;
 }
 
 /*
  * decouple the URB from the HC queues (TDs, urb_priv); it's
- * already marked for deletion.  reporting is always done
+ * already marked using urb->status.  reporting is always done
  * asynchronously, and we might be dealing with an urb that's
- * almost completed anyway...
+ * partially transferred, or an ED with other urbs being unlinked.
  */
 static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 {
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/usb/host/ohci-q.c	Tue Jul 16 16:49:43 2002
@@ -465,6 +465,25 @@
 		 * we know it's already a power of 2
 		 */
 		ed->interval = interval;
+#ifdef DEBUG
+	/*
+	 * There are two other cases we ought to change hwINFO, both during
+	 * enumeration.  There, the control request completes, unlinks, and
+	 * the next request gets queued before the unlink completes, so it
+	 * uses old/wrong hwINFO.  How much of a problem is this?  khubd is
+	 * already retrying after such failures...
+	 */
+	} else if (type == PIPE_CONTROL) {
+		u32	info = le32_to_cpup (&ed->hwINFO);
+
+		if (!(info & 0x7f))
+			dbg ("RETRY ctrl: address != 0");
+		info >>= 16;
+		if (info != udev->epmaxpacketin [0])
+			dbg ("RETRY ctrl: maxpacket %d != 8",
+				udev->epmaxpacketin [0]);
+
+#endif /* DEBUG */
 	}
 
 done:
@@ -539,12 +558,15 @@
 
 	/* aim for only one interrupt per urb.  mostly applies to control
 	 * and iso; other urbs rarely need more than one TD per urb.
+	 * this way, only final tds (or ones with an error) cause IRQs.
 	 *
 	 * NOTE: could delay interrupts even for the last TD, and get fewer
 	 * interrupts ... increasing per-urb latency by sharing interrupts.
+	 * Drivers that queue bulk urbs may request that behavior.
 	 */
-	if (index != (urb_priv->length - 1))
-		info |= is_iso ? TD_DI_SET (7) : TD_DI_SET (1);
+	if (index != (urb_priv->length - 1)
+			|| (urb->transfer_flags & URB_NO_INTERRUPT))
+		info |= TD_DI_SET (7);
 
 	/* use this td as the next dummy */
 	td_pt = urb_priv->td [index];
@@ -565,6 +587,7 @@
 	td->hwINFO = cpu_to_le32 (info);
 	if (is_iso) {
 		td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
+		td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
 		td->ed->intriso.last_iso = info & 0xffff;
 	} else {
 		td->hwCBP = cpu_to_le32 (data); 
@@ -574,7 +597,6 @@
 	else
 		td->hwBE = 0;
 	td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
-	td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
 
 	/* HC might read the TD right after we link it ... */
 	wmb ();
@@ -596,17 +618,17 @@
 	int		cnt = 0; 
 	__u32		info = 0;
   	unsigned int	toggle = 0;
+	int		is_out = usb_pipeout (urb->pipe);
 
 	/* OHCI handles the DATA-toggles itself, we just use the
 	 * USB-toggle bits for resetting
 	 */
-  	if (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
-			usb_pipeout (urb->pipe))) {
+  	if (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) {
   		toggle = TD_T_TOGGLE;
 	} else {
   		toggle = TD_T_DATA0;
 		usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
-			usb_pipeout (urb->pipe), 1);
+			is_out, 1);
 	}
 
 	urb_priv->td_cnt = 0;
@@ -614,9 +636,9 @@
 	if (data_len) {
 		data = pci_map_single (ohci->hcd.pdev,
 				       urb->transfer_buffer, data_len,
-				       usb_pipeout (urb->pipe)
-				       ? PCI_DMA_TODEVICE
-				       : PCI_DMA_FROMDEVICE);
+				       is_out
+					       ? PCI_DMA_TODEVICE
+					       : PCI_DMA_FROMDEVICE);
 	} else
 		data = 0;
 
@@ -625,18 +647,20 @@
 	 */
 	switch (usb_pipetype (urb->pipe)) {
 		case PIPE_BULK:
-			info = usb_pipeout (urb->pipe)
+			info = is_out
 				? TD_CC | TD_DP_OUT
 				: TD_CC | TD_DP_IN ;
+			/* TDs _could_ transfer up to 8K each */
 			while (data_len > 4096) {		
 				td_fill (ohci,
 					info | (cnt? TD_T_TOGGLE:toggle),
 					data, 4096, urb, cnt);
 				data += 4096; data_len -= 4096; cnt++;
 			}
-			info = usb_pipeout (urb->pipe)?
-				TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
-			td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle),
+			/* maybe avoid ED halt on final TD short read */
+			if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+				info |= TD_R;
+			td_fill (ohci, info | (cnt ? TD_T_TOGGLE : toggle),
 				data, data_len, urb, cnt);
 			cnt++;
 			if ((urb->transfer_flags & USB_ZERO_PACKET)
@@ -653,8 +677,11 @@
 			break;
 
 		case PIPE_INTERRUPT:
+			/* current policy:  only one TD per request.
+			 * otherwise identical to bulk, except for BLF
+			 */
 			info = TD_CC | toggle;
-			info |= usb_pipeout (urb->pipe) 
+			info |= is_out
 				?  TD_DP_OUT
 				:  TD_R | TD_DP_IN;
 			td_fill (ohci, info, data, data_len, urb, cnt++);
@@ -670,14 +697,12 @@
 				 8, urb, cnt++); 
 			if (data_len > 0) {  
 				info = TD_CC | TD_R | TD_T_DATA1;
-				info |= usb_pipeout (urb->pipe)
-				    ? TD_DP_OUT
-				    : TD_DP_IN;
+				info |= is_out ? TD_DP_OUT : TD_DP_IN;
 				/* NOTE:  mishandles transfers >8K, some >4K */
 				td_fill (ohci, info, data, data_len,
 						urb, cnt++);  
 			} 
-			info = usb_pipeout (urb->pipe)
+			info = is_out
 				? TD_CC | TD_DP_IN | TD_T_DATA1
 				: TD_CC | TD_DP_OUT | TD_T_DATA1;
 			td_fill (ohci, info, data, 0, urb, cnt++);
@@ -726,10 +751,6 @@
 		int	dlen = 0;
 
  		cc = (tdPSW >> 12) & 0xF;
-		if (! ((urb->transfer_flags & USB_DISABLE_SPD)
-				&& (cc == TD_DATAUNDERRUN)))
-			cc = TD_CC_NOERROR;
-
 		if (usb_pipeout (urb->pipe))
 			dlen = urb->iso_frame_desc [td->index].length;
 		else
@@ -758,9 +779,9 @@
 				usb_pipeendpoint (urb->pipe),
 				usb_pipeout (urb->pipe));
 
-		/* update packet status if needed (short may be ok) */
-		if (((urb->transfer_flags & USB_DISABLE_SPD) != 0
-				&& cc == TD_DATAUNDERRUN))
+		/* update packet status if needed (short is normally ok) */
+		if (cc == TD_DATAUNDERRUN
+				&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
 			cc = TD_CC_NOERROR;
 		if (cc != TD_CC_NOERROR) {
 			spin_lock (&urb->lock);
@@ -810,10 +831,13 @@
 	while (td_list_hc) {		
 		td_list = dma_to_td (ohci, td_list_hc);
 
+		td_list->hwINFO |= cpu_to_le32 (TD_DONE);
+
 		if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
 			urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
-			/* typically the endpoint halts on error; un-halt,
-			 * and maybe dequeue other TDs from this urb
+			/* Non-iso endpoints can halt on error; un-halt,
+			 * and dequeue any other TDs from this urb.
+			 * No other TD could have caused the halt.
 			 */
 			if (td_list->ed->hwHeadP & ED_H) {
 				if (urb_priv && ((td_list->index + 1)
diff -Nru a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
--- a/drivers/usb/host/ohci-sa1111.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/host/ohci-sa1111.c	Tue Jul 16 16:49:42 2002
@@ -175,7 +175,7 @@
 	usb_bus_init (&hcd->self);
 	hcd->self.op = &usb_hcd_operations;
 	hcd->self.hcpriv = (void *) hcd;
-	hcd->self.bus_name = "SA-1111";
+	hcd->self.bus_name = "sa1111";
 	hcd->product_desc = "SA-1111 OHCI";
 
 	INIT_LIST_HEAD (&hcd->dev_list);
diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
--- a/drivers/usb/host/ohci.h	Tue Jul 16 16:49:43 2002
+++ b/drivers/usb/host/ohci.h	Tue Jul 16 16:49:43 2002
@@ -11,6 +11,9 @@
 /*
  * OHCI Endpoint Descriptor (ED) ... holds TD queue
  * See OHCI spec, section 4.2
+ *
+ * This is a "Queue Head" for those transfers, which is why
+ * both EHCI and UHCI call similar structures a "QH".
  */
 struct ed {
 	/* first fields are hardware-specified, le32 */
@@ -74,8 +77,8 @@
 	/* these two bits are available for definition/use by HCDs in both
 	 * general and iso tds ... others are available for only one type
 	 */
-//#define TD____	    0x00020000
-#define TD_ISO	    0x00010000			/* copy of ED_ISO */
+#define TD_DONE     0x00020000			/* retired to donelist */
+#define TD_ISO      0x00010000			/* copy of ED_ISO */
 
 	/* hwINFO bits for general tds: */
 #define TD_EC       0x0C000000			/* error count */
@@ -349,12 +352,14 @@
         struct device		*parent_dev;
 
 	/*
-	 * I/O memory used to communicate with the HC (uncached);
+	 * I/O memory used to communicate with the HC (dma-consistent)
 	 */
 	struct ohci_regs	*regs;
 
 	/*
-	 * main memory used to communicate with the HC (uncached)
+	 * main memory used to communicate with the HC (dma-consistent).
+	 * hcd adds to schedule for a live hc any time, but removals finish
+	 * only at the start of the next frame.
 	 */
 	struct ohci_hcca	*hcca;
 	dma_addr_t		hcca_dma;
@@ -365,6 +370,9 @@
 	struct ed		*ed_controltail;	/* last in ctrl list */
  	struct ed		*ed_isotail;		/* last in iso list */
 
+	/*
+	 * memory management for queue data structures
+	 */
 	struct pci_pool		*td_cache;
 	struct pci_pool		*ed_cache;
 	struct hash_list_t	td_hash [TD_HASH_SIZE];
@@ -380,6 +388,7 @@
 
 	unsigned long		flags;		/* for HC bugs */
 #define	OHCI_QUIRK_AMD756	0x01			/* erratum #4 */
+	// there are also chip quirks/bugs in init logic
 
 	/*
 	 * framework state
diff -Nru a/drivers/usb/host/uhci-debug.h b/drivers/usb/host/uhci-debug.h
--- a/drivers/usb/host/uhci-debug.h	Tue Jul 16 16:49:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,577 +0,0 @@
-/*
- * UHCI-specific debugging code. Invaluable when something
- * goes wrong, but don't get in my face.
- *
- * Kernel visible pointers are surrounded in []'s and bus
- * visible pointers are surrounded in ()'s
- *
- * (C) Copyright 1999 Linus Torvalds
- * (C) Copyright 1999-2001 Johannes Erdfelt
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
-#include <asm/io.h>
-
-#include "uhci.h"
-
-/* Handle REALLY large printk's so we don't overflow buffers */
-static void inline lprintk(char *buf)
-{
-	char *p;
-
-	/* Just write one line at a time */
-	while (buf) {
-		p = strchr(buf, '\n');
-		if (p)
-			*p = 0;
-		printk("%s\n", buf);
-		buf = p;
-		if (buf)
-			buf++;
-	}
-}
-
-static int inline uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td)
-{
-	int i;
-
-	for (i = 0; i < UHCI_NUM_SKELTD; i++)
-		if (td == uhci->skeltd[i])
-			return 1;
-
-	return 0;
-}
-
-static int inline uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
-{
-	int i;
-
-	for (i = 0; i < UHCI_NUM_SKELQH; i++)
-		if (qh == uhci->skelqh[i])
-			return 1;
-
-	return 0;
-}
-
-static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
-{
-	char *out = buf;
-	char *spid;
-
-	/* Try to make sure there's enough memory */
-	if (len < 160)
-		return 0;
-
-	out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, td->link);
-	out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
-		((td->status >> 27) & 3),
-		(td->status & TD_CTRL_SPD) ?      "SPD " : "",
-		(td->status & TD_CTRL_LS) ?       "LS " : "",
-		(td->status & TD_CTRL_IOC) ?      "IOC " : "",
-		(td->status & TD_CTRL_ACTIVE) ?   "Active " : "",
-		(td->status & TD_CTRL_STALLED) ?  "Stalled " : "",
-		(td->status & TD_CTRL_DBUFERR) ?  "DataBufErr " : "",
-		(td->status & TD_CTRL_BABBLE) ?   "Babble " : "",
-		(td->status & TD_CTRL_NAK) ?      "NAK " : "",
-		(td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
-		(td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
-		td->status & 0x7ff);
-
-	switch (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;
-	}
-
-	out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
-		td->info >> 21,
-		((td->info >> 19) & 1),
-		(td->info >> 15) & 15,
-		(td->info >> 8) & 127,
-		(td->info & 0xff),
-		spid);
-	out += sprintf(out, "(buf=%08x)\n", td->buffer);
-
-	return out - buf;
-}
-
-static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
-{
-	char *out = buf;
-
-	/* Try to make sure there's enough memory */
-	if (len < 80)
-		return 0;
-
-	out += sprintf(out, "  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 " : "");
-
-	return out - buf;
-}
-
-static int uhci_show_status(struct uhci *uhci, char *buf, int len)
-{
-	char *out = buf;
-	unsigned int io_addr = uhci->io_addr;
-	unsigned short usbcmd, usbstat, usbint, usbfrnum;
-	unsigned int flbaseadd;
-	unsigned char sof;
-	unsigned short portsc1, portsc2;
-
-	/* Try to make sure there's enough memory */
-	if (len < 80 * 6)
-		return 0;
-
-	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);
-
-	out += sprintf(out, "  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 " : "");
-
-	out += sprintf(out, "  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 " : "");
-
-	out += sprintf(out, "  usbint    =     %04x\n", usbint);
-	out += sprintf(out, "  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
-		0xfff & (4*(unsigned int)usbfrnum));
-	out += sprintf(out, "  flbaseadd = %08x\n", flbaseadd);
-	out += sprintf(out, "  sof       =       %02x\n", sof);
-	out += uhci_show_sc(1, portsc1, out, len - (out - buf));
-	out += uhci_show_sc(2, portsc2, out, len - (out - buf));
-
-	return out - buf;
-}
-
-static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
-{
-	char *out = buf;
-	struct urb_priv *urbp;
-	struct list_head *head, *tmp;
-	struct uhci_td *td;
-	int i = 0, checked = 0, prevactive = 0;
-
-	/* Try to make sure there's enough memory */
-	if (len < 80 * 6)
-		return 0;
-
-	out += sprintf(out, "%*s[%p] link (%08x) element (%08x)\n", space, "",
-			qh, qh->link, qh->element);
-
-	if (qh->element & UHCI_PTR_QH)
-		out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
-
-	if (qh->element & UHCI_PTR_DEPTH)
-		out += sprintf(out, "%*s  Depth traverse\n", space, "");
-
-	if (qh->element & 8)
-		out += sprintf(out, "%*s  Bit 3 set (bug?)\n", space, "");
-
-	if (!(qh->element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
-		out += sprintf(out, "%*s  Element is NULL (bug?)\n", space, "");
-
-	if (!qh->urbp) {
-		out += sprintf(out, "%*s  urbp == NULL\n", space, "");
-		goto out;
-	}
-
-	urbp = qh->urbp;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-
-	td = list_entry(tmp, struct uhci_td, list);
-
-	if (td->dma_handle != (qh->element & ~UHCI_PTR_BITS))
-		out += sprintf(out, "%*s Element != First TD\n", space, "");
-
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		out += sprintf(out, "%*s%d: ", space + 2, "", i++);
-		out += uhci_show_td(td, out, len - (out - buf), 0);
-
-		if (i > 10 && !checked && prevactive && tmp != head &&
-		    debug <= 2) {
-			struct list_head *ntmp = tmp;
-			struct uhci_td *ntd = td;
-			int active = 1, ni = i;
-
-			checked = 1;
-
-			while (ntmp != head && ntmp->next != head && active) {
-				ntd = list_entry(ntmp, struct uhci_td, list);
-
-				ntmp = ntmp->next;
-
-				active = ntd->status & TD_CTRL_ACTIVE;
-
-				ni++;
-			}
-
-			if (active && ni > i) {
-				out += sprintf(out, "%*s[skipped %d active TD's]\n", space, "", ni - i);
-				tmp = ntmp;
-				td = ntd;
-				i = ni;
-			}
-		}
-
-		prevactive = td->status & TD_CTRL_ACTIVE;
-	}
-
-	if (list_empty(&urbp->queue_list) || urbp->queued)
-		goto out;
-
-	out += sprintf(out, "%*sQueued QH's:\n", -space, "--");
-
-	head = &urbp->queue_list;
-	tmp = head->next;
-
-	while (tmp != head) {
-		struct urb_priv *nurbp = list_entry(tmp, struct urb_priv,
-						queue_list);
-		tmp = tmp->next;
-
-		out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space);
-	}
-
-out:
-	return out - buf;
-}
-
-static const char *td_names[] = {"skel_int1_td", "skel_int2_td",
-				 "skel_int4_td", "skel_int8_td",
-				 "skel_int16_td", "skel_int32_td",
-				 "skel_int64_td", "skel_int128_td",
-				 "skel_int256_td", "skel_term_td" };
-static const char *qh_names[] = { "skel_ls_control_qh", "skel_hs_control_qh",
-				  "skel_bulk_qh", "skel_term_qh" };
-
-#define show_frame_num()	\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- Frame %d\n", i); \
-	}
-
-#define show_td_name()		\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- %s\n", td_names[i]); \
-	}
-
-#define show_qh_name()		\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- %s\n", qh_names[i]); \
-	}
-
-static int uhci_sprint_schedule(struct uhci *uhci, char *buf, int len)
-{
-	char *out = buf;
-	int i;
-	struct uhci_qh *qh;
-	struct uhci_td *td;
-	struct list_head *tmp, *head;
-
-	out += sprintf(out, "HC status\n");
-	out += uhci_show_status(uhci, out, len - (out - buf));
-
-	out += sprintf(out, "Frame List\n");
-	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
-		int shown = 0;
-		td = uhci->fl->frame_cpu[i];
-		if (!td)
-			continue;
-
-		if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) {
-			show_frame_num();
-			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
-		}
-		if (uhci_is_skeleton_td(uhci, td))
-			continue;
-		show_frame_num();
-
-		head = &td->fl_list;
-		tmp = head;
-		do {
-			td = list_entry(tmp, struct uhci_td, fl_list);
-			tmp = tmp->next;
-			out += uhci_show_td(td, out, len - (out - buf), 4);
-		} while (tmp != head);
-	}
-
-	out += sprintf(out, "Skeleton TD's\n");
-	for (i = UHCI_NUM_SKELTD - 1; i >= 0; i--) {
-		int shown = 0;
-
-		td = uhci->skeltd[i];
-
-		if (debug > 1) {
-			show_td_name();
-			out += uhci_show_td(td, out, len - (out - buf), 4);
-		}
-
-		if (list_empty(&td->fl_list)) {
-			/* TD 0 is the int1 TD and links to control_ls_qh */
-			if (!i) {
-				if (td->link !=
-				    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH)) {
-					show_td_name();
-					out += sprintf(out, "    skeleton TD not linked to ls_control QH!\n");
-				}
-			} else if (i < 9) {
-				if (td->link != uhci->skeltd[i - 1]->dma_handle) {
-					show_td_name();
-					out += sprintf(out, "    skeleton TD not linked to next skeleton TD!\n");
-				}
-			} else {
-				show_td_name();
-
-				if (td->link != td->dma_handle)
-					out += sprintf(out, "    skel_term_td does not link to self\n");
-
-				/* Don't show it twice */
-				if (debug <= 1)
-					out += uhci_show_td(td, out, len - (out - buf), 4);
-			}
-
-			continue;
-		}
-
-		show_td_name();
-
-		head = &td->fl_list;
-		tmp = head->next;
-
-		while (tmp != head) {
-			td = list_entry(tmp, struct uhci_td, fl_list);
-
-			tmp = tmp->next;
-
-			out += uhci_show_td(td, out, len - (out - buf), 4);
-		}
-
-		if (!i) {
-			if (td->link !=
-			    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH))
-				out += sprintf(out, "    last TD not linked to ls_control QH!\n");
-		} else if (i < 9) {
-			if (td->link != uhci->skeltd[i - 1]->dma_handle)
-				out += sprintf(out, "    last TD not linked to next skeleton!\n");
-		}
-	}
-
-	out += sprintf(out, "Skeleton QH's\n");
-
-	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
-		int shown = 0;
-
-		qh = uhci->skelqh[i];
-
-		if (debug > 1) {
-			show_qh_name();
-			out += uhci_show_qh(qh, out, len - (out - buf), 4);
-		}
-
-		/* QH 3 is the Terminating QH, it's different */
-		if (i == 3) {
-			if (qh->link != UHCI_PTR_TERM) {
-				show_qh_name();
-				out += sprintf(out, "    bandwidth reclamation on!\n");
-			}
-
-			if (qh->element != uhci->skel_term_td->dma_handle) {
-				show_qh_name();
-				out += sprintf(out, "    skel_term_qh element is not set to skel_term_td\n");
-			}
-		}
-
-		if (list_empty(&qh->list)) {
-			if (i < 3) {
-				if (qh->link !=
-				    (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH)) {
-					show_qh_name();
-					out += sprintf(out, "    skeleton QH not linked to next skeleton QH!\n");
-				}
-			}
-
-			continue;
-		}
-
-		show_qh_name();
-
-		head = &qh->list;
-		tmp = head->next;
-
-		while (tmp != head) {
-			qh = list_entry(tmp, struct uhci_qh, list);
-
-			tmp = tmp->next;
-
-			out += uhci_show_qh(qh, out, len - (out - buf), 4);
-		}
-
-		if (i < 3) {
-			if (qh->link !=
-			    (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH))
-				out += sprintf(out, "    last QH not linked to next skeleton!\n");
-		}
-	}
-
-	return out - buf;
-}
-
-#ifdef CONFIG_PROC_FS
-#define MAX_OUTPUT	(PAGE_SIZE * 8)
-
-static struct proc_dir_entry *uhci_proc_root = NULL;
-
-struct uhci_proc {
-	int size;
-	char *data;
-	struct uhci *uhci;
-};
-
-static int uhci_proc_open(struct inode *inode, struct file *file)
-{
-	const struct proc_dir_entry *dp = PDE(inode);
-	struct uhci *uhci = dp->data;
-	struct uhci_proc *up;
-	unsigned long flags;
-	int ret = -ENOMEM;
-
-	lock_kernel();
-	up = kmalloc(sizeof(*up), GFP_KERNEL);
-	if (!up)
-		goto out;
-
-	up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
-	if (!up->data) {
-		kfree(up);
-		goto out;
-	}
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-
-	file->private_data = up;
-
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
-}
-
-static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence)
-{
-	struct uhci_proc *up;
-	loff_t new = -1;
-
-	lock_kernel();
-	up = file->private_data;
-
-	switch (whence) {
-	case 0:
-		new = off;
-		break;
-	case 1:
-		new = file->f_pos + off;
-		break;
-	}
-	if (new < 0 || new > up->size) {
-		unlock_kernel();
-		return -EINVAL;
-	}
-	unlock_kernel();
-	return (file->f_pos = new);
-}
-
-static ssize_t uhci_proc_read(struct file *file, char *buf, size_t nbytes,
-			loff_t *ppos)
-{
-	struct uhci_proc *up = file->private_data;
-	unsigned int pos;
-	unsigned int size;
-
-	pos = *ppos;
-	size = up->size;
-	if (pos >= size)
-		return 0;
-	if (nbytes >= size)
-		nbytes = size;
-	if (pos + nbytes > size)
-		nbytes = size - pos;
-
-	if (!access_ok(VERIFY_WRITE, buf, nbytes))
-		return -EINVAL;
-
-	copy_to_user(buf, up->data + pos, nbytes);
-
-	*ppos += nbytes;
-
-	return nbytes;
-}
-
-static int uhci_proc_release(struct inode *inode, struct file *file)
-{
-	struct uhci_proc *up = file->private_data;
-
-	kfree(up->data);
-	kfree(up);
-
-	return 0;
-}
-
-static struct file_operations uhci_proc_operations = {
-	open:		uhci_proc_open,
-	llseek:		uhci_proc_lseek,
-	read:		uhci_proc_read,
-//	write:		uhci_proc_write,
-	release:	uhci_proc_release,
-};
-#endif
-
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c	Tue Jul 16 16:49:43 2002
+++ b/drivers/usb/host/uhci-hcd.c	Tue Jul 16 16:49:43 2002
@@ -491,7 +491,7 @@
 }
 
 /* This function will append one URB's QH to another URB's QH. This is for */
-/*  USB_QUEUE_BULK support for bulk transfers and soon implicitily for */
+/* queuing bulk transfers and soon implicitily for */
 /*  control transfers */
 static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb)
 {
@@ -840,7 +840,7 @@
 	 */
 	destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe));
 
-	if (!(urb->transfer_flags & USB_DISABLE_SPD))
+	if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
 		status |= TD_CTRL_SPD;
 
 	/*
@@ -1006,7 +1006,7 @@
 
 		/* Check to see if we received a short packet */
 		if (uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td))) {
-			if (urb->transfer_flags & USB_DISABLE_SPD) {
+			if (urb->transfer_flags & URB_SHORT_NOT_OK) {
 				ret = -EREMOTEIO;
 				goto err;
 			}
@@ -1128,7 +1128,7 @@
 			goto td_error;
 
 		if (uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td))) {
-			if (urb->transfer_flags & USB_DISABLE_SPD) {
+			if (urb->transfer_flags & URB_SHORT_NOT_OK) {
 				ret = -EREMOTEIO;
 				goto err;
 			} else
@@ -1210,7 +1210,7 @@
 
 	/* 3 errors */
 	status = TD_CTRL_ACTIVE | uhci_maxerr(3);
-	if (!(urb->transfer_flags & USB_DISABLE_SPD))
+	if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
 		status |= TD_CTRL_SPD;
 
 	/*
@@ -1276,7 +1276,7 @@
 	/* Always assume breadth first */
 	uhci_insert_tds_in_qh(qh, urb, 1);
 
-	if (urb->transfer_flags & USB_QUEUE_BULK && eurb)
+	if (eurb)
 		uhci_append_queued_urb(uhci, eurb, urb);
 	else
 		uhci_insert_qh(uhci, uhci->skel_bulk_qh, urb);
@@ -1470,10 +1470,6 @@
 	spin_lock_irqsave(&uhci->urb_list_lock, flags);
 
 	eurb = uhci_find_urb_ep(uhci, urb);
-	if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) {
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-		return -ENXIO;
-	}
 
 	if (!uhci_alloc_urb_priv(uhci, urb)) {
 		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
@@ -1482,10 +1478,15 @@
 
 	switch (usb_pipetype(urb->pipe)) {
 	case PIPE_CONTROL:
-		ret = uhci_submit_control(uhci, urb);
+		if (eurb)
+			ret = -ENXIO;		/* no control queueing yet */
+		else
+			ret = uhci_submit_control(uhci, urb);
 		break;
 	case PIPE_INTERRUPT:
-		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
+		if (eurb)
+			ret = -ENXIO;		/* no interrupt queueing yet */
+		else if (urb->bandwidth == 0) {	/* not yet checked/allocated */
 			bustime = usb_check_bandwidth(urb->dev, urb);
 			if (bustime < 0)
 				ret = bustime;
@@ -2406,7 +2407,7 @@
 	return retval;
 }
 
-static void __devexit uhci_stop(struct usb_hcd *hcd)
+static void uhci_stop(struct usb_hcd *hcd)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
@@ -2487,7 +2488,7 @@
 	suspend:		uhci_suspend,
 	resume:			uhci_resume,
 #endif
-	stop:			__devexit_p(uhci_stop),
+	stop:			uhci_stop,
 
 	hcd_alloc:		uhci_hcd_alloc,
 	hcd_free:		uhci_hcd_free,
diff -Nru a/drivers/usb/host/uhci.c b/drivers/usb/host/uhci.c
--- a/drivers/usb/host/uhci.c	Tue Jul 16 16:49:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,3132 +0,0 @@
-/*
- * Universal Host Controller Interface driver for USB.
- *
- * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
- *
- * (C) Copyright 1999 Linus Torvalds
- * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
- * (C) Copyright 1999 Randy Dunlap
- * (C) Copyright 1999 Georg Acher, acher@in.tum.de
- * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
- * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
- * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
- * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
- *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
- * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- *
- * Intel documents this fairly well, and as far as I know there
- * are no royalties or anything like that, but even so there are
- * people who decided that they want to do the same thing in a
- * completely different way.
- *
- * WARNING! The USB documentation is downright evil. Most of it
- * is just crap, written by a committee. You're better off ignoring
- * most of it, the important stuff is:
- *  - the low-level protocol (fairly simple but lots of small details)
- *  - working around the horridness of the rest
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/proc_fs.h>
-#ifdef CONFIG_USB_DEBUG
-#define DEBUG
-#else
-#undef DEBUG
-#endif
-#include <linux/usb.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include "../core/hcd.h"
-#include "uhci.h"
-
-#include <linux/pm.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.1"
-#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
-#define DRIVER_DESC "USB Universal Host Controller Interface driver"
-
-/*
- * debug = 0, no debugging messages
- * debug = 1, dump failed URB's except for stalls
- * debug = 2, dump all failed URB's (including stalls)
- *            show all queues in /proc/uhci/hc*
- * debug = 3, show all TD's in URB's when dumping
- */
-#ifdef DEBUG
-static int debug = 1;
-#else
-static int debug = 0;
-#endif
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debug level");
-static char *errbuf;
-#define ERRBUF_LEN    (PAGE_SIZE * 8)
-
-#include "uhci-debug.h"
-
-static kmem_cache_t *uhci_up_cachep;	/* urb_priv */
-
-static int rh_submit_urb(struct urb *urb);
-static int rh_unlink_urb(struct urb *urb);
-static int uhci_get_current_frame_number(struct usb_device *dev);
-static int uhci_unlink_urb(struct urb *urb);
-static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb);
-static void uhci_call_completion(struct urb *urb);
-
-static int  ports_active(struct uhci *uhci);
-static void suspend_hc(struct uhci *uhci);
-static void wakeup_hc(struct uhci *uhci);
-
-/* If a transfer is still active after this much time, turn off FSBR */
-#define IDLE_TIMEOUT	(HZ / 20)	/* 50 ms */
-#define FSBR_DELAY	(HZ / 20)	/* 50 ms */
-
-/* When we timeout an idle transfer for FSBR, we'll switch it over to */
-/* depth first traversal. We'll do it in groups of this number of TD's */
-/* to make sure it doesn't hog all of the bandwidth */
-#define DEPTH_INTERVAL	5
-
-/*
- * Technically, updating td->status here is a race, but it's not really a
- * problem. The worst that can happen is that we set the IOC bit again
- * generating a spurios interrupt. We could fix this by creating another
- * QH and leaving the IOC bit always set, but then we would have to play
- * games with the FSBR code to make sure we get the correct order in all
- * the cases. I don't think it's worth the effort
- */
-static inline void uhci_set_next_interrupt(struct uhci *uhci)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	uhci->skel_term_td->status |= TD_CTRL_IOC;
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static inline void uhci_clear_next_interrupt(struct uhci *uhci)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	uhci->skel_term_td->status &= ~TD_CTRL_IOC;
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static inline void uhci_add_complete(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->complete_list_lock, flags);
-	list_add(&urbp->complete_list, &uhci->complete_list);
-	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
-}
-
-static struct uhci_td *uhci_alloc_td(struct uhci *uhci, struct usb_device *dev)
-{
-	dma_addr_t dma_handle;
-	struct uhci_td *td;
-
-	td = pci_pool_alloc(uhci->td_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
-	if (!td)
-		return NULL;
-
-	td->dma_handle = dma_handle;
-
-	td->link = UHCI_PTR_TERM;
-	td->buffer = 0;
-
-	td->frame = -1;
-	td->dev = dev;
-
-	INIT_LIST_HEAD(&td->list);
-	INIT_LIST_HEAD(&td->fl_list);
-
-	usb_get_dev(dev);
-
-	return td;
-}
-
-static void inline uhci_fill_td(struct uhci_td *td, __u32 status,
-		__u32 info, __u32 buffer)
-{
-	td->status = status;
-	td->info = info;
-	td->buffer = buffer;
-}
-
-static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
-{
-	unsigned long flags;
-	struct uhci_td *ltd;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	ltd = list_entry(skeltd->fl_list.prev, struct uhci_td, fl_list);
-
-	td->link = ltd->link;
-	mb();
-	ltd->link = td->dma_handle;
-
-	list_add_tail(&td->fl_list, &skeltd->fl_list);
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-/*
- * We insert Isochronous transfers directly into the frame list at the
- * beginning
- * The layout looks as follows:
- * frame list pointer -> iso td's (if any) ->
- * periodic interrupt td (if frame 0) -> irq td's -> control qh -> bulk qh
- */
-static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum)
-{
-	unsigned long flags;
-
-	framenum %= UHCI_NUMFRAMES;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	td->frame = framenum;
-
-	/* Is there a TD already mapped there? */
-	if (uhci->fl->frame_cpu[framenum]) {
-		struct uhci_td *ftd, *ltd;
-
-		ftd = uhci->fl->frame_cpu[framenum];
-		ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
-
-		list_add_tail(&td->fl_list, &ftd->fl_list);
-
-		td->link = ltd->link;
-		mb();
-		ltd->link = td->dma_handle;
-	} else {
-		td->link = uhci->fl->frame[framenum];
-		mb();
-		uhci->fl->frame[framenum] = td->dma_handle;
-		uhci->fl->frame_cpu[framenum] = td;
-	}
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
-{
-	unsigned long flags;
-
-	/* If it's not inserted, don't remove it */
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	if (td->frame == -1 && list_empty(&td->fl_list))
-		goto out;
-
-	if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
-		if (list_empty(&td->fl_list)) {
-			uhci->fl->frame[td->frame] = td->link;
-			uhci->fl->frame_cpu[td->frame] = NULL;
-		} else {
-			struct uhci_td *ntd;
-
-			ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
-			uhci->fl->frame[td->frame] = ntd->dma_handle;
-			uhci->fl->frame_cpu[td->frame] = ntd;
-		}
-	} else {
-		struct uhci_td *ptd;
-
-		ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list);
-		ptd->link = td->link;
-	}
-
-	mb();
-	td->link = UHCI_PTR_TERM;
-
-	list_del_init(&td->fl_list);
-	td->frame = -1;
-
-out:
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-/*
- * Inserts a td into qh list at the top.
- */
-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td, *ptd;
-
-	if (list_empty(&urbp->td_list))
-		return;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-
-	/* Ordering isn't important here yet since the QH hasn't been */
-	/*  inserted into the schedule yet */
-	td = list_entry(tmp, struct uhci_td, list);
-
-	/* Add the first TD to the QH element pointer */
-	qh->element = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH);
-
-	ptd = td;
-
-	/* Then link the rest of the TD's */
-	tmp = tmp->next;
-	while (tmp != head) {
-		td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		ptd->link = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH);
-
-		ptd = td;
-	}
-
-	ptd->link = UHCI_PTR_TERM;
-}
-
-static void uhci_free_td(struct uhci *uhci, struct uhci_td *td)
-{
-	if (!list_empty(&td->list) || !list_empty(&td->fl_list))
-		dbg("td is still in URB list!");
-
-	if (td->dev)
-		usb_put_dev(td->dev);
-
-	pci_pool_free(uhci->td_pool, td, td->dma_handle);
-}
-
-static struct uhci_qh *uhci_alloc_qh(struct uhci *uhci, struct usb_device *dev)
-{
-	dma_addr_t dma_handle;
-	struct uhci_qh *qh;
-
-	qh = pci_pool_alloc(uhci->qh_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
-	if (!qh)
-		return NULL;
-
-	qh->dma_handle = dma_handle;
-
-	qh->element = UHCI_PTR_TERM;
-	qh->link = UHCI_PTR_TERM;
-
-	qh->dev = dev;
-	qh->urbp = NULL;
-
-	INIT_LIST_HEAD(&qh->list);
-	INIT_LIST_HEAD(&qh->remove_list);
-
-	usb_get_dev(dev);
-
-	return qh;
-}
-
-static void uhci_free_qh(struct uhci *uhci, struct uhci_qh *qh)
-{
-	if (!list_empty(&qh->list))
-		dbg("qh list not empty!");
-	if (!list_empty(&qh->remove_list))
-		dbg("qh still in remove_list!");
-
-	if (qh->dev)
-		usb_put_dev(qh->dev);
-
-	pci_pool_free(uhci->qh_pool, qh, qh->dma_handle);
-}
-
-/*
- * MUST be called with uhci->frame_list_lock acquired
- */
-static void _uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct list_head *head, *tmp;
-	struct uhci_qh *lqh;
-
-	/* Grab the last QH */
-	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
-
-	if (lqh->urbp) {
-		head = &lqh->urbp->queue_list;
-		tmp = head->next;
-		while (head != tmp) {
-			struct urb_priv *turbp =
-				list_entry(tmp, struct urb_priv, queue_list);
-
-			tmp = tmp->next;
-
-			turbp->qh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
-		}
-	}
-
-	head = &urbp->queue_list;
-	tmp = head->next;
-	while (head != tmp) {
-		struct urb_priv *turbp =
-			list_entry(tmp, struct urb_priv, queue_list);
-
-		tmp = tmp->next;
-
-		turbp->qh->link = lqh->link;
-	}
-
-	urbp->qh->link = lqh->link;
-	mb();				/* Ordering is important */
-	lqh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
-
-	list_add_tail(&urbp->qh->list, &skelqh->list);
-}
-
-static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	_uhci_insert_qh(uhci, skelqh, urb);
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
-{
-	unsigned long flags;
-	struct uhci_qh *pqh;
-
-	if (!qh)
-		return;
-
-	qh->urbp = NULL;
-
-	/* Only go through the hoops if it's actually linked in */
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	if (!list_empty(&qh->list)) {
-		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
-
-		if (pqh->urbp) {
-			struct list_head *head, *tmp;
-
-			head = &pqh->urbp->queue_list;
-			tmp = head->next;
-			while (head != tmp) {
-				struct urb_priv *turbp =
-					list_entry(tmp, struct urb_priv, queue_list);
-
-				tmp = tmp->next;
-
-				turbp->qh->link = qh->link;
-			}
-		}
-
-		pqh->link = qh->link;
-		mb();
-		qh->element = qh->link = UHCI_PTR_TERM;
-
-		list_del_init(&qh->list);
-	}
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-
-	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
-
-	/* Check to see if the remove list is empty. Set the IOC bit */
-	/* to force an interrupt so we can remove the QH */
-	if (list_empty(&uhci->qh_remove_list))
-		uhci_set_next_interrupt(uhci);
-
-	list_add(&qh->remove_list, &uhci->qh_remove_list);
-
-	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
-}
-
-static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct list_head *head, *tmp;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (head != tmp) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		if (toggle)
-			td->info |= TD_TOKEN_TOGGLE;
-		else
-			td->info &= ~TD_TOKEN_TOGGLE;
-
-		toggle ^= 1;
-	}
-
-	return toggle;
-}
-
-/* This function will append one URB's QH to another URB's QH. This is for */
-/*  USB_QUEUE_BULK support for bulk transfers and soon implicitily for */
-/*  control transfers */
-static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct urb *urb)
-{
-	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
-	struct list_head *tmp;
-	struct uhci_td *lltd;
-	unsigned long flags;
-
-	eurbp = eurb->hcpriv;
-	urbp = urb->hcpriv;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	/* Find the first URB in the queue */
-	if (eurbp->queued) {
-		struct list_head *head = &eurbp->queue_list;
-
-		tmp = head->next;
-		while (tmp != head) {
-			struct urb_priv *turbp =
-				list_entry(tmp, struct urb_priv, queue_list);
-
-			if (!turbp->queued)
-				break;
-
-			tmp = tmp->next;
-		}
-	} else
-		tmp = &eurbp->queue_list;
-
-	furbp = list_entry(tmp, struct urb_priv, queue_list);
-	lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
-
-	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
-
-	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe),
-		uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1));
-
-	/* All qh's in the queue need to link to the next queue */
-	urbp->qh->link = eurbp->qh->link;
-
-	mb();			/* Make sure we flush everything */
-	/* Only support bulk right now, so no depth */
-	lltd->link = urbp->qh->dma_handle | UHCI_PTR_QH;
-
-	list_add_tail(&urbp->queue_list, &furbp->queue_list);
-
-	urbp->queued = 1;
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp, *nurbp;
-	struct list_head *head, *tmp;
-	struct urb_priv *purbp;
-	struct uhci_td *pltd;
-	unsigned int toggle;
-	unsigned long flags;
-
-	urbp = urb->hcpriv;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	if (list_empty(&urbp->queue_list))
-		goto out;
-
-	nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
-
-	/* Fix up the toggle for the next URB's */
-	if (!urbp->queued)
-		/* We set the toggle when we unlink */
-		toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-	else {
-		/* If we're in the middle of the queue, grab the toggle */
-		/*  from the TD previous to us */
-		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
-				queue_list);
-
-		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
-
-		toggle = uhci_toggle(pltd->info) ^ 1;
-	}
-
-	head = &urbp->queue_list;
-	tmp = head->next;
-	while (head != tmp) {
-		struct urb_priv *turbp;
-
-		turbp = list_entry(tmp, struct urb_priv, queue_list);
-
-		tmp = tmp->next;
-
-		if (!turbp->queued)
-			break;
-
-		toggle = uhci_fixup_toggle(turbp->urb, toggle);
-	}
-
-	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-		usb_pipeout(urb->pipe), toggle);
-
-	if (!urbp->queued) {
-		nurbp->queued = 0;
-
-		_uhci_insert_qh(uhci, uhci->skel_bulk_qh, nurbp->urb);
-	} else {
-		/* We're somewhere in the middle (or end). A bit trickier */
-		/*  than the head scenario */
-		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
-				queue_list);
-
-		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
-		if (nurbp->queued)
-			pltd->link = nurbp->qh->dma_handle | UHCI_PTR_QH;
-		else
-			/* The next URB happens to be the beginning, so */
-			/*  we're the last, end the chain */
-			pltd->link = UHCI_PTR_TERM;
-	}
-
-	list_del_init(&urbp->queue_list);
-
-out:
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static struct urb_priv *uhci_alloc_urb_priv(struct uhci *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp;
-
-	urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
-	if (!urbp) {
-		err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
-		return NULL;
-	}
-
-	memset((void *)urbp, 0, sizeof(*urbp));
-
-	urbp->inserttime = jiffies;
-	urbp->fsbrtime = jiffies;
-	urbp->urb = urb;
-	urbp->dev = urb->dev;
-	
-	INIT_LIST_HEAD(&urbp->td_list);
-	INIT_LIST_HEAD(&urbp->queue_list);
-	INIT_LIST_HEAD(&urbp->complete_list);
-
-	urb->hcpriv = urbp;
-
-	if (urb->dev != uhci->rh.dev) {
-		if (urb->transfer_buffer_length) {
-			urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev,
-				urb->transfer_buffer, urb->transfer_buffer_length,
-				usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE :
-				PCI_DMA_TODEVICE);
-			if (!urbp->transfer_buffer_dma_handle)
-				return NULL;
-		}
-
-		if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) {
-			urbp->setup_packet_dma_handle = pci_map_single(uhci->dev,
-				urb->setup_packet, sizeof(struct usb_ctrlrequest),
-				PCI_DMA_TODEVICE);
-			if (!urbp->setup_packet_dma_handle)
-				return NULL;
-		}
-	}
-
-	return urbp;
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	td->urb = urb;
-
-	list_add_tail(&td->list, &urbp->td_list);
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static void uhci_remove_td_from_urb(struct uhci_td *td)
-{
-	if (list_empty(&td->list))
-		return;
-
-	list_del_init(&td->list);
-
-	td->urb = NULL;
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static void uhci_destroy_urb_priv(struct urb *urb)
-{
-	struct list_head *head, *tmp;
-	struct urb_priv *urbp;
-	struct uhci *uhci;
-
-	urbp = (struct urb_priv *)urb->hcpriv;
-	if (!urbp)
-		return;
-
-	if (!urbp->dev || !urbp->dev->bus || !urbp->dev->bus->hcpriv) {
-		warn("uhci_destroy_urb_priv: urb %p belongs to disconnected device or bus?", urb);
-		return;
-	}
-
-	if (!list_empty(&urb->urb_list))
-		warn("uhci_destroy_urb_priv: urb %p still on uhci->urb_list or uhci->remove_list", urb);
-
-	if (!list_empty(&urbp->complete_list))
-		warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", urb);
-
-	uhci = urbp->dev->bus->hcpriv;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		uhci_remove_td_from_urb(td);
-		uhci_remove_td(uhci, td);
-		uhci_free_td(uhci, td);
-	}
-
-	if (urbp->setup_packet_dma_handle) {
-		pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle,
-			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-		urbp->setup_packet_dma_handle = 0;
-	}
-
-	if (urbp->transfer_buffer_dma_handle) {
-		pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle,
-			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
-			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-		urbp->transfer_buffer_dma_handle = 0;
-	}
-
-	urb->hcpriv = NULL;
-	kmem_cache_free(uhci_up_cachep, urbp);
-}
-
-static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
-{
-	unsigned long flags;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	if ((!(urb->transfer_flags & USB_NO_FSBR)) && !urbp->fsbr) {
-		urbp->fsbr = 1;
-		if (!uhci->fsbr++ && !uhci->fsbrtimeout)
-			uhci->skel_term_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
-	}
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb)
-{
-	unsigned long flags;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	if ((!(urb->transfer_flags & USB_NO_FSBR)) && urbp->fsbr) {
-		urbp->fsbr = 0;
-		if (!--uhci->fsbr)
-			uhci->fsbrtimeout = jiffies + FSBR_DELAY;
-	}
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-/*
- * 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 0;
-	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 -EOVERFLOW;
-	if (status & TD_CTRL_DBUFERR)			/* Buffer error */
-		return -ENOSR;
-	if (status & TD_CTRL_STALLED)			/* Stalled */
-		return -EPIPE;
-	if (status & TD_CTRL_ACTIVE)			/* Active */
-		return 0;
-
-	return -EINVAL;
-}
-
-/*
- * Control transfers
- */
-static int uhci_submit_control(struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct uhci_td *td;
-	struct uhci_qh *qh;
-	unsigned long destination, status;
-	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-	int len = urb->transfer_buffer_length;
-	dma_addr_t data = urbp->transfer_buffer_dma_handle;
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
-
-	/* 3 errors */
-	status = TD_CTRL_ACTIVE | (3 << 27);
-	if (urb->dev->speed == USB_SPEED_LOW)
-		status |= TD_CTRL_LS;
-
-	/*
-	 * Build the TD for the control request
-	 */
-	td = uhci_alloc_td(uhci, urb->dev);
-	if (!td)
-		return -ENOMEM;
-
-	uhci_add_td_to_urb(urb, td);
-	uhci_fill_td(td, status, destination | (7 << 21),
-		urbp->setup_packet_dma_handle);
-
-	/*
-	 * 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_packetid(urb->pipe));
-
-	if (!(urb->transfer_flags & USB_DISABLE_SPD))
-		status |= TD_CTRL_SPD;
-
-	/*
-	 * Build the DATA TD's
-	 */
-	while (len > 0) {
-		int pktsze = len;
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		/* Alternate Data0/1 (start with Data1) */
-		destination ^= TD_TOKEN_TOGGLE;
-	
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination | ((pktsze - 1) << 21),
-			data);
-
-		data += pktsze;
-		len -= pktsze;
-	}
-
-	/*
-	 * Build the final TD for control status 
-	 */
-	td = uhci_alloc_td(uhci, urb->dev);
-	if (!td)
-		return -ENOMEM;
-
-	/*
-	 * It's IN if the pipe is an output pipe or we're not expecting
-	 * data back.
-	 */
-	destination &= ~TD_TOKEN_PID_MASK;
-	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
-		destination |= USB_PID_IN;
-	else
-		destination |= USB_PID_OUT;
-
-	destination |= TD_TOKEN_TOGGLE;		/* End in Data1 */
-
-	status &= ~TD_CTRL_SPD;
-
-	uhci_add_td_to_urb(urb, td);
-	uhci_fill_td(td, status | TD_CTRL_IOC,
-		destination | (UHCI_NULL_DATA_SIZE << 21), 0);
-
-	qh = uhci_alloc_qh(uhci, urb->dev);
-	if (!qh)
-		return -ENOMEM;
-
-	urbp->qh = qh;
-	qh->urbp = urbp;
-
-	/* Low speed or small transfers gets a different queue and treatment */
-	if (urb->dev->speed == USB_SPEED_LOW) {
-		uhci_insert_tds_in_qh(qh, urb, 0);
-		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
-	} else {
-		uhci_insert_tds_in_qh(qh, urb, 1);
-		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
-		uhci_inc_fsbr(uhci, urb);
-	}
-
-	return -EINPROGRESS;
-}
-
-static int usb_control_retrigger_status(struct urb *urb);
-
-static int uhci_result_control(struct urb *urb)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = urb->hcpriv;
-	struct uhci_td *td;
-	unsigned int status;
-	int ret = 0;
-
-	if (list_empty(&urbp->td_list))
-		return -EINVAL;
-
-	head = &urbp->td_list;
-
-	if (urbp->short_control_packet) {
-		tmp = head->prev;
-		goto status_phase;
-	}
-
-	tmp = head->next;
-	td = list_entry(tmp, struct uhci_td, list);
-
-	/* The first TD is the SETUP phase, check the status, but skip */
-	/*  the count */
-	status = uhci_status_bits(td->status);
-	if (status & TD_CTRL_ACTIVE)
-		return -EINPROGRESS;
-
-	if (status)
-		goto td_error;
-
-	urb->actual_length = 0;
-
-	/* The rest of the TD's (but the last) are data */
-	tmp = tmp->next;
-	while (tmp != head && tmp->next != head) {
-		td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		status = uhci_status_bits(td->status);
-		if (status & TD_CTRL_ACTIVE)
-			return -EINPROGRESS;
-
-		urb->actual_length += uhci_actual_length(td->status);
-
-		if (status)
-			goto td_error;
-
-		/* Check to see if we received a short packet */
-		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
-			if (urb->transfer_flags & USB_DISABLE_SPD) {
-				ret = -EREMOTEIO;
-				goto err;
-			}
-
-			if (uhci_packetid(td->info) == USB_PID_IN)
-				return usb_control_retrigger_status(urb);
-			else
-				return 0;
-		}
-	}
-
-status_phase:
-	td = list_entry(tmp, struct uhci_td, list);
-
-	/* Control status phase */
-	status = uhci_status_bits(td->status);
-
-#ifdef I_HAVE_BUGGY_APC_BACKUPS
-	/* APC BackUPS Pro kludge */
-	/* It tries to send all of the descriptor instead of the amount */
-	/*  we requested */
-	if (td->status & TD_CTRL_IOC &&	/* IOC is masked out by uhci_status_bits */
-	    status & TD_CTRL_ACTIVE &&
-	    status & TD_CTRL_NAK)
-		return 0;
-#endif
-
-	if (status & TD_CTRL_ACTIVE)
-		return -EINPROGRESS;
-
-	if (status)
-		goto td_error;
-
-	return 0;
-
-td_error:
-	ret = uhci_map_status(status, uhci_packetout(td->info));
-	if (ret == -EPIPE)
-		/* endpoint has stalled - mark it halted */
-		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
-	    			uhci_packetout(td->info));
-
-err:
-	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
-		/* Some debugging code */
-		dbg("uhci_result_control() failed with status %x", status);
-
-		if (errbuf) {
-			/* Print the chain for debugging purposes */
-			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
-			lprintk(errbuf);
-		}
-	}
-
-	return ret;
-}
-
-static int usb_control_retrigger_status(struct urb *urb)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci *uhci = urb->dev->bus->hcpriv;
-
-	urbp->short_control_packet = 1;
-
-	/* Create a new QH to avoid pointer overwriting problems */
-	uhci_remove_qh(uhci, urbp->qh);
-
-	/* Delete all of the TD's except for the status TD at the end */
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head && tmp->next != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		uhci_remove_td_from_urb(td);
-		uhci_remove_td(uhci, td);
-		uhci_free_td(uhci, td);
-	}
-
-	urbp->qh = uhci_alloc_qh(uhci, urb->dev);
-	if (!urbp->qh) {
-		err("unable to allocate new QH for control retrigger");
-		return -ENOMEM;
-	}
-
-	urbp->qh->urbp = urbp;
-
-	/* One TD, who cares about Breadth first? */
-	uhci_insert_tds_in_qh(urbp->qh, urb, 0);
-
-	/* Low speed or small transfers gets a different queue and treatment */
-	if (urb->dev->speed == USB_SPEED_LOW)
-		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
-	else
-		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
-
-	return -EINPROGRESS;
-}
-
-/*
- * Interrupt transfers
- */
-static int uhci_submit_interrupt(struct urb *urb)
-{
-	struct uhci_td *td;
-	unsigned long destination, status;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))
-		return -EINVAL;
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-	status = TD_CTRL_ACTIVE | TD_CTRL_IOC;
-	if (urb->dev->speed == USB_SPEED_LOW)
-		status |= TD_CTRL_LS;
-
-	td = uhci_alloc_td(uhci, urb->dev);
-	if (!td)
-		return -ENOMEM;
-
-	destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
-	destination |= ((urb->transfer_buffer_length - 1) << 21);
-
-	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-
-	uhci_add_td_to_urb(urb, td);
-	uhci_fill_td(td, status, destination, urbp->transfer_buffer_dma_handle);
-
-	uhci_insert_td(uhci, uhci->skeltd[__interval_to_skel(urb->interval)], td);
-
-	return -EINPROGRESS;
-}
-
-static int uhci_result_interrupt(struct urb *urb)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = urb->hcpriv;
-	struct uhci_td *td;
-	unsigned int status;
-	int ret = 0;
-
-	urb->actual_length = 0;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		status = uhci_status_bits(td->status);
-		if (status & TD_CTRL_ACTIVE)
-			return -EINPROGRESS;
-
-		urb->actual_length += uhci_actual_length(td->status);
-
-		if (status)
-			goto td_error;
-
-		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
-			if (urb->transfer_flags & USB_DISABLE_SPD) {
-				ret = -EREMOTEIO;
-				goto err;
-			} else
-				return 0;
-		}
-	}
-
-	return 0;
-
-td_error:
-	ret = uhci_map_status(status, uhci_packetout(td->info));
-	if (ret == -EPIPE)
-		/* endpoint has stalled - mark it halted */
-		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
-	    			uhci_packetout(td->info));
-
-err:
-	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
-		/* Some debugging code */
-		dbg("uhci_result_interrupt/bulk() failed with status %x",
-			status);
-
-		if (errbuf) {
-			/* Print the chain for debugging purposes */
-			if (urbp->qh)
-				uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-			else
-				uhci_show_td(td, errbuf, ERRBUF_LEN, 0);
-
-			lprintk(errbuf);
-		}
-	}
-
-	return ret;
-}
-
-static void uhci_reset_interrupt(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td;
-	unsigned long flags;
-
-	spin_lock_irqsave(&urb->lock, flags);
-
-	/* Root hub is special */
-	if (urb->dev == uhci->rh.dev)
-		goto out;
-
-	td = list_entry(urbp->td_list.next, struct uhci_td, list);
-
-	td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
-	td->info &= ~TD_TOKEN_TOGGLE;
-	td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
-	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-
-out:
-	urb->status = -EINPROGRESS;
-
-	spin_unlock_irqrestore(&urb->lock, flags);
-}
-
-/*
- * Bulk transfers
- */
-static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
-{
-	struct uhci_td *td;
-	struct uhci_qh *qh;
-	unsigned long destination, status;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-	int len = urb->transfer_buffer_length;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	dma_addr_t data = urbp->transfer_buffer_dma_handle;
-
-	if (len < 0)
-		return -EINVAL;
-
-	/* Can't have low speed bulk transfers */
-	if (urb->dev->speed == USB_SPEED_LOW)
-		return -EINVAL;
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-	/* 3 errors */
-	status = TD_CTRL_ACTIVE | (3 << TD_CTRL_C_ERR_SHIFT);
-
-	if (!(urb->transfer_flags & USB_DISABLE_SPD))
-		status |= TD_CTRL_SPD;
-
-	/*
-	 * Build the DATA TD's
-	 */
-	do {	/* Allow zero length packets */
-		int pktsze = len;
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination |
-			(((pktsze - 1) & UHCI_NULL_DATA_SIZE) << 21) |
-			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
-			data);
-
-		data += pktsze;
-		len -= maxsze;
-
-		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			usb_pipeout(urb->pipe));
-	} while (len > 0);
-
-	/*
-	 * USB_ZERO_PACKET means adding a 0-length packet, if
-	 * direction is OUT and the transfer_length was an
-	 * exact multiple of maxsze, hence
-	 * (len = transfer_length - N * maxsze) == 0
-	 * however, if transfer_length == 0, the zero packet
-	 * was already prepared above.
-	 */
-	if (usb_pipeout(urb->pipe) && (urb->transfer_flags & USB_ZERO_PACKET) &&
-	   !len && urb->transfer_buffer_length) {
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination |
-			(UHCI_NULL_DATA_SIZE << 21) |
-			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
-			data);
-
-		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			usb_pipeout(urb->pipe));
-	}
-
-	/* Set the flag on the last packet */
-	td->status |= TD_CTRL_IOC;
-
-	qh = uhci_alloc_qh(uhci, urb->dev);
-	if (!qh)
-		return -ENOMEM;
-
-	urbp->qh = qh;
-	qh->urbp = urbp;
-
-	/* Always assume breadth first */
-	uhci_insert_tds_in_qh(qh, urb, 1);
-
-	if (urb->transfer_flags & USB_QUEUE_BULK && eurb)
-		uhci_append_queued_urb(uhci, eurb, urb);
-	else
-		uhci_insert_qh(uhci, uhci->skel_bulk_qh, urb);
-
-	uhci_inc_fsbr(uhci, urb);
-
-	return -EINPROGRESS;
-}
-
-/* We can use the result interrupt since they're identical */
-#define uhci_result_bulk uhci_result_interrupt
-
-/*
- * Isochronous transfers
- */
-static int isochronous_find_limits(struct urb *urb, unsigned int *start, unsigned int *end)
-{
-	struct urb *last_urb = NULL;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct list_head *tmp, *head;
-	int ret = 0;
-
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		/* look for pending URB's with identical pipe handle */
-		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
-		    (u->status == -EINPROGRESS) && (u != urb)) {
-			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;
-	} else
-		ret = -1;	/* no previous urb found */
-
-	return ret;
-}
-
-static int isochronous_find_start(struct urb *urb)
-{
-	int limits;
-	unsigned int start = 0, end = 0;
-
-	if (urb->number_of_packets > 900)	/* 900? Why? */
-		return -EFBIG;
-
-	limits = isochronous_find_limits(urb, &start, &end);
-
-	if (urb->transfer_flags & USB_ISO_ASAP) {
-		if (limits) {
-			int curframe;
-
-			curframe = uhci_get_current_frame_number(urb->dev) % UHCI_NUMFRAMES;
-			urb->start_frame = (curframe + 10) % UHCI_NUMFRAMES;
-		} else
-			urb->start_frame = end;
-	} else {
-		urb->start_frame %= UHCI_NUMFRAMES;
-		/* FIXME: Sanity check */
-	}
-
-	return 0;
-}
-
-/*
- * Isochronous transfers
- */
-static int uhci_submit_isochronous(struct urb *urb)
-{
-	struct uhci_td *td;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	int i, ret, framenum;
-	int status, destination;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-	ret = isochronous_find_start(urb);
-	if (ret)
-		return ret;
-
-	framenum = urb->start_frame;
-	for (i = 0; i < urb->number_of_packets; i++, framenum++) {
-		if (!urb->iso_frame_desc[i].length)
-			continue;
-
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination | ((urb->iso_frame_desc[i].length - 1) << 21),
-			urbp->transfer_buffer_dma_handle + urb->iso_frame_desc[i].offset);
-
-		if (i + 1 >= urb->number_of_packets)
-			td->status |= TD_CTRL_IOC;
-
-		uhci_insert_td_frame_list(uhci, td, framenum);
-	}
-
-	return -EINPROGRESS;
-}
-
-static int uhci_result_isochronous(struct urb *urb)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	int status;
-	int i, ret = 0;
-
-	urb->actual_length = 0;
-
-	i = 0;
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-		int actlength;
-
-		tmp = tmp->next;
-
-		if (td->status & TD_CTRL_ACTIVE)
-			return -EINPROGRESS;
-
-		actlength = uhci_actual_length(td->status);
-		urb->iso_frame_desc[i].actual_length = actlength;
-		urb->actual_length += actlength;
-
-		status = uhci_map_status(uhci_status_bits(td->status), usb_pipeout(urb->pipe));
-		urb->iso_frame_desc[i].status = status;
-		if (status) {
-			urb->error_count++;
-			ret = status;
-		}
-
-		i++;
-	}
-
-	return ret;
-}
-
-/*
- * MUST be called with uhci->urb_list_lock acquired
- */
-static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb)
-{
-	struct list_head *tmp, *head;
-
-	/* We don't match Isoc transfers since they are special */
-	if (usb_pipeisoc(urb->pipe))
-		return NULL;
-
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		if (u->dev == urb->dev && u->pipe == urb->pipe &&
-		    u->status == -EINPROGRESS)
-			return u;
-	}
-
-	return NULL;
-}
-
-static int uhci_submit_urb(struct urb *urb, int mem_flags)
-{
-	int ret = -EINVAL;
-	struct uhci *uhci;
-	unsigned long flags;
-	struct urb *eurb;
-	int bustime;
-
-	if (!urb)
-		return -EINVAL;
-
-	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) {
-		warn("uhci_submit_urb: urb %p belongs to disconnected device or bus?", urb);
-		return -ENODEV;
-	}
-
-	/* increment the reference count of the urb, as we now also control it */
-	urb = usb_get_urb(urb);
-
-	uhci = (struct uhci *)urb->dev->bus->hcpriv;
-
-	INIT_LIST_HEAD(&urb->urb_list);
-	usb_get_dev(urb->dev);
-
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-	spin_lock(&urb->lock);
-
-	if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET ||
-	    urb->status == -ECONNABORTED) {
-		dbg("uhci_submit_urb: urb not available to submit (status = %d)", urb->status);
-		/* Since we can have problems on the out path */
-		spin_unlock(&urb->lock);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-		usb_put_dev(urb->dev);
-		usb_put_urb(urb);
-
-		return ret;
-	}
-
-	if (!uhci_alloc_urb_priv(uhci, urb)) {
-		ret = -ENOMEM;
-
-		goto out;
-	}
-
-	eurb = uhci_find_urb_ep(uhci, urb);
-	if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) {
-		ret = -ENXIO;
-
-		goto out;
-	}
-
-	/* Short circuit the virtual root hub */
-	if (urb->dev == uhci->rh.dev) {
-		ret = rh_submit_urb(urb);
-
-		goto out;
-	}
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-		ret = uhci_submit_control(urb);
-		break;
-	case PIPE_INTERRUPT:
-		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0)
-				ret = bustime;
-			else {
-				ret = uhci_submit_interrupt(urb);
-				if (ret == -EINPROGRESS)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-			}
-		} else		/* bandwidth is already set */
-			ret = uhci_submit_interrupt(urb);
-		break;
-	case PIPE_BULK:
-		ret = uhci_submit_bulk(urb, eurb);
-		break;
-	case PIPE_ISOCHRONOUS:
-		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
-			if (urb->number_of_packets <= 0) {
-				ret = -EINVAL;
-				break;
-			}
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0) {
-				ret = bustime;
-				break;
-			}
-
-			ret = uhci_submit_isochronous(urb);
-			if (ret == -EINPROGRESS)
-				usb_claim_bandwidth(urb->dev, urb, bustime, 1);
-		} else		/* bandwidth is already set */
-			ret = uhci_submit_isochronous(urb);
-		break;
-	}
-
-out:
-	urb->status = ret;
-
-	if (ret == -EINPROGRESS) {
-		/* We use _tail to make find_urb_ep more efficient */
-		list_add_tail(&urb->urb_list, &uhci->urb_list);
-
-		spin_unlock(&urb->lock);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-		return 0;
-	}
-
-	uhci_unlink_generic(uhci, urb);
-
-	spin_unlock(&urb->lock);
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-	/* Only call completion if it was successful */
-	if (!ret)
-		uhci_call_completion(urb);
-
-	return ret;
-}
-
-/*
- * Return the result of a transfer
- *
- * MUST be called with urb_list_lock acquired
- */
-static void uhci_transfer_result(struct uhci *uhci, struct urb *urb)
-{
-	int ret = -EINVAL;
-	unsigned long flags;
-	struct urb_priv *urbp;
-
-	/* The root hub is special */
-	if (urb->dev == uhci->rh.dev)
-		return;
-
-	spin_lock_irqsave(&urb->lock, flags);
-
-	urbp = (struct urb_priv *)urb->hcpriv;
-
-	if (urb->status != -EINPROGRESS) {
-		info("uhci_transfer_result: called for URB %p not in flight?", urb);
-		goto out;
-	}
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-		ret = uhci_result_control(urb);
-		break;
-	case PIPE_INTERRUPT:
-		ret = uhci_result_interrupt(urb);
-		break;
-	case PIPE_BULK:
-		ret = uhci_result_bulk(urb);
-		break;
-	case PIPE_ISOCHRONOUS:
-		ret = uhci_result_isochronous(urb);
-		break;
-	}
-
-	urbp->status = ret;
-
-	if (ret == -EINPROGRESS)
-		goto out;
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
-	case PIPE_ISOCHRONOUS:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		/* Spinlock needed ? */
-		if (urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 1);
-		uhci_unlink_generic(uhci, urb);
-		break;
-	case PIPE_INTERRUPT:
-		/* Interrupts are an exception */
-		if (urb->interval)
-			goto out_complete;
-
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		/* Spinlock needed ? */
-		if (urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 0);
-		uhci_unlink_generic(uhci, urb);
-		break;
-	default:
-		info("uhci_transfer_result: unknown pipe type %d for urb %p\n",
-			usb_pipetype(urb->pipe), urb);
-	}
-
-	/* Remove it from uhci->urb_list */
-	list_del_init(&urb->urb_list);
-
-out_complete:
-	uhci_add_complete(urb);
-
-out:
-	spin_unlock_irqrestore(&urb->lock, flags);
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
-{
-	struct list_head *head, *tmp;
-	struct urb_priv *urbp = urb->hcpriv;
-	int prevactive = 1;
-
-	/* We can get called when urbp allocation fails, so check */
-	if (!urbp)
-		return;
-
-	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
-
-	/*
-	 * Now we need to find out what the last successful toggle was
-	 * so we can update the local data toggle for the next transfer
-	 *
-	 * There's 3 way's the last successful completed TD is found:
-	 *
-	 * 1) The TD is NOT active and the actual length < expected length
-	 * 2) The TD is NOT active and it's the last TD in the chain
-	 * 3) The TD is active and the previous TD is NOT active
-	 *
-	 * Control and Isochronous ignore the toggle, so this is safe
-	 * for all types
-	 */
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		if (!(td->status & TD_CTRL_ACTIVE) &&
-		    (uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
-		    tmp == head))
-			usb_settoggle(urb->dev, uhci_endpoint(td->info),
-				uhci_packetout(td->info),
-				uhci_toggle(td->info) ^ 1);
-		else if ((td->status & TD_CTRL_ACTIVE) && !prevactive)
-			usb_settoggle(urb->dev, uhci_endpoint(td->info),
-				uhci_packetout(td->info),
-				uhci_toggle(td->info));
-
-		prevactive = td->status & TD_CTRL_ACTIVE;
-	}
-
-	uhci_delete_queued_urb(uhci, urb);
-
-	/* The interrupt loop will reclaim the QH's */
-	uhci_remove_qh(uhci, urbp->qh);
-	urbp->qh = NULL;
-}
-
-static int uhci_unlink_urb(struct urb *urb)
-{
-	struct uhci *uhci;
-	unsigned long flags;
-	struct urb_priv *urbp = urb->hcpriv;
-
-	if (!urb)
-		return -EINVAL;
-
-	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
-		return -ENODEV;
-
-	uhci = (struct uhci *)urb->dev->bus->hcpriv;
-
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-	spin_lock(&urb->lock);
-
-	/* Release bandwidth for Interrupt or Isoc. transfers */
-	/* Spinlock needed ? */
-	if (urb->bandwidth) {
-		switch (usb_pipetype(urb->pipe)) {
-		case PIPE_INTERRUPT:
-			usb_release_bandwidth(urb->dev, urb, 0);
-			break;
-		case PIPE_ISOCHRONOUS:
-			usb_release_bandwidth(urb->dev, urb, 1);
-			break;
-		default:
-			break;
-		}
-	}
-
-	if (urb->status != -EINPROGRESS) {
-		spin_unlock(&urb->lock);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-		return 0;
-	}
-
-	list_del_init(&urb->urb_list);
-
-	uhci_unlink_generic(uhci, urb);
-
-	/* Short circuit the virtual root hub */
-	if (urb->dev == uhci->rh.dev) {
-		rh_unlink_urb(urb);
-
-		spin_unlock(&urb->lock);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-		uhci_call_completion(urb);
-	} else {
-		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-			urbp->status = urb->status = -ECONNABORTED;
-
-			spin_lock(&uhci->urb_remove_list_lock);
-
-			/* If we're the first, set the next interrupt bit */
-			if (list_empty(&uhci->urb_remove_list))
-				uhci_set_next_interrupt(uhci);
-			
-			list_add(&urb->urb_list, &uhci->urb_remove_list);
-
-			spin_unlock(&uhci->urb_remove_list_lock);
-
-			spin_unlock(&urb->lock);
-			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-		} else {
-			urb->status = -ENOENT;
-
-			spin_unlock(&urb->lock);
-			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-			if (in_interrupt()) {	/* wait at least 1 frame */
-				static int errorcount = 10;
-
-				if (errorcount--)
-					dbg("uhci_unlink_urb called from interrupt for urb %p", urb);
-				udelay(1000);
-			} else
-				schedule_timeout(1+1*HZ/1000); 
-
-			uhci_call_completion(urb);
-		}
-	}
-
-	return 0;
-}
-
-static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct list_head *head, *tmp;
-	int count = 0;
-
-	uhci_dec_fsbr(uhci, urb);
-
-	urbp->fsbr_timeout = 1;
-
-	/*
-	 * Ideally we would want to fix qh->element as well, but it's
-	 * read/write by the HC, so that can introduce a race. It's not
-	 * really worth the hassle
-	 */
-
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		/*
-		 * Make sure we don't do the last one (since it'll have the
-		 * TERM bit set) as well as we skip every so many TD's to
-		 * make sure it doesn't hog the bandwidth
-		 */
-		if (tmp != head && (count % DEPTH_INTERVAL) == (DEPTH_INTERVAL - 1))
-			td->link |= UHCI_PTR_DEPTH;
-
-		count++;
-	}
-
-	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 *dev)
-{
-	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
-
-	return inw(uhci->io_addr + USBFRNUM);
-}
-
-struct usb_operations uhci_device_operations = {
-	get_frame_number:	uhci_get_current_frame_number,
-	submit_urb:		uhci_submit_urb,
-	unlink_urb:		uhci_unlink_urb,
-};
-
-/* 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; */
-	0x02,			/*  __u8  iProduct; */
-	0x01,			/*  __u8  iSerialNumber; */
-	0x01			/*  __u8  bNumConfigurations; */
-};
-
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
-	0x09,			/*  __u8  bLength; */
-	0x02,			/*  __u8  bDescriptorType; Configuration */
-	0x19,			/*  __u16 wTotalLength; */
-	0x00,
-	0x01,			/*  __u8  bNumInterfaces; */
-	0x01,			/*  __u8  bConfigurationValue; */
-	0x00,			/*  __u8  iConfiguration; */
-	0x40,			/*  __u8  bmAttributes;
-					Bit 7: Bus-powered, 6: Self-powered,
-					Bit 5 Remote-wakeup, 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(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	unsigned int io_addr = uhci->io_addr;
-	unsigned long flags;
-	int i, len = 1;
-	__u16 data = 0;
-
-	spin_lock_irqsave(&urb->lock, flags);
-	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 *) urb->transfer_buffer = cpu_to_le16(data);
-	urb->actual_length = len;
-	urbp->status = 0;
-
-	spin_unlock_irqrestore(&urb->lock, flags);
-
-	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);
-		uhci_call_completion(urb);
-	}
-
-	return 0;
-}
-
-/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
-static int rh_init_int_timer(struct urb *urb);
-
-static void rh_int_timer_do(unsigned long ptr)
-{
-	struct urb *urb = (struct urb *)ptr;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct list_head list, *tmp, *head;
-	unsigned long flags;
-
-	if (uhci->rh.send)
-		rh_send_irq(urb);
-
-	INIT_LIST_HEAD(&list);
-
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
-		struct urb_priv *up = (struct urb_priv *)u->hcpriv;
-
-		tmp = tmp->next;
-
-		spin_lock(&u->lock);
-
-		/* Check if the FSBR timed out */
-		if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
-			uhci_fsbr_timeout(uhci, u);
-
-		/* Check if the URB timed out */
-		if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout))
-			list_move_tail(&u->urb_list, &list);
-
-		spin_unlock(&u->lock);
-	}
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-	head = &list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
-		uhci_unlink_urb(u);
-	}
-
-	/* Really disable FSBR */
-	if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
-		uhci->fsbrtimeout = 0;
-		uhci->skel_term_qh->link = UHCI_PTR_TERM;
-	}
-
-	/* enter global suspend if nothing connected */
-	if (!uhci->is_suspended && !ports_active(uhci))
-		suspend_hc(uhci);
-
-	rh_init_int_timer(urb);
-}
-
-/* Root Hub INTs are polled by this timer */
-static int rh_init_int_timer(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-
-	uhci->rh.interval = urb->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)urb;
-	uhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->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(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	unsigned int pipe = urb->pipe;
-	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet;
-	void *data = urb->transfer_buffer;
-	int leni = urb->transfer_buffer_length;
-	int len = 0;
-	int status = 0;
-	int stat = 0;
-	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) {
-		uhci->rh.urb = urb;
-		uhci->rh.send = 1;
-		uhci->rh.interval = urb->interval;
-		rh_init_int_timer(urb);
-
-		return -EINPROGRESS;
-	}
-
-	bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
-	wValue = le16_to_cpu(cmd->wValue);
-	wIndex = le16_to_cpu(cmd->wIndex);
-	wLength = le16_to_cpu(cmd->wLength);
-
-	for (i = 0; i < 8; i++)
-		uhci->rh.c_p_r[i] = 0;
-
-	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);
-			mdelay(50);	/* USB v1.1 7.1.7.3 */
-			uhci->rh.c_p_r[wIndex - 1] = 1;
-			CLR_RH_PORTSTAT(USBPORTSC_PR);
-			udelay(10);
-			SET_RH_PORTSTAT(USBPORTSC_PE);
-			mdelay(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_t(unsigned int, leni,
-				  min_t(unsigned int,
-				      sizeof(root_hub_dev_des), wLength));
-			memcpy(data, root_hub_dev_des, len);
-			OK(len);
-		case 0x02:	/* configuration descriptor */
-			len = min_t(unsigned int, leni,
-				  min_t(unsigned int,
-				      sizeof(root_hub_config_des), wLength));
-			memcpy (data, root_hub_config_des, len);
-			OK(len);
-		case 0x03:	/* string descriptors */
-			len = usb_root_hub_string (wValue & 0xff,
-				uhci->io_addr, "UHCI-alt",
-				data, wLength);
-			if (len > 0) {
-				OK(min_t(int, leni, len));
-			} else 
-				stat = -EPIPE;
-		}
-		break;
-	case RH_GET_DESCRIPTOR | RH_CLASS:
-		root_hub_hub_des[2] = uhci->rh.numports;
-		len = min_t(unsigned int, leni,
-			  min_t(unsigned int, 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);
-	case RH_GET_INTERFACE | RH_INTERFACE:
-		*(__u8 *)data = 0x00;
-		OK(1);
-	case RH_SET_INTERFACE | RH_INTERFACE:
-		OK(0);
-	default:
-		stat = -EPIPE;
-	}
-
-	urb->actual_length = len;
-
-	return stat;
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static int rh_unlink_urb(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-
-	if (uhci->rh.urb == urb) {
-		urb->status = -ENOENT;
-		uhci->rh.send = 0;
-		uhci->rh.urb = NULL;
-		del_timer(&uhci->rh.rh_int_timer);
-	}
-	return 0;
-}
-
-static void uhci_free_pending_qhs(struct uhci *uhci)
-{
-	struct list_head *tmp, *head;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
-	head = &uhci->qh_remove_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list);
-
-		tmp = tmp->next;
-
-		list_del_init(&qh->remove_list);
-
-		uhci_free_qh(uhci, qh);
-	}
-	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
-}
-
-static void uhci_call_completion(struct urb *urb)
-{
-	struct urb_priv *urbp;
-	struct usb_device *dev = urb->dev;
-	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
-	int killed, resubmit_interrupt, status;
-	unsigned long flags;
-
-	spin_lock_irqsave(&urb->lock, flags);
-
-	urbp = (struct urb_priv *)urb->hcpriv;
-	if (!urbp || !urb->dev) {
-		spin_unlock_irqrestore(&urb->lock, flags);
-		return;
-	}
-
-	killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED ||
-			urb->status == -ECONNRESET);
-	resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&
-			urb->interval);
-
-	if (urbp->transfer_buffer_dma_handle)
-		pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle,
-			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
-			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-
-	if (urbp->setup_packet_dma_handle)
-		pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle,
-			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-
-	status = urbp->status;
-	if (!resubmit_interrupt || killed)
-		/* We don't need urb_priv anymore */
-		uhci_destroy_urb_priv(urb);
-
-	if (!killed)
-		urb->status = status;
-
-	urb->dev = NULL;
-	spin_unlock_irqrestore(&urb->lock, flags);
-
-	if (urb->complete)
-		urb->complete(urb);
-
-	if (resubmit_interrupt)
-		/* Recheck the status. The completion handler may have */
-		/*  unlinked the resubmitting interrupt URB */
-		killed = (urb->status == -ENOENT ||
-			  urb->status == -ECONNABORTED ||
-			  urb->status == -ECONNRESET);
-
-	if (resubmit_interrupt && !killed) {
-		urb->dev = dev;
-		uhci_reset_interrupt(urb);
-	} else {
-		/* We decrement the usage count after we're done */
-		/*  with everything */
-		usb_put_dev(dev);
-		usb_put_urb(urb);
-	}
-}
-
-static void uhci_finish_completion(struct uhci *uhci)
-{
-	struct list_head *tmp, *head;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->complete_list_lock, flags);
-	head = &uhci->complete_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);
-		struct urb *urb = urbp->urb;
-
-		list_del_init(&urbp->complete_list);
-		spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
-
-		uhci_call_completion(urb);
-
-		spin_lock_irqsave(&uhci->complete_list_lock, flags);
-		head = &uhci->complete_list;
-		tmp = head->next;
-	}
-	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
-}
-
-static void uhci_remove_pending_qhs(struct uhci *uhci)
-{
-	struct list_head *tmp, *head;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->urb_remove_list_lock, flags);
-	head = &uhci->urb_remove_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *urb = list_entry(tmp, struct urb, urb_list);
-		struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-		tmp = tmp->next;
-
-		list_del_init(&urb->urb_list);
-
-		urbp->status = urb->status = -ECONNRESET;
-
-		uhci_add_complete(urb);
-	}
-	spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);
-}
-
-static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
-{
-	struct uhci *uhci = __uhci;
-	unsigned int io_addr = uhci->io_addr;
-	unsigned short status;
-	struct list_head *tmp, *head;
-
-	/*
-	 * 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;
-	outw(status, io_addr + USBSTS);		/* Clear it */
-
-	if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
-		if (status & USBSTS_HSE)
-			err("%x: host system error, PCI problems?", io_addr);
-		if (status & USBSTS_HCPE)
-			err("%x: host controller process error. something bad happened", io_addr);
-		if ((status & USBSTS_HCH) && !uhci->is_suspended) {
-			err("%x: host controller halted. very bad", io_addr);
-			/* FIXME: Reset the controller, fix the offending TD */
-		}
-	}
-
-	if (status & USBSTS_RD)
-		wakeup_hc(uhci);
-
-	uhci_free_pending_qhs(uhci);
-
-	uhci_remove_pending_qhs(uhci);
-
-	uhci_clear_next_interrupt(uhci);
-
-	/* Walk the list of pending URB's to see which ones completed */
-	spin_lock(&uhci->urb_list_lock);
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *urb = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		/* Checks the status and does all of the magic necessary */
-		uhci_transfer_result(uhci, urb);
-	}
-	spin_unlock(&uhci->urb_list_lock);
-
-	uhci_finish_completion(uhci);
-}
-
-static void reset_hc(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-
-	/* Global reset for 50ms */
-	outw(USBCMD_GRESET, io_addr + USBCMD);
-	wait_ms(50);
-	outw(0, io_addr + USBCMD);
-	wait_ms(10);
-}
-
-static void suspend_hc(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-
-	dbg("%x: suspend_hc", io_addr);
-
-	outw(USBCMD_EGSM, io_addr + USBCMD);
-
-	uhci->is_suspended = 1;
-}
-
-static void wakeup_hc(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-	unsigned int status;
-
-	dbg("%x: wakeup_hc", io_addr);
-
-	outw(0, io_addr + USBCMD);
-	
-	/* wait for EOP to be sent */
-	status = inw(io_addr + USBCMD);
-	while (status & USBCMD_FGR)
-		status = inw(io_addr + USBCMD);
-
-	uhci->is_suspended = 0;
-
-	/* Run and mark it configured with a 64-byte max packet */
-	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
-}
-
-static int ports_active(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-	int connection = 0;
-	int i;
-
-	for (i = 0; i < uhci->rh.numports; i++)
-		connection |= (inw(io_addr + USBPORTSC1 + i * 2) & 0x1);
-
-	return connection;
-}
-
-static void start_hc(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->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 "uhci: 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(uhci->fl->dma_handle, io_addr + USBFLBASEADD);
-
-	/* Run and mark it configured with a 64-byte max packet */
-	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
-}
-
-#ifdef CONFIG_PROC_FS
-static int uhci_num = 0;
-#endif
-
-static void free_uhci(struct uhci *uhci)
-{
-	kfree(uhci);
-}
-
-/*
- * De-allocate all resources..
- */
-static void release_uhci(struct uhci *uhci)
-{
-	int i;
-#ifdef CONFIG_PROC_FS
-	char buf[8];
-#endif
-
-	if (uhci->irq >= 0) {
-		free_irq(uhci->irq, uhci);
-		uhci->irq = -1;
-	}
-
-	for (i = 0; i < UHCI_NUM_SKELQH; i++)
-		if (uhci->skelqh[i]) {
-			uhci_free_qh(uhci, uhci->skelqh[i]);
-			uhci->skelqh[i] = NULL;
-		}
-
-	for (i = 0; i < UHCI_NUM_SKELTD; i++)
-		if (uhci->skeltd[i]) {
-			uhci_free_td(uhci, uhci->skeltd[i]);
-			uhci->skeltd[i] = NULL;
-		}
-
-	if (uhci->qh_pool) {
-		pci_pool_destroy(uhci->qh_pool);
-		uhci->qh_pool = NULL;
-	}
-
-	if (uhci->td_pool) {
-		pci_pool_destroy(uhci->td_pool);
-		uhci->td_pool = NULL;
-	}
-
-	if (uhci->fl) {
-		pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
-		uhci->fl = NULL;
-	}
-
-	if (uhci->bus) {
-		usb_free_bus(uhci->bus);
-		uhci->bus = NULL;
-	}
-
-#ifdef CONFIG_PROC_FS
-	if (uhci->proc_entry) {
-		sprintf(buf, "hc%d", uhci->num);
-
-		remove_proc_entry(buf, uhci_proc_root);
-		uhci->proc_entry = NULL;
-	}
-#endif
-
-	free_uhci(uhci);
-}
-
-/*
- * Allocate a frame list, and then setup the skeleton
- *
- * The hardware doesn't really know any difference
- * in the queues, but the order does matter for the
- * protocols higher up. The order is:
- *
- *  - any isochronous events handled before any
- *    of the queues. We don't do that here, because
- *    we'll create the actual TD entries on demand.
- *  - The first queue is the interrupt queue.
- *  - The second queue is the control queue, split into low and high speed
- *  - The third queue is bulk queue.
- *  - The fourth queue is the bandwidth reclamation queue, which loops back
- *    to the high speed control queue.
- */
-static int alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsigned int io_size)
-{
-	struct uhci *uhci;
-	int retval;
-	char buf[8], *bufp = buf;
-	int i, port;
-	struct usb_bus *bus;
-	dma_addr_t dma_handle;
-#ifdef CONFIG_PROC_FS
-	struct proc_dir_entry *ent;
-#endif
-
-	retval = -ENODEV;
-	if (pci_enable_device(dev) < 0) {
-		err("couldn't enable PCI device");
-		goto err_enable_device;
-	}
-
-	if (!dev->irq) {
-		err("found UHCI device with no IRQ assigned. check BIOS settings!");
-		goto err_invalid_irq;
-	}
-
-	if (!pci_dma_supported(dev, 0xFFFFFFFF)) {
-		err("PCI subsystem doesn't support 32 bit addressing?");
-		goto err_pci_dma_supported;
-	}
-
-	retval = -EBUSY;
-	if (!request_region(io_addr, io_size, "usb-uhci")) {
-		err("couldn't allocate I/O range %x - %x", io_addr,
-			io_addr + io_size - 1);
-		goto err_request_region;
-	}
-
-	pci_set_master(dev);
-
-#ifndef __sparc__
-	sprintf(buf, "%d", dev->irq);
-#else
-	bufp = __irq_itoa(dev->irq);
-#endif
-	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
-		io_addr, bufp);
-
-	if (pci_set_dma_mask(dev, 0xFFFFFFFF)) {
-		err("couldn't set PCI dma mask");
-		retval = -ENODEV;
-		goto err_pci_set_dma_mask;
-	}
-
-	uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
-	if (!uhci) {
-		err("couldn't allocate uhci structure");
-		retval = -ENOMEM;
-		goto err_alloc_uhci;
-	}
-
-	uhci->dev = dev;
-	uhci->irq = dev->irq;
-	uhci->io_addr = io_addr;
-	uhci->io_size = io_size;
-	pci_set_drvdata(dev, uhci);
-
-#ifdef CONFIG_PROC_FS
-	uhci->num = uhci_num++;
-
-	sprintf(buf, "hc%d", uhci->num);
-
-	ent = create_proc_entry(buf, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root);
-	if (!ent) {
-		err("couldn't create uhci proc entry");
-		retval = -ENOMEM;
-		goto err_create_proc_entry;
-	}
-
-	ent->data = uhci;
-	ent->proc_fops = &uhci_proc_operations;
-	ent->size = 0;
-	uhci->proc_entry = ent;
-#endif
-
-	/* Reset here so we don't get any interrupts from an old setup */
-	/*  or broken setup */
-	reset_hc(uhci);
-
-	uhci->fsbr = 0;
-	uhci->fsbrtimeout = 0;
-
-	uhci->is_suspended = 0;
-
-	spin_lock_init(&uhci->qh_remove_list_lock);
-	INIT_LIST_HEAD(&uhci->qh_remove_list);
-
-	spin_lock_init(&uhci->urb_remove_list_lock);
-	INIT_LIST_HEAD(&uhci->urb_remove_list);
-
-	spin_lock_init(&uhci->urb_list_lock);
-	INIT_LIST_HEAD(&uhci->urb_list);
-
-	spin_lock_init(&uhci->complete_list_lock);
-	INIT_LIST_HEAD(&uhci->complete_list);
-
-	spin_lock_init(&uhci->frame_list_lock);
-
-	/* We need exactly one page (per UHCI specs), how convenient */
-	/* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
-#if PAGE_SIZE < (4 * 1024)
-#error PAGE_SIZE is not atleast 4k
-#endif
-	uhci->fl = pci_alloc_consistent(uhci->dev, sizeof(*uhci->fl), &dma_handle);
-	if (!uhci->fl) {
-		err("unable to allocate consistent memory for frame list");
-		goto err_alloc_fl;
-	}
-
-	memset((void *)uhci->fl, 0, sizeof(*uhci->fl));
-
-	uhci->fl->dma_handle = dma_handle;
-
-	uhci->td_pool = pci_pool_create("uhci_td", uhci->dev,
-		sizeof(struct uhci_td), 16, 0, GFP_DMA | GFP_ATOMIC);
-	if (!uhci->td_pool) {
-		err("unable to create td pci_pool");
-		goto err_create_td_pool;
-	}
-
-	uhci->qh_pool = pci_pool_create("uhci_qh", uhci->dev,
-		sizeof(struct uhci_qh), 16, 0, GFP_DMA | GFP_ATOMIC);
-	if (!uhci->qh_pool) {
-		err("unable to create qh pci_pool");
-		goto err_create_qh_pool;
-	}
-
-	bus = usb_alloc_bus(&uhci_device_operations);
-	if (!bus) {
-		err("unable to allocate bus");
-		goto err_alloc_bus;
-	}
-
-	uhci->bus = bus;
-	bus->hcpriv = uhci;
-	bus->bus_name = dev->slot_name;
-
-	usb_register_bus(uhci->bus);
-
-	/* Initialize the root hub */
-
-	/* 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. However, according to the UHCI spec, Bit 7 is always set */
-	/*  to 1. So we try to use this to our advantage */
-	for (port = 0; port < (uhci->io_size - 0x10) / 2; port++) {
-		unsigned int portstatus;
-
-		portstatus = inw(uhci->io_addr + 0x10 + (port * 2));
-		if (!(portstatus & 0x0080))
-			break;
-	}
-	if (debug)
-		info("detected %d ports", port);
-
-	/* This is experimental so anything less than 2 or greater than 8 is */
-	/*  something weird and we'll ignore it */
-	if (port < 2 || port > 8) {
-		info("port count misdetected? forcing to 2 ports");
-		port = 2;
-	}
-
-	uhci->rh.numports = port;
-
-	uhci->bus->root_hub = uhci->rh.dev = usb_alloc_dev(NULL, uhci->bus);
-	if (!uhci->rh.dev) {
-		err("unable to allocate root hub");
-		goto err_alloc_root_hub;
-	}
-
-	uhci->skeltd[0] = uhci_alloc_td(uhci, uhci->rh.dev);
-	if (!uhci->skeltd[0]) {
-		err("unable to allocate TD 0");
-		goto err_alloc_skeltd;
-	}
-
-	/*
-	 * 9 Interrupt queues; link int2 to int1, int4 to int2, etc
-	 * then link int1 to control and control to bulk
-	 */
-	for (i = 1; i < 9; i++) {
-		struct uhci_td *td;
-
-		td = uhci->skeltd[i] = uhci_alloc_td(uhci, uhci->rh.dev);
-		if (!td) {
-			err("unable to allocate TD %d", i);
-			goto err_alloc_skeltd;
-		}
-
-		uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
-		td->link = uhci->skeltd[i - 1]->dma_handle;
-	}
-
-	uhci->skel_term_td = uhci_alloc_td(uhci, uhci->rh.dev);
-	if (!uhci->skel_term_td) {
-		err("unable to allocate skel TD term");
-		goto err_alloc_skeltd;
-	}
-
-	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
-		uhci->skelqh[i] = uhci_alloc_qh(uhci, uhci->rh.dev);
-		if (!uhci->skelqh[i]) {
-			err("unable to allocate QH %d", i);
-			goto err_alloc_skelqh;
-		}
-	}
-
-	uhci_fill_td(uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
-	uhci->skel_int1_td->link = uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH;
-
-	uhci->skel_ls_control_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
-	uhci->skel_ls_control_qh->element = UHCI_PTR_TERM;
-
-	uhci->skel_hs_control_qh->link = uhci->skel_bulk_qh->dma_handle | UHCI_PTR_QH;
-	uhci->skel_hs_control_qh->element = UHCI_PTR_TERM;
-
-	uhci->skel_bulk_qh->link = uhci->skel_term_qh->dma_handle | UHCI_PTR_QH;
-	uhci->skel_bulk_qh->element = UHCI_PTR_TERM;
-
-	/* This dummy TD is to work around a bug in Intel PIIX controllers */
-	uhci_fill_td(uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
-	uhci->skel_term_td->link = uhci->skel_term_td->dma_handle;
-
-	uhci->skel_term_qh->link = UHCI_PTR_TERM;
-	uhci->skel_term_qh->element = uhci->skel_term_td->dma_handle;
-
-	/*
-	 * Fill the frame list: make all entries point to
-	 * the proper interrupt queue.
-	 *
-	 * This is probably silly, but it's a simple way to
-	 * scatter the interrupt queues in a way that gives
-	 * us a reasonable dynamic range for irq latencies.
-	 */
-	for (i = 0; i < UHCI_NUMFRAMES; i++) {
-		int irq = 0;
-
-		if (i & 1) {
-			irq++;
-			if (i & 2) {
-				irq++;
-				if (i & 4) { 
-					irq++;
-					if (i & 8) { 
-						irq++;
-						if (i & 16) {
-							irq++;
-							if (i & 32) {
-								irq++;
-								if (i & 64)
-									irq++;
-							}
-						}
-					}
-				}
-			}
-		}
-
-		/* Only place we don't use the frame list routines */
-		uhci->fl->frame[i] =  uhci->skeltd[irq]->dma_handle;
-	}
-
-	start_hc(uhci);
-
-	if (request_irq(dev->irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci))
-		goto err_request_irq;
-
-	/* disable legacy emulation */
-	pci_write_config_word(uhci->dev, USBLEGSUP, USBLEGSUP_DEFAULT);
-
-	usb_connect(uhci->rh.dev);
-
-	if (usb_register_root_hub(uhci->rh.dev, &dev->dev) != 0) {
-		err("unable to start root hub");
-		retval = -ENOMEM;
-		goto err_start_root_hub;
-	}
-
-	return 0;
-
-/*
- * error exits:
- */
-err_start_root_hub:
-	free_irq(uhci->irq, uhci);
-	uhci->irq = -1;
-
-err_request_irq:
-	for (i = 0; i < UHCI_NUM_SKELQH; i++)
-		if (uhci->skelqh[i]) {
-			uhci_free_qh(uhci, uhci->skelqh[i]);
-			uhci->skelqh[i] = NULL;
-		}
-
-err_alloc_skelqh:
-	for (i = 0; i < UHCI_NUM_SKELTD; i++)
-		if (uhci->skeltd[i]) {
-			uhci_free_td(uhci, uhci->skeltd[i]);
-			uhci->skeltd[i] = NULL;
-		}
-
-err_alloc_skeltd:
-	usb_free_dev(uhci->rh.dev);
-	uhci->rh.dev = NULL;
-
-err_alloc_root_hub:
-	usb_free_bus(uhci->bus);
-	uhci->bus = NULL;
-
-err_alloc_bus:
-	pci_pool_destroy(uhci->qh_pool);
-	uhci->qh_pool = NULL;
-
-err_create_qh_pool:
-	pci_pool_destroy(uhci->td_pool);
-	uhci->td_pool = NULL;
-
-err_create_td_pool:
-	pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
-	uhci->fl = NULL;
-
-err_alloc_fl:
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry(buf, uhci_proc_root);
-	uhci->proc_entry = NULL;
-
-err_create_proc_entry:
-	free_uhci(uhci);
-#endif
-
-err_alloc_uhci:
-
-err_pci_set_dma_mask:
-	release_region(io_addr, io_size);
-
-err_request_region:
-
-err_pci_dma_supported:
-
-err_invalid_irq:
-
-err_enable_device:
-
-	return retval;
-}
-
-static int __devinit uhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
-	int i;
-
-	/* Search for the IO base address.. */
-	for (i = 0; i < 6; i++) {
-		unsigned int io_addr = pci_resource_start(dev, i);
-		unsigned int io_size = pci_resource_len(dev, i);
-
-		/* IO address? */
-		if (!(pci_resource_flags(dev, i) & IORESOURCE_IO))
-			continue;
-
-		return alloc_uhci(dev, io_addr, io_size);
-	}
-
-	return -ENODEV;
-}
-
-static void __devexit uhci_pci_remove(struct pci_dev *dev)
-{
-	struct uhci *uhci = pci_get_drvdata(dev);
-
-	if (uhci->bus->root_hub)
-		usb_disconnect(&uhci->bus->root_hub);
-
-	usb_deregister_bus(uhci->bus);
-
-	/*
-	 * At this point, we're guaranteed that no new connects can be made
-	 * to this bus since there are no more parents
-	 */
-	uhci_free_pending_qhs(uhci);
-	uhci_remove_pending_qhs(uhci);
-
-	reset_hc(uhci);
-	release_region(uhci->io_addr, uhci->io_size);
-
-	uhci_free_pending_qhs(uhci);
-
-	release_uhci(uhci);
-}
-
-#ifdef CONFIG_PM
-static int uhci_pci_suspend(struct pci_dev *dev, u32 state)
-{
-	suspend_hc((struct uhci *) pci_get_drvdata(dev));
-	return 0;
-}
-
-static int uhci_pci_resume(struct pci_dev *dev)
-{
-	reset_hc((struct uhci *) pci_get_drvdata(dev));
-	start_hc((struct uhci *) pci_get_drvdata(dev));
-	return 0;
-}
-#endif
-
-static const struct pci_device_id __devinitdata uhci_pci_ids[] = { {
-
-	/* handle any USB UHCI controller */
-	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x00),
-	class_mask: 	~0,
-
-	/* no matter who makes it */
-	vendor:		PCI_ANY_ID,
-	device:		PCI_ANY_ID,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
-
-	}, { /* end: all zeroes */ }
-};
-
-MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
-
-static struct pci_driver uhci_pci_driver = {
-	name:		"usb-uhci",
-	id_table:	uhci_pci_ids,
-
-	probe:		uhci_pci_probe,
-	remove:		__devexit_p(uhci_pci_remove),
-
-#ifdef	CONFIG_PM
-	suspend:	uhci_pci_suspend,
-	resume:		uhci_pci_resume,
-#endif	/* PM */
-};
-
- 
-static int __init uhci_hcd_init(void)
-{
-	int retval = -ENOMEM;
-
-	info(DRIVER_DESC " " DRIVER_VERSION);
-
-	if (debug) {
-		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
-		if (!errbuf)
-			goto errbuf_failed;
-	}
-
-#ifdef CONFIG_PROC_FS
-	uhci_proc_root = create_proc_entry("driver/uhci", S_IFDIR, 0);
-	if (!uhci_proc_root)
-		goto proc_failed;
-#endif
-
-	uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
-		sizeof(struct urb_priv), 0, 0, NULL, NULL);
-	if (!uhci_up_cachep)
-		goto up_failed;
-
-	retval = pci_module_init(&uhci_pci_driver);
-	if (retval)
-		goto init_failed;
-
-	return 0;
-
-init_failed:
-	if (kmem_cache_destroy(uhci_up_cachep))
-		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
-
-up_failed:
-
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("uhci", 0);
-
-proc_failed:
-#endif
-	if (errbuf)
-		kfree(errbuf);
-
-errbuf_failed:
-
-	return retval;
-}
-
-static void __exit uhci_hcd_cleanup(void) 
-{
-	pci_unregister_driver(&uhci_pci_driver);
-	
-	if (kmem_cache_destroy(uhci_up_cachep))
-		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
-
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("uhci", 0);
-#endif
-
-	if (errbuf)
-		kfree(errbuf);
-}
-
-module_init(uhci_hcd_init);
-module_exit(uhci_hcd_cleanup);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
diff -Nru a/drivers/usb/host/uhci.h b/drivers/usb/host/uhci.h
--- a/drivers/usb/host/uhci.h	Tue Jul 16 16:49:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,441 +0,0 @@
-#ifndef __LINUX_UHCI_H
-#define __LINUX_UHCI_H
-
-#include <linux/list.h>
-#include <linux/usb.h>
-
-/*
- * Universal Host Controller Interface data structures and defines
- */
-
-/* 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 */
-
-struct uhci_frame_list {
-	__u32 frame[UHCI_NUMFRAMES];
-
-	void *frame_cpu[UHCI_NUMFRAMES];
-
-	dma_addr_t dma_handle;
-};
-
-struct urb_priv;
-
-struct uhci_qh {
-	/* Hardware fields */
-	__u32 link;			/* Next queue */
-	__u32 element;			/* Queue element pointer */
-
-	/* Software fields */
-	dma_addr_t dma_handle;
-
-	struct usb_device *dev;
-	struct urb_priv *urbp;
-
-	struct list_head list;		/* P: uhci->frame_list_lock */
-	struct list_head remove_list;	/* P: uhci->remove_list_lock */
-} __attribute__((aligned(16)));
-
-/*
- * 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_C_ERR_SHIFT	27
-#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 */
-
-/*
- * for TD <info>: (a.k.a. Token)
- */
-#define TD_TOKEN_TOGGLE_SHIFT	19
-#define TD_TOKEN_TOGGLE		(1 << 19)
-#define TD_TOKEN_PID_MASK	0xFF
-#define TD_TOKEN_EXPLEN_MASK	0x7FF		/* expected length, encoded as n - 1 */
-
-#define uhci_maxlen(token)	((token) >> 21)
-#define uhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */
-#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE_SHIFT) & 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) & TD_TOKEN_PID_MASK)
-#define uhci_packetout(token)	(uhci_packetid(token) != USB_PID_IN)
-#define uhci_packetin(token)	(uhci_packetid(token) == USB_PID_IN)
-
-/*
- * The documentation says "4 words for hardware, 4 words for software".
- *
- * That's silly, the hardware doesn't care. The hardware only cares that
- * the hardware words are 16-byte aligned, and we can have any amount of
- * sw space after the TD entry as far as I can tell.
- *
- * But let's just go with the documentation, at least for 32-bit machines.
- * On 64-bit machines we probably want to take advantage of the fact that
- * hw doesn't really care about the size of the sw-only area.
- *
- * Alas, not anymore, we have more than 4 words for software, woops.
- * Everything still works tho, surprise! -jerdfelt
- */
-struct uhci_td {
-	/* Hardware fields */
-	__u32 link;
-	__u32 status;
-	__u32 info;
-	__u32 buffer;
-
-	/* Software fields */
-	dma_addr_t dma_handle;
-
-	struct usb_device *dev;
-	struct urb *urb;
-
-	struct list_head list;		/* P: urb->lock */
-
-	int frame;
-	struct list_head fl_list;	/* P: uhci->frame_list_lock */
-} __attribute__((aligned(16)));
-
-/*
- * There are various standard queues. We set up several different
- * queues for each of the three basic queue types: interrupt,
- * control, and bulk.
- *
- *  - There are various different interrupt latencies: ranging from
- *    every other USB frame (2 ms apart) to every 256 USB frames (ie
- *    256 ms apart). Make your choice according to how obnoxious you
- *    want to be on the wire, vs how critical latency is for you.
- *  - The control list is done every frame.
- *  - There are 4 bulk lists, so that up to four devices can have a
- *    bulk list of their own and when run concurrently all four lists
- *    will be be serviced.
- *
- * This is a bit misleading, there are various interrupt latencies, but they
- * vary a bit, interrupt2 isn't exactly 2ms, it can vary up to 4ms since the
- * other queues can "override" it. interrupt4 can vary up to 8ms, etc. Minor
- * problem
- *
- * In the case of the root hub, these QH's are just head's of qh's. Don't
- * be scared, it kinda makes sense. Look at this wonderful picture care of
- * Linus:
- *
- *  generic-  ->  dev1-  ->  generic-  ->  dev1-  ->  control-  ->  bulk- -> ...
- *   iso-QH      iso-QH       irq-QH      irq-QH        QH           QH
- *      |           |            |           |           |            |
- *     End     dev1-iso-TD1     End     dev1-irq-TD1    ...          ... 
- *                  |
- *             dev1-iso-TD2
- *                  |
- *                ....
- *
- * This may vary a bit (the UHCI docs don't explicitly say you can put iso
- * transfers in QH's and all of their pictures don't have that either) but
- * other than that, that is what we're doing now
- *
- * And now we don't put Iso transfers in QH's, so we don't waste one on it
- * --jerdfelt
- *
- * To keep with Linus' nomenclature, this is called the QH skeleton. These
- * labels (below) are only signficant to the root hub's QH's
- */
-
-#define UHCI_NUM_SKELTD		10
-#define skel_int1_td		skeltd[0]
-#define skel_int2_td		skeltd[1]
-#define skel_int4_td		skeltd[2]
-#define skel_int8_td		skeltd[3]
-#define skel_int16_td		skeltd[4]
-#define skel_int32_td		skeltd[5]
-#define skel_int64_td		skeltd[6]
-#define skel_int128_td		skeltd[7]
-#define skel_int256_td		skeltd[8]
-#define skel_term_td		skeltd[9]	/* To work around PIIX UHCI bug */
-
-#define UHCI_NUM_SKELQH		4
-#define skel_ls_control_qh	skelqh[0]
-#define skel_hs_control_qh	skelqh[1]
-#define skel_bulk_qh		skelqh[2]
-#define skel_term_qh		skelqh[3]
-
-/*
- * Search tree for determining where <interval> fits in the
- * skelqh[] skeleton.
- *
- * An interrupt request should be placed into the slowest skelqh[]
- * which meets the interval/period/frequency requirement.
- * An interrupt request is allowed to be faster than <interval> but not slower.
- *
- * For a given <interval>, this function returns the appropriate/matching
- * skelqh[] index value.
- *
- * NOTE: For UHCI, we don't really need int256_qh since the maximum interval
- * is 255 ms.  However, we do need an int1_qh since 1 is a valid interval
- * and we should meet that frequency when requested to do so.
- * This will require some change(s) to the UHCI skeleton.
- */
-static inline int __interval_to_skel(int interval)
-{
-	if (interval < 16) {
-		if (interval < 4) {
-			if (interval < 2)
-				return 0;	/* int1 for 0-1 ms */
-			return 1;		/* int2 for 2-3 ms */
-		}
-		if (interval < 8)
-			return 2;		/* int4 for 4-7 ms */
-		return 3;			/* int8 for 8-15 ms */
-	}
-	if (interval < 64) {
-		if (interval < 32)
-			return 4;		/* int16 for 16-31 ms */
-		return 5;			/* int32 for 32-63 ms */
-	}
-	if (interval < 128)
-		return 6;			/* int64 for 64-127 ms */
-	return 7;				/* int128 for 128-255 ms (Max.) */
-}
-
-struct virt_root_hub {
-	struct usb_device *dev;
-	int devnum;		/* Address of Root Hub endpoint */
-	struct urb *urb;
-	void *int_addr;
-	int send;
-	int interval;
-	int numports;
-	int c_p_r[8];
-	struct timer_list rh_int_timer;
-};
-
-/*
- * This describes the full uhci information.
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs.
- */
-struct uhci {
-	struct pci_dev *dev;
-
-#ifdef CONFIG_PROC_FS
-	/* procfs */
-	int num;
-	struct proc_dir_entry *proc_entry;
-#endif
-
-	/* Grabbed from PCI */
-	int irq;
-	unsigned int io_addr;
-	unsigned int io_size;
-
-	struct pci_pool *qh_pool;
-	struct pci_pool *td_pool;
-
-	struct usb_bus *bus;
-
-	struct uhci_td *skeltd[UHCI_NUM_SKELTD];	/* Skeleton TD's */
-	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
-
-	spinlock_t frame_list_lock;
-	struct uhci_frame_list *fl;		/* P: uhci->frame_list_lock */
-	int fsbr;				/* Full speed bandwidth reclamation */
-	unsigned long fsbrtimeout;		/* FSBR delay */
-	int is_suspended;
-
-	/* Main list of URB's currently controlled by this HC */
-	spinlock_t urb_list_lock;
-	struct list_head urb_list;		/* P: uhci->urb_list_lock */
-
-	/* List of QH's that are done, but waiting to be unlinked (race) */
-	spinlock_t qh_remove_list_lock;
-	struct list_head qh_remove_list;	/* P: uhci->qh_remove_list_lock */
-
-	/* List of asynchronously unlinked URB's */
-	spinlock_t urb_remove_list_lock;
-	struct list_head urb_remove_list;	/* P: uhci->urb_remove_list_lock */
-
-	/* List of URB's awaiting completion callback */
-	spinlock_t complete_list_lock;
-	struct list_head complete_list;		/* P: uhci->complete_list_lock */
-
-	struct virt_root_hub rh;	/* private data of the virtual root hub */
-};
-
-struct urb_priv {
-	struct urb *urb;
-	struct usb_device *dev;
-
-	dma_addr_t setup_packet_dma_handle;
-	dma_addr_t transfer_buffer_dma_handle;
-
-	struct uhci_qh *qh;		/* QH for this URB */
-	struct list_head td_list;	/* P: urb->lock */
-
-	int fsbr : 1;			/* URB turned on FSBR */
-	int fsbr_timeout : 1;		/* URB timed out on FSBR */
-	int queued : 1;			/* QH was queued (not linked in) */
-	int short_control_packet : 1;	/* If we get a short packet during */
-					/*  a control transfer, retrigger */
-					/*  the status phase */
-
-	int status;			/* Final status */
-
-	unsigned long inserttime;	/* In jiffies */
-	unsigned long fsbrtime;		/* In jiffies */
-
-	struct list_head queue_list;	/* P: uhci->frame_list_lock */
-	struct list_head complete_list;	/* P: uhci->complete_list_lock */
-};
-
-/*
- * Locking in uhci.c
- *
- * spinlocks are used extensively to protect the many lists and data
- * structures we have. It's not that pretty, but it's necessary. We
- * need to be done with all of the locks (except complete_list_lock) when
- * we call urb->complete. I've tried to make it simple enough so I don't
- * have to spend hours racking my brain trying to figure out if the
- * locking is safe.
- *
- * Here's the safe locking order to prevent deadlocks:
- *
- * #1 uhci->urb_list_lock
- * #2 urb->lock
- * #3 uhci->urb_remove_list_lock, uhci->frame_list_lock, 
- *   uhci->qh_remove_list_lock
- * #4 uhci->complete_list_lock
- *
- * If you're going to grab 2 or more locks at once, ALWAYS grab the lock
- * at the lowest level FIRST and NEVER grab locks at the same level at the
- * same time.
- * 
- * So, if you need uhci->urb_list_lock, grab it before you grab urb->lock
- */
-
-/* -------------------------------------------------------------------------
-   Virtual Root HUB
-   ------------------------------------------------------------------------- */
-/* destination of request */
-#define RH_DEVICE		0x00
-#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
-
-#endif
-
diff -Nru a/drivers/usb/host/usb-uhci-dbg.c b/drivers/usb/host/usb-uhci-dbg.c
--- a/drivers/usb/host/usb-uhci-dbg.c	Tue Jul 16 16:49:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,151 +0,0 @@
-/*  
-    UHCI HCD (Host Controller Driver) for USB, debugging calls
-   
-    (c) 1999-2002 
-    Georg Acher      +    Deti Fliegl    +    Thomas Sailer
-    georg@acher.org      deti@fliegl.de   sailer@ife.ee.ethz.ch
-  
-    $Id: usb-uhci-dbg.c,v 1.2 2002/05/21 21:40:16 acher Exp $
-*/
-
-#ifdef DEBUG
-static void __attribute__((__unused__)) uhci_show_qh (puhci_desc_t qh)
-{
-	if (qh->type != QH_TYPE) {
-		dbg("qh has not QH_TYPE");
-		return;
-	}
-	dbg("QH @ %p/%08llX:", qh, (unsigned long long)qh->dma_addr);
-
-	if (qh->hw.qh.head & UHCI_PTR_TERM)
-		dbg("    Head Terminate");
-	else 
-		dbg("    Head: %s @ %08X",
-		    (qh->hw.qh.head & UHCI_PTR_QH?"QH":"TD"),
-		    qh->hw.qh.head & ~UHCI_PTR_BITS);
-
-	if (qh->hw.qh.element & UHCI_PTR_TERM)
-		dbg("    Element Terminate");
-	else 
-		dbg("    Element: %s @ %08X",
-		    (qh->hw.qh.element & UHCI_PTR_QH?"QH":"TD"),
-		    qh->hw.qh.element & ~UHCI_PTR_BITS);
-}
-#endif
-
-#if 0
-static 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;
-	}
-
-	warn("  TD @ %p/%08X, MaxLen=%02x DT%d EP=%x Dev=%x PID=(%s) buf=%08x",
-	     td, td->dma_addr,
-	     td->hw.td.info >> 21,
-	     ((td->hw.td.info >> 19) & 1),
-	     (td->hw.td.info >> 15) & 15,
-	     (td->hw.td.info >> 8) & 127,
-	     spid,
-	     td->hw.td.buffer);
-
-	warn("    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)
-		warn("   TD Link Terminate");
-	else 
-		warn("    Link points to %s @ %08x, %s",
-		     (td->hw.td.link & UHCI_PTR_QH?"QH":"TD"),
-		     td->hw.td.link & ~UHCI_PTR_BITS,
-		     (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : "Breadth first"));
-}
-#endif
-
-#ifdef DEBUG
-static void __attribute__((__unused__)) 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 (struct uhci_hcd *uhci)
-{
-	unsigned long io_addr = (unsigned long)uhci->hcd.regs;
-	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);
-}
-#endif
diff -Nru a/drivers/usb/host/usb-uhci-debug.h b/drivers/usb/host/usb-uhci-debug.h
--- a/drivers/usb/host/usb-uhci-debug.h	Tue Jul 16 16:49:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,141 +0,0 @@
-#ifdef DEBUG
-static void __attribute__((__unused__)) uhci_show_qh (puhci_desc_t qh)
-{
-	if (qh->type != QH_TYPE) {
-		dbg("qh has not QH_TYPE");
-		return;
-	}
-	dbg("QH @ %p/%08llX:", qh, (unsigned long long)qh->dma_addr);
-
-	if (qh->hw.qh.head & UHCI_PTR_TERM)
-		dbg("    Head Terminate");
-	else 
-		dbg("    Head: %s @ %08X",
-		    (qh->hw.qh.head & UHCI_PTR_QH?"QH":"TD"),
-		    qh->hw.qh.head & ~UHCI_PTR_BITS);
-
-	if (qh->hw.qh.element & UHCI_PTR_TERM)
-		dbg("    Element Terminate");
-	else 
-		dbg("    Element: %s @ %08X",
-		    (qh->hw.qh.element & UHCI_PTR_QH?"QH":"TD"),
-		    qh->hw.qh.element & ~UHCI_PTR_BITS);
-}
-#endif
-
-#if 0
-static 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;
-	}
-
-	warn("  TD @ %p/%08X, MaxLen=%02x DT%d EP=%x Dev=%x PID=(%s) buf=%08x",
-	     td, td->dma_addr,
-	     td->hw.td.info >> 21,
-	     ((td->hw.td.info >> 19) & 1),
-	     (td->hw.td.info >> 15) & 15,
-	     (td->hw.td.info >> 8) & 127,
-	     spid,
-	     td->hw.td.buffer);
-
-	warn("    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)
-		warn("   TD Link Terminate");
-	else 
-		warn("    Link points to %s @ %08x, %s",
-		     (td->hw.td.link & UHCI_PTR_QH?"QH":"TD"),
-		     td->hw.td.link & ~UHCI_PTR_BITS,
-		     (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : "Breadth first"));
-}
-#endif
-
-#ifdef DEBUG
-static void __attribute__((__unused__)) 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);
-}
-#endif
diff -Nru a/drivers/usb/host/usb-uhci-hcd.c b/drivers/usb/host/usb-uhci-hcd.c
--- a/drivers/usb/host/usb-uhci-hcd.c	Tue Jul 16 16:49:42 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,649 +0,0 @@
-/*  
-    UHCI HCD (Host Controller Driver) for USB, main part for HCD frame
-   
-    (c) 1999-2002 
-    Georg Acher      +    Deti Fliegl    +    Thomas Sailer
-    georg@acher.org      deti@fliegl.de   sailer@ife.ee.ethz.ch
-   
-    with the help of
-    David Brownell, david-b@pacbell.net 
-    Adam Richter, adam@yggdrasil.com
-    Roman Weissgaerber, weissg@vienna.at    
-    
-    HW-initalization based on material of
-    Randy Dunlap + Johannes Erdfelt + Gregory P. Smith + Linus Torvalds 
-
-    $Id: usb-uhci-hcd.c,v 1.3 2002/05/25 16:42:41 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/jiffies.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/init.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>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-#include <linux/usb.h>
-
-#ifdef CONFIG_USB_DEBUG
-	#define DEBUG
-#else
-	#undef DEBUG
-#endif
-
-#include "../core/hcd.h"
-#include "usb-uhci-hcd.h"
-
-#define DRIVER_VERSION "$Revision: 1.3 $"
-#define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer"
-#define DRIVER_DESC "USB 1.1 Universal Host Controller Interface driver (HCD)"
-
-/*--------------------------------------------------------------------------*/
-/* Values you may tweak with module parameters
- *  
- * high_bw: 1=on (default), 0=off
- * Turns on Full Speed Bandwidth Reclamation: 
- * Feature that puts a loop on the descriptor chain when
- * there's some transfer going on. With FSBR, USB performance
- * is optimal, but PCI can be slowed down up-to 5 times, slowing down
- * system performance (eg. framebuffer devices).
- *
- * bulk_depth/ctrl_depth: 0=off (default), 1:on
- * Puts descriptors for bulk/control transfers in depth-first mode. 
- * This has somehow similar effect to FSBR (higher speed), but does not
- * slow PCI down. OTOH USB performace is slightly slower than
- * in FSBR case and single device could hog whole USB, starving
- * other devices. Some devices (e.g. STV680-based cameras) NEED this depth 
- * first search to work properly.
- *
- * Turning off both high_bw and bulk_depth/ctrl_depth
- * will lead to <64KB/sec performance over USB for bulk transfers targeting
- * one device's endpoint. You probably do not want to do that.
- */
-
-// Other constants, there's usually no need to change them.
-// stop bandwidth reclamation after (roughly) 50ms
-#define IDLE_TIMEOUT  (HZ/20)
-
-// Suppress HC interrupt error messages for 5s
-#define ERROR_SUPPRESSION_TIME (HZ*5)
-
-// HC watchdog
-#define WATCHDOG_TIMEOUT (4*HZ)
-#define MAX_REANIMATIONS 5
-
-#define DEBUG_SYMBOLS
-#ifdef DEBUG_SYMBOLS
-        #ifndef EXPORT_SYMTAB
-                #define EXPORT_SYMTAB
-        #endif
-#endif
-
-#define queue_dbg dbg 
-#define async_dbg dbg
-#define init_dbg dbg
-
-/*--------------------------------------------------------------------------*/
-//                   NO serviceable parts below!
-/*--------------------------------------------------------------------------*/
-
-/* Can be set by module parameters */
-static int high_bw = 1;
-static int ctrl_depth = 0;  /* 0: Breadth first, 1: Depth first */
-static int bulk_depth = 0;  /* 0: Breadth first, 1: Depth first */
-
-// How much URBs with ->next are walked
-#define MAX_NEXT_COUNT 2048
-
-static struct uhci *devs = NULL;
-
-/* used by userspace UHCI data structure dumper */
-struct uhci **uhci_devices = &devs;
-
-/* A few prototypes */
-static int uhci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb);
-static int hc_reset (struct uhci_hcd *uhci);
-static void uhci_stop (struct usb_hcd *hcd);
-static int process_transfer (struct uhci_hcd *uhci, struct urb *urb, int mode);
-static int process_iso (struct uhci_hcd *uhci, struct urb *urb, int mode);
-static int process_interrupt (struct uhci_hcd *uhci, struct urb *urb, int mode);
-static int process_urb (struct uhci_hcd *uhci, struct list_head *p);
-static int uhci_urb_enqueue (struct usb_hcd *hcd, struct urb *urb, int mem_flags);
-static int hc_defibrillate(struct uhci_hcd * uhci);
-static int hc_irq_run(struct uhci_hcd *uhci);
-
-#include "usb-uhci-dbg.c"
-#include "usb-uhci-mem.c"
-#include "usb-uhci-hub.c"
-#include "usb-uhci-q.c"
-
-#define PIPESTRING(x) (x==PIPE_BULK?"Bulk":(x==PIPE_INTERRUPT?"Interrupt":(x==PIPE_CONTROL?"Control":"Iso")))
-
-/*--------------------------------------------------------------------------*/
-static int uhci_urb_enqueue (struct usb_hcd *hcd, struct urb *urb, int mem_flags)
-{
-	struct uhci_hcd	*uhci = hcd_to_uhci (hcd);
-	urb_priv_t *urb_priv;
-	int ret = 0, type;
-	unsigned long flags;
-	struct urb *queued_urb=NULL;
-	int bustime;
-	type = usb_pipetype (urb->pipe);
-
-//	err("submit_urb: scheduling %p (%s), tb %p, len %i", urb, 
-//	PIPESTRING(type),urb->transfer_buffer,urb->transfer_buffer_length);
-
-	if (uhci->need_init) {
-		if (in_interrupt())
-			return -ESHUTDOWN;
-
-		spin_lock_irqsave (&uhci->urb_list_lock, flags);
-		ret = hc_defibrillate(uhci);
-		spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-
-		if (ret)
-			return ret;		
-	}
-
-	if (!uhci->running)
-		return -ESHUTDOWN;
-
-	spin_lock_irqsave (&uhci->urb_list_lock, flags);
-
-	queued_urb = search_dev_ep (uhci, urb); // returns already queued urb for that pipe
-
-	if (queued_urb) {
-		queue_dbg("found bulk urb %p\n", queued_urb);
-
-		if (( type != PIPE_BULK) ||
-		    ((type == PIPE_BULK) &&
-		     (!(urb->transfer_flags & USB_QUEUE_BULK) || !(queued_urb->transfer_flags & USB_QUEUE_BULK)))) {
-			spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-			err("ENXIO (%s)  %08x, flags %x, urb %p, burb %p, probably device driver bug...", 
-			    PIPESTRING(type),
-			    urb->pipe,urb->transfer_flags,urb,queued_urb);
-			return -ENXIO;	// urb already queued
-		}
-	}
-
-	urb_priv = uhci_alloc_priv(mem_flags);
-
-	if (!urb_priv) {
-		spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-		return -ENOMEM;
-	}
-
-	urb->hcpriv = urb_priv;
-	urb_priv->urb=urb;
-	INIT_LIST_HEAD (&urb_priv->desc_list);
-	
-	if (type == PIPE_CONTROL)
-		urb_priv->setup_packet_dma = pci_map_single(uhci->uhci_pci, urb->setup_packet,
-							    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-
-	if (urb->transfer_buffer_length)
-		urb_priv->transfer_buffer_dma = pci_map_single(uhci->uhci_pci,
-							       urb->transfer_buffer,
-							       urb->transfer_buffer_length,
-							       usb_pipein(urb->pipe) ?
-							       PCI_DMA_FROMDEVICE :
-							       PCI_DMA_TODEVICE);
-
-	// for bulk queuing it is essential that interrupts are disabled until submission
-	// all other types enable interrupts again
-	switch (type) {
-	case PIPE_BULK:
-		if (queued_urb) {
-			while (((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb)  // find last queued bulk
-				queued_urb=((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb;
-				
-			((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb=urb;
-		}
-		atomic_inc (&uhci->avoid_bulk);
-		ret = uhci_submit_bulk_urb (uhci, urb, queued_urb);
-		atomic_dec (&uhci->avoid_bulk);
-		spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-		break;
-
-	case PIPE_ISOCHRONOUS:	
-		spin_unlock_irqrestore (&uhci->urb_list_lock, flags);		
-
-		if (urb->bandwidth == 0) {      /* not yet checked/allocated */
-			bustime = usb_check_bandwidth (urb->dev, urb);
-			if (bustime < 0) 
-				ret = bustime;
-			else {
-				ret = uhci_submit_iso_urb(uhci, urb, mem_flags);
-				if (ret == 0)
-					usb_claim_bandwidth (urb->dev, urb, bustime, 1);
-			}
-		} else {        /* bandwidth is already set */
-			ret = uhci_submit_iso_urb(uhci, urb, mem_flags);
-		}
-		break;
-
-	case PIPE_INTERRUPT:
-		spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-		if (urb->bandwidth == 0) {      /* not yet checked/allocated */
-			bustime = usb_check_bandwidth (urb->dev, urb);
-			if (bustime < 0)
-				ret = bustime;
-			else {
-				ret = uhci_submit_int_urb(uhci, urb);
-				if (ret == 0)
-					usb_claim_bandwidth (urb->dev, urb, bustime, 0);
-			}
-		} else {        /* bandwidth is already set */
-			ret = uhci_submit_int_urb(uhci, urb);
-		}
-		break;
-
-	case PIPE_CONTROL:
-		spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-		ret = uhci_submit_control_urb (uhci, urb);
-		break;
-
-	default:	
-		spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-		ret = -EINVAL;
-	}
-
-//	err("submit_urb: scheduled with ret: %d", ret);
-	
-	if (ret != 0)
- 		uhci_free_priv(uhci, urb, urb_priv);
-
-	return ret;
-}
-/*--------------------------------------------------------------------------*/
-static int uhci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
-{
-	unsigned long flags=0;
-	struct uhci_hcd	*uhci = hcd_to_uhci (hcd);
-	int ret;
-
-	dbg("uhci_urb_dequeue called for %p",urb);
-	
-	spin_lock_irqsave (&uhci->urb_list_lock, flags);
-	ret = uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
-	spin_unlock_irqrestore (&uhci->urb_list_lock, flags);	
-	return ret;
-}
-/*--------------------------------------------------------------------------*/
-static int uhci_get_frame (struct usb_hcd *hcd)
-{
-	struct uhci_hcd	*uhci = hcd_to_uhci (hcd);
-	return inw ((int)uhci->hcd.regs + USBFRNUM);
-}
-
-/*--------------------------------------------------------------------------*/
-//             Init and shutdown functions for HW 
-/*--------------------------------------------------------------------------*/
-static int hc_reset (struct uhci_hcd *uhci)
-{
-	unsigned long io_addr = (unsigned long)uhci->hcd.regs;
-
-	uhci->apm_state = 0;
-	uhci->running = 0;
-	outw (USBCMD_GRESET, io_addr + USBCMD);
-	uhci_wait_ms (50);   /* Global reset for 50ms */
-	outw (0, io_addr + USBCMD);
-	uhci_wait_ms (10);	
-	return 0;
-}
-/*--------------------------------------------------------------------------*/
-static int hc_irq_run(struct uhci_hcd *uhci)
-{
-	unsigned long io_addr = (unsigned long)uhci->hcd.regs;
-	/* 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 (uhci->framelist_dma, io_addr + USBFLBASEADD);
-
-	/* Run and mark it configured with a 64-byte max packet */
-	outw (USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
-	uhci->apm_state = 1;
-	uhci->running = 1;
-	uhci->last_hcd_irq = jiffies+4*HZ;
-	return 0;
-}
-/*--------------------------------------------------------------------------*/
-static int hc_start (struct uhci_hcd *uhci)
-{
-	unsigned long io_addr = (unsigned long)uhci->hcd.regs;
-	int timeout = 10;
-	struct usb_device	*udev;
-	init_dbg("hc_start uhci %p",uhci);
-	/*
-	 * 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;
-		}
-		udelay(1);
-	}
-	
-	hc_irq_run(uhci);
-
-	/* connect the virtual root hub */
-	uhci->hcd.self.root_hub = udev = usb_alloc_dev (NULL, &uhci->hcd.self);
-	uhci->hcd.state = USB_STATE_READY;
-	if (!udev) {
-	    uhci->running = 0;
-	    return -ENOMEM;
-	}
-
-	usb_connect (udev);
-	udev->speed = USB_SPEED_FULL;
-	if (usb_register_root_hub (udev, &uhci->hcd.pdev->dev) != 0) {
-		usb_free_dev (udev); 
-		uhci->running = 0;
-		return -ENODEV;
-	}
-	
-	return 0;
-}
-
-/*--------------------------------------------------------------------------*/
-// Start up UHCI, find ports, init DMA lists
-
-static int __devinit uhci_start (struct usb_hcd *hcd)
-{
-	struct uhci_hcd	*uhci = hcd_to_uhci (hcd);
-	int ret;
-	unsigned long io_addr=(unsigned long)hcd->regs, io_size=0x20;
-	
-	init_dbg("uhci_start hcd %p uhci %p, pdev %p",hcd,uhci,hcd->pdev);
-	/* disable legacy emulation, Linux takes over... */
-	pci_write_config_word (hcd->pdev, USBLEGSUP, 0);
-
-	/* 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 (uhci->maxports = 0; uhci->maxports < (io_size - 0x10) / 2; uhci->maxports++) {
-		unsigned int portstatus;
-
-		portstatus = inw (io_addr + 0x10 + (uhci->maxports * 2));
-		dbg("port %i, adr %x status %x", uhci->maxports,
-			io_addr + 0x10 + (uhci->maxports * 2), portstatus);
-		if (!(portstatus & 0x0080))
-			break;
-	}
-	warn("Detected %d ports", uhci->maxports);
-	
-	if (uhci->maxports < 2 || uhci->maxports > 8) {
-		dbg("Port count misdetected, forcing to 2 ports");
-		uhci->maxports = 2;
-	}	       
-
-	ret=init_skel(uhci);
-	if (ret)
-		return ret;
-
-	hc_reset (uhci);
-
-	if (hc_start (uhci) < 0) {
-		err ("can't start %s", uhci->hcd.self.bus_name);
-		uhci_stop (hcd);
-		return -EBUSY;
-	}
-
-	// Enable PIRQ
-	pci_write_config_word (hcd->pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
-
-	set_td_ioc(uhci->td128ms); // start watchdog interrupt
-	uhci->last_hcd_irq=jiffies+5*HZ;
-
-	return 0;	
-}
-/*--------------------------------------------------------------------------*/
-static void uhci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
-{
-	dbg("uhci_free_config for dev %p", udev);
-	uhci_unlink_urbs (hcd_to_uhci (hcd), udev, 0);  // Forced unlink of remaining URBs
-}
-/*--------------------------------------------------------------------------*/
-static void uhci_stop (struct usb_hcd *hcd)
-{
-	struct uhci_hcd	*uhci = hcd_to_uhci (hcd);
-	
-	init_dbg("%s: stop controller", hcd->bus_name);
-	
-	uhci->running=0;
-	hc_reset (uhci);
-	wait_ms (1);
-	uhci_unlink_urbs (uhci, 0, CLEAN_FORCED);  // Forced unlink of remaining URBs
-	uhci_cleanup_unlink (uhci, CLEAN_FORCED);  // force cleanup of async killed URBs
-	cleanup_skel (uhci);
-}
-/*--------------------------------------------------------------------------*/
-//                  UHCI INTERRUPT PROCESSING
-/*--------------------------------------------------------------------------*/
-static void uhci_irq (struct usb_hcd *hcd)
-{	
-	struct uhci_hcd	*uhci = hcd_to_uhci (hcd);
-	unsigned long io_addr = (unsigned long)hcd->regs;
-	unsigned short status;
-	struct list_head *p, *p2;
-	int restarts, work_done;
-
-	/*
-	 * 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");
-
-	uhci->last_hcd_irq=jiffies;  // for watchdog
-
-	if (status != 1) {
-		// Avoid too much error messages at a time
-		if (time_after(jiffies, uhci->last_error_time + ERROR_SUPPRESSION_TIME)) {
-			warn("interrupt, status %x, frame# %i", status, 
-			     UHCI_GET_CURRENT_FRAME(uhci));
-			uhci->last_error_time = jiffies;
-		}
-		
-		// remove host controller halted state
-		if ((status&0x20) && (uhci->running)) {
-			err("Host controller halted, waiting for timeout.");
-//			outw (USBCMD_RS | inw(io_addr + USBCMD), io_addr + USBCMD);
-		}
-		//uhci_show_status (s);
-	}
-	/*
-	 * 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
-	 * New: check for max. workload and restart count
-	 */
-
-	spin_lock (&uhci->urb_list_lock);
-
-	restarts=0;
-	work_done=0;
-
-restart:
-	uhci->unlink_urb_done=0;
-	p = uhci->urb_list.prev;	
-
-	while (p != &uhci->urb_list && (work_done < 1024)) {
-		p2 = p;
-		p = p->prev;
-
-		process_urb (uhci, p2);
-		
-		work_done++;
-
-		if (uhci->unlink_urb_done) {
-			uhci->unlink_urb_done=0;
-			restarts++;
-			
-			if (restarts<16)	// avoid endless restarts
-				goto restart;
-			else 
-				break;
-		}
-	}
-	if (time_after(jiffies, uhci->timeout_check + (HZ/30)))
-		uhci_check_timeouts(uhci);
-
-	clean_descs(uhci, CLEAN_NOT_FORCED);
-	uhci_cleanup_unlink(uhci, CLEAN_NOT_FORCED);
-	uhci_switch_timer_int(uhci);
-							
-	spin_unlock (&uhci->urb_list_lock);
-	
-	outw (status, io_addr + USBSTS);
-
-	//dbg("uhci_interrupt: done");
-}
-
-/*--------------------------------------------------------------------------*/
-//             POWER MANAGEMENT
-
-#ifdef	CONFIG_PM
-static int uhci_suspend (struct usb_hcd *hcd, u32 state)
-{
-	struct uhci_hcd		*uhci = hcd_to_uhci (hcd);
-	hc_reset(uhci);
-	return 0;
-}
-/*--------------------------------------------------------------------------*/
-static int uhci_resume (struct usb_hcd *hcd)
-{
-	struct uhci_hcd		*uhci = hcd_to_uhci (hcd);
-	hc_start(uhci);
-	return 0;
-}
-#endif
-/*--------------------------------------------------------------------------*/
-static const char	hcd_name [] = "usb-uhci-hcd";
-
-static const struct hc_driver uhci_driver = {
-	description:		hcd_name,
-
-	// generic hardware linkage
-	irq:			uhci_irq,
-	flags:			HCD_USB11,
-
-	// basic lifecycle operations
-	start:			uhci_start,
-#ifdef	CONFIG_PM
-	suspend:		uhci_suspend,
-	resume:			uhci_resume,
-#endif
-	stop:			uhci_stop,
-
-	// memory lifecycle (except per-request)
-	hcd_alloc:		uhci_hcd_alloc,
-	hcd_free:		uhci_hcd_free,
-
-	// managing i/o requests and associated device resources
-	urb_enqueue:		uhci_urb_enqueue,
-	urb_dequeue:		uhci_urb_dequeue,
-	free_config:		uhci_free_config,
-
-	// scheduling support
-	get_frame_number:	uhci_get_frame,
-
-	// root hub support
-	hub_status_data:	uhci_hub_status_data,
-	hub_control:		uhci_hub_control,
-};
-
-#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
-
-MODULE_AUTHOR (DRIVER_AUTHOR);
-MODULE_DESCRIPTION (DRIVER_INFO);
-MODULE_LICENSE ("GPL");
-MODULE_PARM (high_bw, "i");
-MODULE_PARM_DESC (high_bw, "high_hw: Enable high bandwidth mode, 1=on (default), 0=off"); 
-MODULE_PARM (bulk_depth, "i");
-MODULE_PARM_DESC (bulk_depth, "bulk_depth: Depth first processing for bulk transfers, 0=off (default), 1=on");
-MODULE_PARM (ctrl_depth, "i");
-MODULE_PARM_DESC (ctrl_depth, "ctrl_depth: Depth first processing for control transfers, 0=off (default), 1=on");
-
-static const struct pci_device_id __devinitdata pci_ids [] = { {
-
-	/* handle any USB UHCI controller */
-	class:		(PCI_CLASS_SERIAL_USB << 8) | 0x00,
-	class_mask:	~0,
-	driver_data:	(unsigned long) &uhci_driver,
-
-	/* no matter who makes it */
-	vendor:		PCI_ANY_ID,
-	device:		PCI_ANY_ID,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
-	}, { /* end: all zeroes */ }
-};
-
-MODULE_DEVICE_TABLE (pci, pci_ids);
-
-/* pci driver glue; this is a "new style" PCI driver module */
-static struct pci_driver uhci_pci_driver = {
-	name:		(char *) hcd_name,
-	id_table:	pci_ids,
-
-	probe:		usb_hcd_pci_probe,
-	remove:		usb_hcd_pci_remove,
-
-#ifdef	CONFIG_PM
-	suspend:	usb_hcd_pci_suspend,
-	resume:		usb_hcd_pci_resume,
-#endif
-};
-/*-------------------------------------------------------------------------*/
-
-static int __init uhci_hcd_init (void) 
-{
-	init_dbg (DRIVER_INFO);
-	init_dbg ("block sizes: hq %d td %d",
-		sizeof (struct qh), sizeof (struct td));
-	info("High bandwidth mode %s.%s%s",
-	     high_bw?"enabled":"disabled",
-	     ctrl_depth?"CTRL depth first enabled":"",
-	     bulk_depth?"BULK depth first enabled":"");
-	return pci_module_init (&uhci_pci_driver);
-}
-
-static void __exit uhci_hcd_cleanup (void) 
-{	
-	pci_unregister_driver (&uhci_pci_driver);
-}
-
-module_init (uhci_hcd_init);
-module_exit (uhci_hcd_cleanup);
-
-
diff -Nru a/drivers/usb/host/usb-uhci-hcd.h b/drivers/usb/host/usb-uhci-hcd.h
--- a/drivers/usb/host/usb-uhci-hcd.h	Tue Jul 16 16:49:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,247 +0,0 @@
-#ifndef __LINUX_USB_UHCI_H
-#define __LINUX_USB_UHCI_H
-
-/*  $Id: usb-uhci-hcd.h,v 1.1 2002/05/14 20:36:57 acher Exp $ */
-
-#ifndef CONFIG_PCI
-#error "UHCI needs the CONFIG_PCI option!"
-#endif
-
-#define MODNAME "usb-uhci-hcd"
-#define UHCI_LATENCY_TIMER 0
-
-static __inline__ void uhci_wait_ms(unsigned int ms)
-{
-	if(!in_interrupt())
-	{
-		current->state = TASK_UNINTERRUPTIBLE;
-		schedule_timeout(1 + ms * HZ / 1000);
-	}
-	else
-		mdelay(ms);
-}
-
-/* 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_PID 		0xff	/* PID MASK */
-
-#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(desc)	((le32_to_cpu(desc->hw.td.status) + 1) & TD_CTRL_ACTLEN_MASK)	/* 1-based */
-
-/* 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)
-
-#define uhci_do_toggle(urb)     usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe))
-#define uhci_get_toggle(urb)    usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe))
-
-/* ------------------------------------------------------------------------------------
-   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;
-	dma_addr_t 		dma_addr;
-	struct list_head 	horizontal;
-	struct list_head 	vertical;
-	struct list_head 	desc_list;
-	int 			last_used;
-} uhci_desc_t, *puhci_desc_t;
-
-typedef struct {
-	struct list_head 	desc_list;	// list pointer to all corresponding TDs/QHs associated with this request
-	struct list_head 	urb_list;
-	struct urb              *urb;  // urb to which this data belongs
-	dma_addr_t 		setup_packet_dma;
-	dma_addr_t 		transfer_buffer_dma;
-	unsigned long 		started;
-	struct urb		*next_queued_urb;	// next queued urb for this EP
-	struct urb 		*prev_queued_urb;
-	uhci_desc_t		*bottom_qh;
-	uhci_desc_t		*next_qh;       	// next helper QH
-	char 			use_loop;
-	char 			flags;
-} urb_priv_t, *purb_priv_t;
-
-struct uhci_hcd {
-	unsigned int 		maxports;
-	int 			running;
-	int 			apm_state;
-
-	struct uhci_hcd 	*next;	// chain of uhci device contexts
-
-	spinlock_t 		urb_list_lock;	// lock to keep consistency 
-	spinlock_t 		qh_lock;
-	spinlock_t 		td_lock;
-	atomic_t 		avoid_bulk;
-	
-	__u32 			*framelist;
-	dma_addr_t 		framelist_dma;
-	uhci_desc_t 		**iso_td;
-	uhci_desc_t 		*int_chain[8];
-	uhci_desc_t 		*ls_control_chain;
-	uhci_desc_t 		*control_chain;
-	uhci_desc_t 		*bulk_chain;
-	uhci_desc_t 		*chain_end;
-	uhci_desc_t 		*td1ms;
-	uhci_desc_t 		*td32ms;
-	uhci_desc_t 		*td128ms;
-
-	struct list_head 	urb_list;	// list of all pending urbs
-	struct list_head 	free_desc_qh;   // Cool down pool for QH
-	struct list_head 	free_desc_td;   // Cool down pool for ISO/INT-TDs
-	struct list_head 	urb_unlinked;	// list of all unlinked  urbs
-	struct pci_dev 		*uhci_pci;
-	struct pci_pool 	*desc_pool;
-
-	int 			unlink_urb_done;
-	int 			loop_usage;            // URBs using bandwidth reclamation
-	long 			timeout_check;
-	int 			timeout_urbs;
-	long 			last_error_time;          // last error output in uhci_interrupt()
-	
-	long                    last_hcd_irq;
-	int                     reanimations;
-	int                     need_init;
-
-	// Framework state
-	struct usb_hcd          hcd;
-};
-
-#define hcd_to_uhci(hcd_ptr) list_entry(hcd_ptr, struct uhci_hcd, hcd)
-
-#define MAKE_TD_ADDR(a) ((a)->dma_addr&~UHCI_PTR_QH)
-#define MAKE_QH_ADDR(a) ((a)->dma_addr|UHCI_PTR_QH)
-#define UHCI_GET_CURRENT_FRAME(uhci) (inw ((int)(uhci->hcd.regs) + USBFRNUM))
-
-#define CLEAN_TRANSFER_NO_DELETION 0
-#define CLEAN_TRANSFER_REGULAR 1
-#define CLEAN_TRANSFER_DELETION_MARK 2
-
-#define CLEAN_NOT_FORCED 0
-#define CLEAN_FORCED 1
-
-#define PROCESS_ISO_REGULAR 0
-#define PROCESS_ISO_FORCE 1
-
-#define PROCESS_INT_REGULAR 0
-#define PROCESS_INT_REMOVE 1
-
-#define UNLINK_ASYNC_STORE_URB 0
-#define UNLINK_ASYNC_DONT_STORE 1
-
-#define is_td_active(desc) (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE))
-
-#define set_qh_head(desc,val) (desc)->hw.qh.head=cpu_to_le32(val)
-#define set_qh_element(desc,val) (desc)->hw.qh.element=cpu_to_le32(val)
-#define set_td_link(desc,val) (desc)->hw.td.link=cpu_to_le32(val)
-#define set_td_ioc(desc) (desc)->hw.td.status |= cpu_to_le32(TD_CTRL_IOC)
-#define clr_td_ioc(desc) (desc)->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC)
-
-
-#endif
diff -Nru a/drivers/usb/host/usb-uhci-hub.c b/drivers/usb/host/usb-uhci-hub.c
--- a/drivers/usb/host/usb-uhci-hub.c	Tue Jul 16 16:49:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,213 +0,0 @@
-/*  
-    UHCI HCD (Host Controller Driver) for USB, UHCI Root Hub
-    
-    (c) 1999-2002 
-    Georg Acher      +    Deti Fliegl    +    Thomas Sailer
-    georg@acher.org      deti@fliegl.de   sailer@ife.ee.ethz.ch
-   
-    with the help of
-    David Brownell, david-b@pacbell.net
-    Adam Richter, adam@yggdrasil.com
-    Roman Weissgaerber, weissg@vienna.at
-    
-    HW-initalization based on material of
-    Randy Dunlap + Johannes Erdfelt + Gregory P. Smith + Linus Torvalds 
-
-    $Id: usb-uhci-hub.c,v 1.2 2002/05/21 21:40:16 acher Exp $
-*/
-
-#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))
-
-static int oldval=-1;
-
-/* build "status change" packet (one or two bytes) from HC registers 
-   Since uhci_hub_status_data is called by a SW timer, it is also used
-   for monitoring HC health */
-static int uhci_hub_status_data (struct usb_hcd *hcd, char *buf)
-{
-	struct uhci_hcd *uhci = hcd_to_uhci (hcd);
-	unsigned long io_addr = (unsigned long)uhci->hcd.regs;
-	int i, len=0, data = 0, portstate;
-	int changed=0;
-
-	for (i = 0; i < uhci->maxports; i++) {
-		portstate=inw (io_addr + USBPORTSC1 + i * 2);
-#if 0
-		if (i==0 && (portstate&0xf) != (oldval&0xf))
-			err("Port %i: %x", i+1, portstate);
-#endif
-		if (i==0)
-			oldval=portstate;
-		if ((portstate & 0xa) > 0) {
-			changed=1;
-		}
-		data |= ((portstate & 0xa) > 0 ? (1 << (i + 1)) : 0);
-		len = (i + 1) / 8 + 1;
-	}
-
-
-	*(__u16 *)buf = cpu_to_le16 (data);
-
-	// Watchdog
-
-	if (uhci->running && time_after(jiffies, uhci->last_hcd_irq + WATCHDOG_TIMEOUT)) {
-		if (uhci->reanimations > MAX_REANIMATIONS) {
-			err("He's dead, Jim. Giving up reanimating the UHCI host controller.\n"
-			    "Maybe a real module reload helps...");
-			uhci->running = 0;
-		}
-		else {	
-			uhci->running = 0;
-			uhci->need_init=1; // init done in the next submit_urb
-		}
-	}
-	return changed?len:0;
-}
-/*-------------------------------------------------------------------------*/
-static void uhci_hub_descriptor (struct uhci_hcd *uhci, struct usb_hub_descriptor *desc) 
-{
-	int		ports = uhci->maxports;
-	u16		temp;
-	desc->bDescriptorType = 0x29;
-	desc->bPwrOn2PwrGood = 1;
-	desc->bHubContrCurrent = 0;
-	desc->bNbrPorts = ports;
-	temp = 1 + (ports / 8);
-	desc->bDescLength = 7 + 2 * temp;
-	desc->wHubCharacteristics = 0;	
-	desc-> bitmap[0] = 0;
-	desc-> bitmap[1] = 0xff;
-}
-/*-------------------------------------------------------------------------*/
-static int uhci_hub_control (
-        struct usb_hcd  *hcd,
-        u16             typeReq,
-        u16             wValue,
-        u16             wIndex,
-        char            *buf,
-        u16             wLength) 
-{
-	struct uhci_hcd *uhci = hcd_to_uhci (hcd);
-	int status = 0;
-	int stat = 0;
-	int cstatus;
-	unsigned long io_addr = (unsigned long)uhci->hcd.regs;
-	int		ports = uhci->maxports;
-
-	switch (typeReq) {	
-
-	case ClearHubFeature:
-		break;
-
-	case ClearPortFeature:
-		if (!wIndex || wIndex > ports)
-                        goto error;
-
-		switch (wValue) {
-		case USB_PORT_FEAT_ENABLE:
-			CLR_RH_PORTSTAT (USBPORTSC_PE);
-			break;
-		case USB_PORT_FEAT_C_ENABLE:
-			SET_RH_PORTSTAT (USBPORTSC_PEC);
-			break;
-
-		case USB_PORT_FEAT_SUSPEND:
-			CLR_RH_PORTSTAT (USBPORTSC_SUSP);
-			break;
-		case USB_PORT_FEAT_C_SUSPEND:
-			/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
-			break;
-
-		case USB_PORT_FEAT_POWER:
-		       	break;/* port power ** */
-
-		case USB_PORT_FEAT_C_CONNECTION:
-			SET_RH_PORTSTAT (USBPORTSC_CSC);
-			break;
-		
-		case USB_PORT_FEAT_C_OVER_CURRENT:
-			break;	/* port power over current ** */
-
-		case USB_PORT_FEAT_C_RESET:
-			break;
-		default:
-			goto error;
-		}
-		break;
-
-	case GetHubDescriptor:
-                uhci_hub_descriptor (uhci, (struct usb_hub_descriptor *) buf);
-                break;
-
-	case GetHubStatus:
-		*(u32 *) buf = cpu_to_le32 (0);
-		break;
-
-	case GetPortStatus:
-		if (!wIndex || wIndex > ports)
-			goto error;
-
-		status = inw (io_addr + USBPORTSC1 + 2 * (wIndex - 1));
-		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
-			((status & USBPORTSC_PEC) >> (3 - 1));
-
-		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 *) buf = cpu_to_le16 (status);
-		*(__u16 *) (buf + 2) = cpu_to_le16 (cstatus);
-		break;
-
-	case SetHubFeature:
-		// FIXME
-		break;
-
-	case SetPortFeature: 
-		if (!wIndex || wIndex > ports)
-			goto error;
-			
-		switch (wValue) {
-		case USB_PORT_FEAT_SUSPEND:
-			SET_RH_PORTSTAT (USBPORTSC_SUSP);
-			break;
-		case USB_PORT_FEAT_RESET:
-			SET_RH_PORTSTAT (USBPORTSC_PR);
-			uhci_wait_ms (10);
-			CLR_RH_PORTSTAT (USBPORTSC_PR);
-			udelay (10);
-			SET_RH_PORTSTAT (USBPORTSC_PE);
-			uhci_wait_ms (10);
-			SET_RH_PORTSTAT (0xa);
-			break;
-		case USB_PORT_FEAT_POWER:
-			break;	/* port power ** */
-		case  USB_PORT_FEAT_ENABLE:
-			SET_RH_PORTSTAT (USBPORTSC_PE);
-			break;
-		default:
-			goto error;
-		}
-		break;
-				
-	default:
-error:		
-		stat = -EPIPE;
-	}
-
-	dbg("Root-Hub stat port1: %x port2: %x",
-	     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2));
-
-	return stat;
-}
diff -Nru a/drivers/usb/host/usb-uhci-mem.c b/drivers/usb/host/usb-uhci-mem.c
--- a/drivers/usb/host/usb-uhci-mem.c	Tue Jul 16 16:49:42 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,717 +0,0 @@
-/*  
-    UHCI HCD (Host Controller Driver) for USB
-    UHCI memory allocation and basic descriptor handling
-   
-    (c) 1999-2002 
-    Georg Acher      +    Deti Fliegl    +    Thomas Sailer
-    georg@acher.org      deti@fliegl.de   sailer@ife.ee.ethz.ch
-   
-    with the help of
-    David Brownell, david-b@pacbell.net
-    Adam Richter, adam@yggdrasil.com
-    Roman Weissgaerber, weissg@vienna.at    
-    
-    HW-initalization based on material of
-    Randy Dunlap + Johannes Erdfelt + Gregory P. Smith + Linus Torvalds 
-
-    $Id: usb-uhci-mem.c,v 1.3 2002/05/25 16:42:41 acher Exp $
- */
-
-/*###########################################################################*/
-//                        UHCI STRUCTURE
-/*###########################################################################*/
-static struct usb_hcd *uhci_hcd_alloc (void)
-{
-	struct uhci_hcd *uhci;
-	int len;
-
-	len=sizeof (struct uhci_hcd);
-	uhci = (struct uhci_hcd *) kmalloc (len, GFP_KERNEL);
-	if (uhci == 0) 
-		return NULL;
-	
-	memset (uhci, 0, len);
-	init_dbg("uhci @ %p, hcd @ %p",uhci, &(uhci->hcd));
-	INIT_LIST_HEAD (&uhci->free_desc_qh);
-	INIT_LIST_HEAD (&uhci->free_desc_td);
-	INIT_LIST_HEAD (&uhci->urb_list);
-	INIT_LIST_HEAD (&uhci->urb_unlinked);
-	spin_lock_init (&uhci->urb_list_lock);
-	spin_lock_init (&uhci->qh_lock);
-	spin_lock_init (&uhci->td_lock);
-	atomic_set(&uhci->avoid_bulk, 0);		
-	return &(uhci->hcd);
-}
-/*-------------------------------------------------------------------*/
-static void uhci_hcd_free (struct usb_hcd *hcd)
-{
-	kfree (hcd_to_uhci (hcd));
-}
-/*###########################################################################*/
-//                   DMA/PCI CONSISTENCY
-/*###########################################################################*/
-
-static void uhci_urb_dma_sync(struct uhci_hcd *uhci, struct urb *urb, urb_priv_t *urb_priv)
-{
-	if (urb_priv->setup_packet_dma)
-		pci_dma_sync_single(uhci->uhci_pci, urb_priv->setup_packet_dma,
-				    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-
-	if (urb_priv->transfer_buffer_dma)
-		pci_dma_sync_single(uhci->uhci_pci, urb_priv->transfer_buffer_dma,
-				    urb->transfer_buffer_length,
-				    usb_pipein(urb->pipe) ?
-				    PCI_DMA_FROMDEVICE :
-				    PCI_DMA_TODEVICE);
-}
-/*-------------------------------------------------------------------*/
-static void uhci_urb_dma_unmap(struct uhci_hcd *uhci, struct urb *urb, urb_priv_t *urb_priv)
-{
-	if (urb_priv->setup_packet_dma) {
-		pci_unmap_single(uhci->uhci_pci, urb_priv->setup_packet_dma,
-				 sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-		urb_priv->setup_packet_dma = 0;
-	}
-	if (urb_priv->transfer_buffer_dma) {
-		pci_unmap_single(uhci->uhci_pci, urb_priv->transfer_buffer_dma,
-				 urb->transfer_buffer_length,
-				 usb_pipein(urb->pipe) ?
-				 PCI_DMA_FROMDEVICE :
-				 PCI_DMA_TODEVICE);
-		urb_priv->transfer_buffer_dma = 0;
-	}
-}
-/*###########################################################################*/
-//                       TRANSFER DESCRIPTORS (TD)
-/*###########################################################################*/
-
-static void fill_td (uhci_desc_t *td, int status, int info, __u32 buffer)
-{
-	td->hw.td.status = cpu_to_le32(status);
-	td->hw.td.info = cpu_to_le32(info);
-	td->hw.td.buffer = cpu_to_le32(buffer);
-}
-/*-------------------------------------------------------------------*/
-static int alloc_td (struct uhci_hcd *uhci, uhci_desc_t ** new, int flags)
-{
-	dma_addr_t dma_handle;
-
-	*new = pci_pool_alloc(uhci->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
-	if (!*new)
-		return -ENOMEM;
-	memset (*new, 0, sizeof (uhci_desc_t));
-	(*new)->dma_addr = dma_handle;
-	set_td_link((*new), 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 (struct uhci_hcd *uhci, uhci_desc_t *qh, uhci_desc_t* new, int flags)
-{
-	uhci_desc_t *prev;
-	unsigned long cpuflags;
-	
-	spin_lock_irqsave (&uhci->td_lock, cpuflags);
-
-	list_add_tail (&new->vertical, &qh->vertical);
-
-	prev = list_entry (new->vertical.prev, uhci_desc_t, vertical);
-
-	if (qh == prev ) {
-		// virgin qh without any tds
-		set_qh_element(qh, new->dma_addr | UHCI_PTR_TERM);
-	}
-	else {
-		// already tds inserted, implicitely remove TERM bit of prev
-		set_td_link(prev, new->dma_addr | (flags & UHCI_PTR_DEPTH));
-	}
-	mb();
-	spin_unlock_irqrestore (&uhci->td_lock, cpuflags);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-/* insert new_td after td (horizontal) */
-static int insert_td_horizontal (struct uhci_hcd *uhci, uhci_desc_t *td, uhci_desc_t* new)
-{
-	uhci_desc_t *next;
-	unsigned long flags;
-	
-	spin_lock_irqsave (&uhci->td_lock, flags);
-
-	next = list_entry (td->horizontal.next, uhci_desc_t, horizontal);
-	list_add (&new->horizontal, &td->horizontal);
-	new->hw.td.link = td->hw.td.link;
-	mb();
-	set_td_link(td, new->dma_addr);
-	mb();
-	spin_unlock_irqrestore (&uhci->td_lock, flags);	
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-static int unlink_td (struct uhci_hcd *uhci, uhci_desc_t *element, int phys_unlink)
-{
-	uhci_desc_t *next, *prev;
-	int dir = 0;
-	unsigned long flags;
-	
-	spin_lock_irqsave (&uhci->td_lock, flags);
-	
-	next = list_entry (element->vertical.next, uhci_desc_t, vertical);
-	
-	if (next == element) {
-		dir = 1;
-		prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
-	}
-	else 
-		prev = list_entry (element->vertical.prev, uhci_desc_t, vertical);
-	
-	if (phys_unlink) {
-		// really remove HW linking
-		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 (&uhci->td_lock, flags);	
-	
-	return 0;
-}
-/*###########################################################################*/
-//               QUEUE HEADS (QH)
-/*###########################################################################*/
-// Allocates qh element
-static int alloc_qh (struct uhci_hcd *uhci, uhci_desc_t ** new)
-{
-	dma_addr_t dma_handle;
-
-	*new = pci_pool_alloc(uhci->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
-	if (!*new)
-		return -ENOMEM;
-	memset (*new, 0, sizeof (uhci_desc_t));
-	(*new)->dma_addr = dma_handle;
-	set_qh_head(*new, UHCI_PTR_TERM);
-	set_qh_element(*new, UHCI_PTR_TERM);
-	(*new)->type = QH_TYPE;
-	
-	mb();
-	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 (struct uhci_hcd *uhci, uhci_desc_t *pos, uhci_desc_t *new, int order)
-{
-	uhci_desc_t *old;
-	unsigned long flags;
-
-	spin_lock_irqsave (&uhci->qh_lock, flags);
-
-	if (!order) {
-		// (OLD) (POS) -> (OLD) (NEW) (POS)
-		old = list_entry (pos->horizontal.prev, uhci_desc_t, horizontal);
-		list_add_tail (&new->horizontal, &pos->horizontal);
-		set_qh_head(new, MAKE_QH_ADDR (pos)) ;
-		mb();
-		if (!(old->hw.qh.head & cpu_to_le32(UHCI_PTR_TERM)))
-			set_qh_head(old, 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);
-		set_qh_head(new, MAKE_QH_ADDR (old));
-		mb();
-		set_qh_head(pos, MAKE_QH_ADDR (new)) ;
-	}
- 	mb ();
-	
-	spin_unlock_irqrestore (&uhci->qh_lock, flags);
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// append a qh to td.link physically, the SW linkage is not affected
-static void append_qh(struct uhci_hcd *uhci, uhci_desc_t *td, uhci_desc_t* qh, int  flags)
-{
-	unsigned long cpuflags;
-	
-	spin_lock_irqsave (&uhci->td_lock, cpuflags);
-
-	set_td_link(td, qh->dma_addr | (flags & UHCI_PTR_DEPTH) | UHCI_PTR_QH);
-       
-	mb();
-	spin_unlock_irqrestore (&uhci->td_lock, cpuflags);
-}
-/*-------------------------------------------------------------------*/
-static int unlink_qh (struct uhci_hcd *uhci, uhci_desc_t *element)
-{
-	uhci_desc_t  *prev;
-	unsigned long flags;
-	__u32 old_head;
-	spin_lock_irqsave (&uhci->qh_lock, flags);
-	
-	prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
-
-	old_head = element->hw.qh.head;
-	element->hw.qh.head = UHCI_PTR_TERM;
-	mb();
-	prev->hw.qh.head = old_head;
-
-	dbg("unlink qh %p, pqh %p, nxqh %p, to %08x", element, prev, 
-	    list_entry (element->horizontal.next, uhci_desc_t, horizontal),
-	    le32_to_cpu(element->hw.qh.head) &~15);
-	
-	list_del(&element->horizontal);
-
-	mb ();
-	spin_unlock_irqrestore (&uhci->qh_lock, flags);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-static int delete_desc (struct uhci_hcd *uhci, uhci_desc_t *element)
-{
-	pci_pool_free(uhci->desc_pool, element, element->dma_addr);
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-static int delete_qh (struct uhci_hcd *uhci, uhci_desc_t *qh)
-{
-	uhci_desc_t *td;
-	struct list_head *p;
-	int n=0;
-
-	list_del (&qh->horizontal);
-
-	while ((p = qh->vertical.next) != &qh->vertical && n<10000) {
-		td = list_entry (p, uhci_desc_t, vertical);
-		dbg("unlink td @ %p",td);
-		unlink_td (uhci, td, 0); // no physical unlink
-		delete_desc (uhci, td);
-		n++;
-	}
-	// never trust any software, not even your own...
-	if (n>=10000)
-		err("delete_qh: Garbage in QH list, giving up");
-
-	delete_desc (uhci, qh);
-	
-	return 0;
-}
-/*###########################################################################*/
-//             DESCRIPTOR CHAINING HELPERS
-/*###########################################################################*/
-
-static void clean_td_chain (struct uhci_hcd *uhci, uhci_desc_t *td)
-{
-	struct list_head *p;
-	uhci_desc_t *td1;
-
-	if (!td)
-		return;
-	
-	while ((p = td->horizontal.next) != &td->horizontal) {
-		td1 = list_entry (p, uhci_desc_t, horizontal);
-		delete_desc (uhci, td1);
-	}
-	
-	delete_desc (uhci, td);
-}
-/*-------------------------------------------------------------------*/
-// Cleans up collected QHs/TDs, but not more than 100 in one go
-void clean_descs(struct uhci_hcd *uhci, int force)
-{
-	struct list_head *q;
-	uhci_desc_t *qh,*td;
-	int now=UHCI_GET_CURRENT_FRAME(uhci), n=0;
-
-	q=uhci->free_desc_qh.prev;
-	
-	while (q != &uhci->free_desc_qh && (force || n<100)) {
-		qh = list_entry (q, uhci_desc_t, horizontal);		
-		q=qh->horizontal.prev;
-
-		if ((qh->last_used!=now) || force) {
-			delete_qh(uhci,qh);
-		}
-		n++;
-	}
-
-	q=uhci->free_desc_td.prev;
-	n=0;
-
-	while (q != &uhci->free_desc_td && (force || n<100)) {
-
-		td = list_entry (q, uhci_desc_t, horizontal);		
-		q=td->horizontal.prev;
-
-		if (((td->last_used!=now)&&(td->last_used+1!=now)) || force) {
-			list_del (&td->horizontal);
-			delete_desc(uhci,td);
-		}
-		n++;
-	}
-}
-/*-------------------------------------------------------------------*/
-static void uhci_switch_timer_int(struct uhci_hcd *uhci)
-{
-
-	if (!list_empty(&uhci->urb_unlinked))
-		set_td_ioc(uhci->td1ms);
-	else
-		clr_td_ioc(uhci->td1ms);
-
-	if (uhci->timeout_urbs)
-		set_td_ioc(uhci->td32ms);
-	else
-		clr_td_ioc(uhci->td32ms);
-	wmb();
-}
-/*-------------------------------------------------------------------*/
-static void enable_desc_loop(struct uhci_hcd *uhci, struct urb *urb)
-{
-	unsigned long flags;
-
-	if (urb->transfer_flags & USB_NO_FSBR)
-		return;
-
-	spin_lock_irqsave (&uhci->qh_lock, flags);
-	uhci->chain_end->hw.qh.head&=cpu_to_le32(~UHCI_PTR_TERM);
-	mb();
-	uhci->loop_usage++;
-	((urb_priv_t*)urb->hcpriv)->use_loop=1;
-	spin_unlock_irqrestore (&uhci->qh_lock, flags);
-}
-/*-------------------------------------------------------------------*/
-static void disable_desc_loop(struct uhci_hcd *uhci, struct urb *urb)
-{
-	unsigned long flags;
-
-	if (urb->transfer_flags & USB_NO_FSBR)
-		return;
-
-	spin_lock_irqsave (&uhci->qh_lock, flags);
-	if (((urb_priv_t*)urb->hcpriv)->use_loop) {
-		uhci->loop_usage--;
-
-		if (!uhci->loop_usage) {
-			uhci->chain_end->hw.qh.head|=cpu_to_le32(UHCI_PTR_TERM);
-			mb();
-		}
-		((urb_priv_t*)urb->hcpriv)->use_loop=0;
-	}
-	spin_unlock_irqrestore (&uhci->qh_lock, flags);
-}
-/*-------------------------------------------------------------------*/
-static void queue_urb_unlocked (struct uhci_hcd *uhci, struct urb *urb)
-{
-	urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-	int type;
-	type=usb_pipetype (urb->pipe);
-	
-	if (high_bw && ((type == PIPE_BULK) || (type == PIPE_CONTROL)))
-			enable_desc_loop(uhci, urb);
-
-	urb->status = -EINPROGRESS;
-	priv->started=jiffies;
-
-	list_add (&priv->urb_list, &uhci->urb_list);
-	if (urb->timeout)
-		uhci->timeout_urbs++;
-	uhci_switch_timer_int(uhci);
-}
-/*-------------------------------------------------------------------*/
-static void queue_urb (struct uhci_hcd *uhci, struct urb *urb)
-{
-	unsigned long flags=0;
-
-	spin_lock_irqsave (&uhci->urb_list_lock, flags);
-	queue_urb_unlocked(uhci,urb);
-	spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-}
-/*-------------------------------------------------------------------*/
-static void dequeue_urb (struct uhci_hcd *uhci, struct urb *urb)
-{
-	urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-	int type;
-	dbg("dequeue URB %p",urb);
-	type=usb_pipetype (urb->pipe);
-
-	if (high_bw && ((type == PIPE_BULK) || (type == PIPE_CONTROL)))
-		disable_desc_loop(uhci, urb);
-
-	list_del (&priv->urb_list);
-	if (urb->timeout && uhci->timeout_urbs)
-		uhci->timeout_urbs--;
-
-}
-/*###########################################################################*/
-//                  INIT/FREE FRAME LAYOUT IN MEMORY
-/*###########################################################################*/
-
-// Removes ALL qhs in chain (paranoia!)
-static void cleanup_skel (struct uhci_hcd *uhci)
-{
-	unsigned int n;
-	uhci_desc_t *td;
-
-	dbg("cleanup_skel");
-
-	clean_descs(uhci,1);
-	dbg("clean_descs done");
-
-	if (uhci->td32ms) {	
-		unlink_td(uhci,uhci->td32ms,1);
-		delete_desc(uhci, uhci->td32ms);
-	}
-
-	if (uhci->td128ms) {	
-		unlink_td(uhci,uhci->td128ms,1);
-		delete_desc(uhci, uhci->td128ms);
-	}
-
-	for (n = 0; n < 8; n++) {
-		td = uhci->int_chain[n];
-		clean_td_chain (uhci, td);
-	}
-
-	if (uhci->iso_td) {
-		for (n = 0; n < 1024; n++) {
-			td = uhci->iso_td[n];
-			clean_td_chain (uhci, td);
-		}
-		kfree (uhci->iso_td);
-	}
-
-	if (uhci->framelist)
-		pci_free_consistent(uhci->uhci_pci, PAGE_SIZE,
-				    uhci->framelist, uhci->framelist_dma);
-
-	if (uhci->control_chain) {
-		// completed init_skel?
-		struct list_head *p;
-		uhci_desc_t *qh, *qh1;
-
-		qh = uhci->control_chain;
-		while ((p = qh->horizontal.next) != &qh->horizontal) {
-			qh1 = list_entry (p, uhci_desc_t, horizontal);
-			delete_qh (uhci, qh1);
-		}
-
-		delete_qh (uhci, qh);
-	}
-	else {
-		if (uhci->ls_control_chain)
-			delete_desc (uhci, uhci->ls_control_chain);
-		if (uhci->control_chain)
-			delete_desc (uhci, uhci->control_chain);
-		if (uhci->bulk_chain)
-			delete_desc (uhci, uhci->bulk_chain);
-		if (uhci->chain_end)
-			delete_desc (uhci, uhci->chain_end);
-	}
-
-	if (uhci->desc_pool) {
-		pci_pool_destroy(uhci->desc_pool);
-		uhci->desc_pool = NULL;
-	}
-
-	uhci->ls_control_chain = NULL;
-	uhci->control_chain = NULL;
-	uhci->bulk_chain = NULL;
-	uhci->chain_end = NULL;
-	for (n = 0; n < 8; n++)
-		uhci->int_chain[n] = NULL;
-	dbg("cleanup_skel finished");	
-}
-/*-------------------------------------------------------------------*/
-// allocates framelist and qh-skeletons
-// only HW-links provide continous linking, SW-links stay in their domain (ISO/INT)
-static int init_skel (struct uhci_hcd *uhci)
-{
-	int n, ret;
-	uhci_desc_t *qh, *td;
-	
-	init_dbg("init_skel");
-	
-	uhci->framelist = pci_alloc_consistent(uhci->uhci_pci, PAGE_SIZE,
-					    &uhci->framelist_dma);
-
-	if (!uhci->framelist)
-		return -ENOMEM;
-
-	memset (uhci->framelist, 0, 4096);
-
-	init_dbg("creating descriptor pci_pool");
-	uhci->desc_pool = pci_pool_create("uhci_desc", uhci->uhci_pci,
-				       sizeof(uhci_desc_t), 16, 0,
-				       GFP_DMA | GFP_ATOMIC);	
-	if (!uhci->desc_pool)
-		goto init_skel_cleanup;
-
-	init_dbg("allocating iso desc pointer list");
-	uhci->iso_td = (uhci_desc_t **) kmalloc (1024 * sizeof (uhci_desc_t*), GFP_KERNEL);
-	
-	if (!uhci->iso_td)
-		goto init_skel_cleanup;
-
-	uhci->ls_control_chain = NULL;
-	uhci->control_chain = NULL;
-	uhci->bulk_chain = NULL;
-	uhci->chain_end = NULL;
-	for (n = 0; n < 8; n++)
-		uhci->int_chain[n] = NULL;
-
-	init_dbg("allocating iso descs");
-	for (n = 0; n < 1024; n++) {
-	 	// allocate skeleton iso/irq-tds
-		if (alloc_td (uhci, &td, 0))
-			goto init_skel_cleanup;
-
-		uhci->iso_td[n] = td;
-		uhci->framelist[n] = cpu_to_le32((__u32) td->dma_addr);
-	}
-
-	init_dbg("allocating qh: chain_end");
-	if (alloc_qh (uhci, &qh))	
-		goto init_skel_cleanup;
-				
-	uhci->chain_end = qh;
-
-	if (alloc_td (uhci, &td, 0))
-		goto init_skel_cleanup;
-	
-	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand)
-	insert_td (uhci, qh, td, 0);
-	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM); // remove TERM bit
-	uhci->td1ms=td;
-
-	dbg("allocating qh: bulk_chain");
-	if (alloc_qh (uhci, &qh))
-		goto init_skel_cleanup;
-	
-	insert_qh (uhci, uhci->chain_end, qh, 0);
-	uhci->bulk_chain = qh;
-
-	dbg("allocating qh: control_chain");
-	if ((ret = alloc_qh (uhci, &qh)))
-		goto init_skel_cleanup;
-	
-	insert_qh (uhci, uhci->bulk_chain, qh, 0);
-	uhci->control_chain = qh;
-
-	// disabled reclamation loop
-	if (high_bw)
-		set_qh_head(uhci->chain_end, uhci->control_chain->dma_addr | UHCI_PTR_QH | UHCI_PTR_TERM);
-
-
-	init_dbg("allocating qh: ls_control_chain");
-	if (alloc_qh (uhci, &qh))
-		goto init_skel_cleanup;
-	
-	insert_qh (uhci, uhci->control_chain, qh, 0);
-	uhci->ls_control_chain = qh;
-
-	init_dbg("allocating skeleton INT-TDs");
-	
-	for (n = 0; n < 8; n++) {
-		uhci_desc_t *td;
-
-		if (alloc_td (uhci, &td, 0))
-			goto init_skel_cleanup;
-
-		uhci->int_chain[n] = td;
-		if (n == 0) {
-			set_td_link(uhci->int_chain[0], uhci->ls_control_chain->dma_addr | UHCI_PTR_QH);
-		}
-		else {
-			set_td_link(uhci->int_chain[n], uhci->int_chain[0]->dma_addr);
-		}
-	}
-
-	init_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,le32_to_cpu(uhci->framelist[n]));
-		if ((n&127)==127) 
-			((uhci_desc_t*) uhci->iso_td[n])->hw.td.link = cpu_to_le32(uhci->int_chain[0]->dma_addr);
-		else 
-			for (o = 1, m = 2; m <= 128; o++, m += m)
-				if ((n & (m - 1)) == ((m - 1) / 2))
-					set_td_link(((uhci_desc_t*) uhci->iso_td[n]), uhci->int_chain[o]->dma_addr);
-	}
-
-	if (alloc_td (uhci, &td, 0))
-		goto init_skel_cleanup;
-	
-	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt (activated later)
-	uhci->td32ms=td;
-	insert_td_horizontal (uhci, uhci->int_chain[5], td);
-
-	if (alloc_td (uhci, &td, 0))
-		goto init_skel_cleanup;
-	
-	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 128ms interrupt (activated later)
-	uhci->td128ms=td;
-	insert_td_horizontal (uhci, uhci->int_chain[7], td);
-
-	mb();
-	init_dbg("init_skel exit");
-	return 0;
-
-  init_skel_cleanup:
-	cleanup_skel (uhci);
-	return -ENOMEM;
-}
-/*###########################################################################*/
-//                 UHCI PRIVATE DATA
-/*###########################################################################*/
-
-urb_priv_t *uhci_alloc_priv(int mem_flags)
-{
-	urb_priv_t *p;
-#ifdef DEBUG_SLAB
-	p = kmem_cache_alloc(urb_priv_kmem, SLAB_FLAG);
-#else
-	p = kmalloc (sizeof (urb_priv_t), mem_flags);
-#endif
-	if (p) {
-		memset(p, 0, sizeof(urb_priv_t));
-		INIT_LIST_HEAD (&p->urb_list);
-	}
-	return p;
-}
-/*-------------------------------------------------------------------*/
-void uhci_free_priv(struct uhci_hcd *uhci, struct urb *urb, urb_priv_t* p)
-{
-		uhci_urb_dma_unmap(uhci, urb, p);
-#ifdef DEBUG_SLAB
-		err("free_priv %p",p);
-		kmem_cache_free(urb_priv_kmem, p);
-#else
-		kfree (p);
-#endif
-		urb->hcpriv = NULL;
-}
-
diff -Nru a/drivers/usb/host/usb-uhci-q.c b/drivers/usb/host/usb-uhci-q.c
--- a/drivers/usb/host/usb-uhci-q.c	Tue Jul 16 16:49:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1227 +0,0 @@
-/*  
-    UHCI HCD (Host Controller Driver) for USB, UHCI transfer processing
-    
-    (c) 1999-2002 
-    Georg Acher      +    Deti Fliegl    +    Thomas Sailer
-    georg@acher.org      deti@fliegl.de   sailer@ife.ee.ethz.ch
-   
-    with the help of
-    David Brownell, david-b@pacbell.net
-    Adam Richter, adam@yggdrasil.com
-    Roman Weissgaerber, weissg@vienna.at
-    
-    HW-initalization based on material of
-    Randy Dunlap + Johannes Erdfelt + Gregory P. Smith + Linus Torvalds 
-
-    $Id: usb-uhci-q.c,v 1.3 2002/05/25 16:42:41 acher Exp $
-*/
-
-/*-------------------------------------------------------------------*/
-static inline void finish_urb (struct uhci_hcd *uhci, struct urb *urb)
-{
-	if (urb->hcpriv) 
-		uhci_free_priv (uhci, urb, urb->hcpriv);
-	
-	usb_hcd_giveback_urb (&uhci->hcd, urb);
-}
-/*###########################################################################*/
-//                        URB SUBMISSION STUFF
-//     assembles QHs und TDs for control, bulk, interrupt  and isochronous
-/*###########################################################################*/
-
-// returns: 0 (no transfer queued), urb* (this urb already queued) 
-static struct urb* search_dev_ep (struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct list_head *p;
-	struct urb *tmp;
-	urb_priv_t *priv;
-	unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0);
-
-	p=uhci->urb_list.next;
-
-	for (; p != &uhci->urb_list; p = p->next) {
-		priv = list_entry (p,  urb_priv_t, urb_list);
-		tmp = priv->urb;
-		dbg("search_dev_ep 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_pipeisoc(urb->pipe) && (tmp->dev == urb->dev) && !((tmp->pipe ^ urb->pipe) & mask)) ||
-		    (urb == tmp))
-			return tmp;	// found another urb already queued for processing
-	}
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-
-static int uhci_submit_control_urb (struct uhci_hcd *uhci, struct urb *urb)
-{
-	uhci_desc_t *qh, *td;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	unsigned long destination, status;
-	int maxsze = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
-	int depth_first = ctrl_depth;  // UHCI descriptor chasing method
-	unsigned long len;
-	char *data;
-
-//	err("uhci_submit_control start, buf %p", urb->transfer_buffer);
-	if (alloc_qh (uhci, &qh))		// alloc qh for this request
-		return -ENOMEM;
-
-	if (alloc_td (uhci, &td, UHCI_PTR_DEPTH * depth_first))		// get td for setup stage
-		goto fail_unmap_enomem;
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
-	
-	status = TD_CTRL_ACTIVE
-		| (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD)
-		| (3 << 27);                      /* 3 errors */
-
-	if (urb->dev->speed == USB_SPEED_LOW)
-		status |= TD_CTRL_LS;
-
-	/*  Build the TD for the control request, try forever, 8 bytes of data */
-	fill_td (td, status, destination | (7 << 21), urb_priv->setup_packet_dma);
-
-	insert_td (uhci, qh, td, 0);	// queue 'setup stage'-td in qh
-#if 0
-	{
-		char *sp=urb->setup_packet;
-		dbg("SETUP to pipe %x: %x %x %x %x %x %x %x %x", urb->pipe,
-		    sp[0],sp[1],sp[2],sp[3],sp[4],sp[5],sp[6],sp[7]);
-	}
-	//uhci_show_td(td);
-#endif
-
-	len = urb->transfer_buffer_length;
-	data = urb->transfer_buffer;
-
-	/* If direction is "send", change the frame from SETUP (0x2D)
-	   to OUT (0xE1). Else change it from SETUP to IN (0x69). */
-
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | (usb_pipeout (urb->pipe)?USB_PID_OUT:USB_PID_IN);
-
-	while (len > 0) {
-		int pktsze = len;
-
-		if (alloc_td (uhci, &td, UHCI_PTR_DEPTH * depth_first))
-			goto fail_unmap_enomem;
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		destination ^= 1 << TD_TOKEN_TOGGLE;	// toggle DATA0/1
-
-		// Status, pktsze bytes of data
-		fill_td (td, status, destination | ((pktsze - 1) << 21),
-			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));
-
-		insert_td (uhci, qh, td, UHCI_PTR_DEPTH * depth_first);	// 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 &= ~UHCI_PID;
-
-	if (usb_pipeout (urb->pipe) || (urb->transfer_buffer_length == 0))
-		destination |= USB_PID_IN;
-	else
-		destination |= USB_PID_OUT;
-
-	destination |= 1 << TD_TOKEN_TOGGLE;	/* End in Data1 */
-
-	if (alloc_td (uhci, &td, UHCI_PTR_DEPTH))
-		goto fail_unmap_enomem;
-
-	status &=~TD_CTRL_SPD;
-
-	/* 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 (uhci, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue status td
-
-	list_add (&qh->desc_list, &urb_priv->desc_list);
-
-	queue_urb (uhci, urb);	// queue _before_ inserting in desc chain
-
-	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);
-
-	/* Start it up... put low speed first */
-	if (urb->dev->speed == USB_SPEED_LOW)
-		insert_qh (uhci, uhci->control_chain, qh, 0);
-	else
-		insert_qh (uhci, uhci->bulk_chain, qh, 0);
-
-	return 0;
-
-fail_unmap_enomem:
-	delete_qh(uhci, qh);
-	return -ENOMEM;
-}
-/*-------------------------------------------------------------------*/
-// For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh)
-// Due to the linking with other bulk urbs, it has to be locked with urb_list_lock!
-
-static int uhci_submit_bulk_urb (struct uhci_hcd *uhci, struct urb *urb, struct urb *bulk_urb)
-{
-	urb_priv_t *urb_priv = urb->hcpriv, *upriv, *bpriv=NULL;
-	uhci_desc_t *qh, *td, *nqh=NULL, *bqh=NULL, *first_td=NULL;
-	unsigned long destination, status;
-	char *data;
-	unsigned int pipe = urb->pipe;
-	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
-	int info, len, last;
-	int depth_first = bulk_depth;  // UHCI descriptor chasing method
-
-	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
-		return -EPIPE;
-
-	queue_dbg("uhci_submit_bulk_urb: urb %p, old %p, pipe %08x, len %i",
-		  urb,bulk_urb,urb->pipe,urb->transfer_buffer_length);
-
-	upriv = (urb_priv_t*)urb->hcpriv;
-
-	if (!bulk_urb) {
-		if (alloc_qh (uhci, &qh))		// get qh for this request
-			return -ENOMEM;
-
-		if (urb->transfer_flags & USB_QUEUE_BULK) {
-			if (alloc_qh(uhci, &nqh)) // placeholder for clean unlink
-				goto fail_unmap_enomem;
-			upriv->next_qh = nqh;
-			queue_dbg("new next qh %p",nqh);
-		}
-	}
-	else { 
-		bpriv = (urb_priv_t*)bulk_urb->hcpriv;
-		qh = bpriv->bottom_qh;  // re-use bottom qh and next qh
-		nqh = bpriv->next_qh;
-		upriv->next_qh=nqh;	
-		upriv->prev_queued_urb=bulk_urb;
-	}
-
-	if (urb->transfer_flags & USB_QUEUE_BULK) {
-		if (alloc_qh (uhci, &bqh))  // "bottom" QH
-			goto fail_unmap_enomem;
-
-		set_qh_element(bqh, UHCI_PTR_TERM);
-		set_qh_head(bqh, nqh->dma_addr | UHCI_PTR_QH); // element
-		upriv->bottom_qh = bqh;
-	}
-	queue_dbg("uhci_submit_bulk: qh %p bqh %p nqh %p",qh, bqh, nqh);
-
-	/* The "pipe" thing contains the destination in bits 8--18. */
-	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
-	
-	status = TD_CTRL_ACTIVE
-		| ((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD)
-		| (3 << 27);                   /* 3 errors */
-
-	if (urb->dev->speed == USB_SPEED_LOW)
-		status |= TD_CTRL_LS;
-
-	/* Build the TDs for the bulk request */
-	len = urb->transfer_buffer_length;
-	data = urb->transfer_buffer;
-	
-	do {					// TBD: Really allow zero-length packets?
-		int pktsze = len;
-
-		if (alloc_td (uhci, &td, UHCI_PTR_DEPTH * depth_first))
-			goto fail_unmap_enomem;
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		// pktsze bytes of data 
-		info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) |
-			(uhci_get_toggle (urb) << TD_TOKEN_TOGGLE);
-
-		fill_td (td, status, info,
-			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));
-
-		data += pktsze;
-		len -= pktsze;
-		// Use USB_ZERO_PACKET to finish bulk OUTs always with a zero length packet
-		last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || !(urb->transfer_flags & USB_ZERO_PACKET)));
-
-		if (last)
-			set_td_ioc(td);	// last one generates INT
-
-		insert_td (uhci, qh, td, UHCI_PTR_DEPTH * depth_first);
-		if (!first_td)
-			first_td=td;
-		uhci_do_toggle (urb);
-
-	} while (!last);
-
-	if (bulk_urb && bpriv)   // everything went OK, link with old bulk URB
-		bpriv->next_queued_urb=urb;
-
-	list_add (&qh->desc_list, &urb_priv->desc_list);
-
-	if (urb->transfer_flags & USB_QUEUE_BULK)
-		append_qh(uhci, td, bqh, UHCI_PTR_DEPTH * depth_first);
-
-	queue_urb_unlocked (uhci, urb);
-	
-	if (urb->transfer_flags & USB_QUEUE_BULK)
-		set_qh_element(qh, first_td->dma_addr);
-	else
-		qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);    // arm QH
-
-	if (!bulk_urb) { 					// new bulk queue	
-		if (urb->transfer_flags & USB_QUEUE_BULK) {
-			spin_lock (&uhci->td_lock);		// both QHs in one go
-			insert_qh (uhci, uhci->chain_end, qh, 0);	// Main QH
-			insert_qh (uhci, uhci->chain_end, nqh, 0);	// Helper QH
-			spin_unlock (&uhci->td_lock);
-		}
-		else
-			insert_qh (uhci, uhci->chain_end, qh, 0);
-	}
-	
-	//dbg("uhci_submit_bulk_urb: exit\n");
-	return 0;
-
-fail_unmap_enomem:
-	delete_qh(uhci, qh);
-	if (bqh) 
-		delete_qh(uhci, bqh);
-	if (!bulk_urb && nqh)
-		delete_qh(uhci, nqh);
-
-	return -ENOMEM;
-}
-/*---------------------------------------------------------------------------*/
-// submits USB interrupt (ie. polling ;-) 
-// ASAP-flag set implicitely
-// if period==0, the transfer is only done once
-
-static int uhci_submit_int_urb (struct uhci_hcd *uhci, struct urb *urb)
-{
-	urb_priv_t *urb_priv = urb->hcpriv;
-	int nint;
-	uhci_desc_t *td;
-	int status, destination;
-	int info;
-	unsigned int pipe = urb->pipe;
-	
-	if (urb->interval == 0)
-		nint = 0;
-	else {  
-		// log2-function (urb->interval already 2^n)
-		nint = ffs(urb->interval);
-		if (nint>7)
-			nint=7;
-	}
-
-	dbg("INT-interval %i, chain  %i", urb->interval, nint);
-	// remember start frame, just in case...
-	urb->start_frame = UHCI_GET_CURRENT_FRAME (uhci) & 1023;	
-
-	urb->number_of_packets = 1;  // INT allows only one packet
-	
-	if (alloc_td (uhci, &td, UHCI_PTR_DEPTH))
-		return -ENOMEM;
-
-	status = TD_CTRL_ACTIVE | TD_CTRL_IOC
-		| (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD)
-		| (3 << 27);
-
-	if (urb->dev->speed == USB_SPEED_LOW)
-		status |= TD_CTRL_LS;
-
-	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe) |
-		(((urb->transfer_buffer_length - 1) & 0x7ff) << 21);
-
-	info = destination | (uhci_get_toggle (urb) << TD_TOKEN_TOGGLE);
-	fill_td (td, status, info, urb_priv->transfer_buffer_dma);
-	list_add_tail (&td->desc_list, &urb_priv->desc_list);
-	queue_urb (uhci, urb);
-	insert_td_horizontal (uhci, uhci->int_chain[nint], td);	// store in INT-TDs
-	uhci_do_toggle (urb);
-
-	return 0;
-}
-/*###########################################################################*/
-//                  ISOCHRONOUS TRANSFERS
-/*###########################################################################*/
-
-// 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 (struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end)
-{
-	struct urb *u, *last_urb = NULL;
-	urb_priv_t *priv;
-	struct list_head *p;
-	int ret=-1;
-	unsigned long flags;
-	
-	spin_lock_irqsave (&uhci->urb_list_lock, flags);
-	p=uhci->urb_list.prev;
-
-	for (; p != &uhci->urb_list; p = p->prev) {
-		priv = list_entry (p, urb_priv_t, urb_list);
-		u = priv->urb;
-		// look for pending URBs with identical pipe handle
-		// works only because iso doesn't toggle the data bit!
-		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS)) {
-			if (!last_urb)
-				*start = u->start_frame;
-			last_urb = u;
-		}
-	}
-	
-	if (last_urb) {
-		*end = (last_urb->start_frame + last_urb->number_of_packets*last_urb->interval) & 1023;
-		ret=0;
-	}
-	
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-	
-	return ret;
-}
-/*-------------------------------------------------------------------*/
-// adjust start_frame according to scheduling constraints (ASAP etc)
-
-static int iso_find_start (struct uhci_hcd *uhci, struct urb *urb)
-{
-	unsigned int now;
-	unsigned int start_limit = 0, stop_limit = 0, queued_size, number_of_frames;
-	int limits;
-
-	now = UHCI_GET_CURRENT_FRAME (uhci) & 1023;
-
-	number_of_frames = (unsigned) (urb->number_of_packets*urb->interval);
-
-	if ( number_of_frames > 900)
-		return -EFBIG;
-	
-	limits = find_iso_limits (uhci, urb, &start_limit, &stop_limit);
-	queued_size = (stop_limit - start_limit) & 1023;
-
-	if (urb->transfer_flags & USB_ISO_ASAP) {
-		// first iso
-		if (limits) {
-			// 10ms setup should be enough //FIXME!
-			urb->start_frame = (now + 10) & 1023;
-		}
-		else {
-			urb->start_frame = stop_limit;		// seamless linkage
-
-			if (((now - urb->start_frame) & 1023) <= (unsigned) number_of_frames) {
-				info("iso_find_start: gap in seamless isochronous scheduling");
-				dbg("iso_find_start: now %u start_frame %u number_of_packets %u interval %u pipe 0x%08x",
-					now, urb->start_frame, urb->number_of_packets, urb->interval, urb->pipe);
-				urb->start_frame = (now + 5) & 1023;	// 5ms setup should be enough
-			}
-		}
-	}
-	else {
-		urb->start_frame &= 1023;
-		if (((now - urb->start_frame) & 1023) < number_of_frames) {
-			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 (((urb->start_frame - start_limit) & 1023) < queued_size ||
-	    ((urb->start_frame + number_of_frames - 1 - start_limit) & 1023) < queued_size) {
-		dbg("iso_find_start: start_frame %u number_of_packets %u start_limit %u stop_limit %u",
-			urb->start_frame, urb->number_of_packets, start_limit, stop_limit);
-		return -EAGAIN;
-	}
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-static int uhci_submit_iso_urb (struct uhci_hcd *uhci, struct urb *urb, int mem_flags)
-{
-	urb_priv_t *urb_priv = urb->hcpriv;
-	int n=0, i, ret, last=0;
-	uhci_desc_t *td, **tdm;
-	int status, destination;
-	unsigned long flags;
-
-	tdm = (uhci_desc_t **) kmalloc (urb->number_of_packets * sizeof (uhci_desc_t*), mem_flags);
-
-	if (!tdm) 
-		return -ENOMEM;
-
-	memset(tdm, 0, urb->number_of_packets * sizeof (uhci_desc_t*));
-
-	// First try to get all TDs. Cause: Removing already inserted TDs can only be done 
-	// racefree in three steps: unlink TDs, wait one frame, delete TDs. 
-	// So, this solutions seems simpler...
-
-	for (n = 0; n < urb->number_of_packets; n++) {
-		dbg("n:%d urb->iso_frame_desc[n].length:%d", n, urb->iso_frame_desc[n].length);
-		if (!urb->iso_frame_desc[n].length)
-			continue;  // allows ISO striping by setting length to zero in iso_descriptor
-		
-		if (alloc_td (uhci, &td, UHCI_PTR_DEPTH)) {
-			ret = -ENOMEM;
-			goto fail_unmap_tds;
-		}
-		
-		last=n;
-		tdm[n] = td;
-	}
-
-	__save_flags(flags);
-	__cli();		      // Disable IRQs to schedule all ISO-TDs in time
-	ret = iso_find_start (uhci, urb);	// adjusts urb->start_frame for later use
-	
-	if (ret) {
-		__restore_flags(flags);
-		n = urb->number_of_packets;
-		goto fail_unmap_tds;
-	}
-
-	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
-
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe);
-
-	// Queue all allocated TDs
-	for (n = 0; n < urb->number_of_packets; n++) {
-		td = tdm[n];
-		if (!td)
-			continue;
-			
-		if (n  == last) {
-			status |= TD_CTRL_IOC;
-			queue_urb (uhci, urb);
-		}
-
-		fill_td (td, status, destination | (((urb->iso_frame_desc[n].length - 1) & 0x7ff) << 21),
-			 urb_priv->transfer_buffer_dma + urb->iso_frame_desc[n].offset);
-		list_add_tail (&td->desc_list, &urb_priv->desc_list);
-	
-		insert_td_horizontal (uhci, uhci->iso_td[(urb->start_frame + n*urb->interval) & 1023], td);	// store in iso-tds
-	}
-
-	kfree (tdm);
-	dbg("ISO-INT# %i, start %i, now %i", urb->number_of_packets, urb->start_frame, UHCI_GET_CURRENT_FRAME (uhci) & 1023);
-	ret = 0;
-
-	__restore_flags(flags);
-	return ret;	
-
-	// Cleanup allocated TDs
-fail_unmap_tds:
-	dbg("ISO failed, free %i, ret %i",n,ret);
-	for (i = 0; i < n; i++)
-		if (tdm[i])
-			delete_desc(uhci, tdm[i]);
-	kfree (tdm);
-	return ret;
-}
-/*###########################################################################*/
-//                        URB UNLINK PROCESSING
-/*###########################################################################*/
-
-static void uhci_clean_iso_step1(struct uhci_hcd *uhci, urb_priv_t *urb_priv)
-{
-	struct list_head *p;
-	uhci_desc_t *td;
-	dbg("uhci_clean_iso_step1");
-	for (p = urb_priv->desc_list.next; p != &urb_priv->desc_list; p = p->next) {
-				td = list_entry (p, uhci_desc_t, desc_list);
-				unlink_td (uhci, td, 1);
-	}
-}
-/*-------------------------------------------------------------------*/
-/* mode: CLEAN_TRANSFER_NO_DELETION: unlink but no deletion mark (step 1 of async_unlink)
-         CLEAN_TRANSFER_REGULAR: regular (unlink/delete-mark)
-         CLEAN_TRANSFER_DELETION_MARK: deletion mark for QH (step 2 of async_unlink)
- looks a bit complicated because of all the bulk queueing goodies
-*/
-
-static void uhci_clean_transfer (struct uhci_hcd *uhci, struct urb *urb, uhci_desc_t *qh, int mode)
-{
-	uhci_desc_t *bqh, *nqh, *prevqh, *prevtd;
-	urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-	int now=UHCI_GET_CURRENT_FRAME(uhci);
-
-	bqh=priv->bottom_qh;	
-	
-	if (!priv->next_queued_urb)  { // no more appended bulk queues
-
-		queue_dbg("uhci_clean_transfer: No more bulks for urb %p, qh %p, bqh %p, nqh %p", 
-			  urb, qh, bqh, priv->next_qh);	
-	
-		if (priv->prev_queued_urb && mode != CLEAN_TRANSFER_DELETION_MARK) {  // qh not top of the queue
-				unsigned long flags; 
-				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
-
-				spin_lock_irqsave (&uhci->qh_lock, flags);
-				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
-				prevtd = list_entry (prevqh->vertical.prev, uhci_desc_t, vertical);
-				set_td_link(prevtd, priv->bottom_qh->dma_addr | UHCI_PTR_QH); // skip current qh
-				mb();
-				queue_dbg("uhci_clean_transfer: relink pqh %p, ptd %p",prevqh, prevtd);
-				spin_unlock_irqrestore (&uhci->qh_lock, flags);
-
-				ppriv->bottom_qh = priv->bottom_qh;
-				ppriv->next_queued_urb = NULL;
-			}
-		else {   // queue is dead, qh is top of the queue
-			
-			if (mode != CLEAN_TRANSFER_DELETION_MARK) 				
-				unlink_qh(uhci, qh); // remove qh from horizontal chain
-
-			if (bqh) {  // remove remainings of bulk queue
-				nqh=priv->next_qh;
-
-				if (mode != CLEAN_TRANSFER_DELETION_MARK) 
-					unlink_qh(uhci, nqh);  // remove nqh from horizontal chain
-				
-				if (mode != CLEAN_TRANSFER_NO_DELETION) {  // add helper QHs to free desc list
-					nqh->last_used = bqh->last_used = now;
-					list_add_tail (&nqh->horizontal, &uhci->free_desc_qh);
-					list_add_tail (&bqh->horizontal, &uhci->free_desc_qh);
-				}			
-			}
-		}
-	}
-	else { // there are queued urbs following
-	
-	  queue_dbg("uhci_clean_transfer: urb %p, prevurb %p, nexturb %p, qh %p, bqh %p, nqh %p",
-		       urb, priv->prev_queued_urb,  priv->next_queued_urb, qh, bqh, priv->next_qh);	
-       	
-		if (mode != CLEAN_TRANSFER_DELETION_MARK) {	// no work for cleanup at unlink-completion
-			struct urb *nurb;
-			unsigned long flags;
-
-			nurb = priv->next_queued_urb;
-			spin_lock_irqsave (&uhci->qh_lock, flags);		
-
-			if (!priv->prev_queued_urb) { // top QH
-				
-				prevqh = list_entry (qh->horizontal.prev, uhci_desc_t, horizontal);
-				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
-				list_del (&qh->horizontal);  // remove this qh from horizontal chain
-				list_add (&bqh->horizontal, &prevqh->horizontal); // insert next bqh in horizontal chain
-			}
-			else {		// intermediate QH
-				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
-				urb_priv_t* npriv=(urb_priv_t*)nurb->hcpriv;
-				uhci_desc_t * bnqh;
-				
-				bnqh = list_entry (npriv->desc_list.next, uhci_desc_t, desc_list);
-				ppriv->bottom_qh = bnqh;
-				ppriv->next_queued_urb = nurb;				
-				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
-				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
-			}
-
-			mb();
-			((urb_priv_t*)nurb->hcpriv)->prev_queued_urb=priv->prev_queued_urb;
-			spin_unlock_irqrestore (&uhci->qh_lock, flags);
-		}		
-	}
-
-	if (mode != CLEAN_TRANSFER_NO_DELETION) {
-		qh->last_used = now;	
-		list_add_tail (&qh->horizontal, &uhci->free_desc_qh); // mark qh for later deletion/kfree
-	}
-}
-
-/*-------------------------------------------------------------------*/
-// async unlink_urb completion/cleanup work
-// has to be protected by urb_list_lock!
-// features: if set in transfer_flags, the resulting status of the killed
-// transaction is not overwritten
-
-static void uhci_cleanup_unlink(struct uhci_hcd *uhci, int force)
-{
-	struct list_head *q;
-	struct urb *urb;
-	urb_priv_t *urb_priv;
-	int type, now = UHCI_GET_CURRENT_FRAME(uhci);
-
-	q = uhci->urb_unlinked.next;
-
-	while (q != &uhci->urb_unlinked) {
-		urb_priv = list_entry (q, urb_priv_t, urb_list);
-		urb = urb_priv->urb;
-
-		q = urb_priv->urb_list.next;
-					
-		if (force || ((urb_priv->started != ~0) && (urb_priv->started != now))) {
-			async_dbg("async cleanup %p",urb);
-			type=usb_pipetype (urb->pipe);
-
-			switch (type) { // process descriptors
-			case PIPE_CONTROL:
-//				usb_show_device(urb->dev);
-				process_transfer (uhci, urb, CLEAN_TRANSFER_DELETION_MARK);  // don't unlink (already done)
-//				usb_show_device(urb->dev);
-				break;
-			case PIPE_BULK:
-				if (!uhci->avoid_bulk.counter)
-					process_transfer (uhci, urb, CLEAN_TRANSFER_DELETION_MARK); // don't unlink (already done)
-				else
-					continue;
-				break;
-			case PIPE_ISOCHRONOUS:
-				process_iso (uhci, urb, PROCESS_ISO_FORCE); // force, don't unlink
-				break;
-			case PIPE_INTERRUPT:
-				process_interrupt (uhci, urb, PROCESS_INT_REMOVE);
-				break;
-			}
-			
-			list_del (&urb_priv->urb_list);			
-			uhci_urb_dma_sync(uhci, urb, urb_priv);
-			// clean up descriptors for INT/ISO
-//			if (type==PIPE_ISOCHRONOUS || type==PIPE_INTERRUPT) 
-//				uhci_clean_iso_step2(uhci, urb_priv);
-	
-			uhci_free_priv(uhci, urb, urb_priv);		
-
-			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
-				urb->status = -ENOENT;  // now the urb is really dead
-
-			spin_unlock(&uhci->urb_list_lock);
-			usb_hcd_giveback_urb(&uhci->hcd, urb);
-			spin_lock(&uhci->urb_list_lock);
-		}
-	}
-}
-/*-------------------------------------------------------------------*/
-/* needs urb_list_lock!
-   mode: UNLINK_ASYNC_STORE_URB: unlink and move URB into unlinked list
-         UNLINK_ASYNC_DONT_STORE: unlink, don't move URB into unlinked list
-*/
-static int uhci_unlink_urb_async (struct uhci_hcd *uhci, struct urb *urb, int mode)
-{
-	uhci_desc_t *qh;
-	urb_priv_t *urb_priv;
-	
-	async_dbg("unlink_urb_async called %p",urb);
-	urb_priv = (urb_priv_t*)urb->hcpriv;
-	if (urb_priv==0) {
-		err("hc_priv for URB %p is zero!",urb);
-		return -EINVAL;
-	}
-	urb_priv->started = ~0;  // mark
-	dequeue_urb (uhci, urb);
-
-	if (mode==UNLINK_ASYNC_STORE_URB)
-		list_add_tail (&urb_priv->urb_list, &uhci->urb_unlinked); // store urb
-
-	uhci_switch_timer_int(uhci);
-	uhci->unlink_urb_done = 1;
-
-	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_INTERRUPT:
-		urb_priv->flags = 0; // mark as deleted (if called from completion)
-		uhci_do_toggle (urb);
-
-	case PIPE_ISOCHRONOUS:
-		uhci_clean_iso_step1 (uhci, urb_priv);
-		break;
-
-	case PIPE_BULK:
-	case PIPE_CONTROL:
-		qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
-		uhci_clean_transfer (uhci, urb, qh, CLEAN_TRANSFER_NO_DELETION);
-		break;
-	}
-	urb_priv->started = UHCI_GET_CURRENT_FRAME(uhci);
-	return 0;  // completion will follow
-}
-/*-------------------------------------------------------------------*/
-// unlink urbs for specific device or all devices
-static void uhci_unlink_urbs(struct uhci_hcd *uhci, struct usb_device *usb_dev, int remove_all)
-{
-	struct list_head *p;
-	struct list_head *p2;
-	struct urb *urb;
-	urb_priv_t *priv;
-	unsigned long flags;
-
-	spin_lock_irqsave (&uhci->urb_list_lock, flags);
-	p = uhci->urb_list.prev;	
-	while (p != &uhci->urb_list) {
-		p2 = p;
-		p = p->prev;
-		priv = list_entry (p2, urb_priv_t, urb_list);
-		urb = priv->urb;
-
-//		err("unlink urb: %p, dev %p, ud %p", urb, usb_dev,urb->dev);
-		
-		if (remove_all || (usb_dev == urb->dev)) {
-			spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-			err("forced removing of queued URB %p due to disconnect",urb);
-			uhci_urb_dequeue(&uhci->hcd, urb);
-			urb->dev = NULL; // avoid further processing of this URB
-			spin_lock_irqsave (&uhci->urb_list_lock, flags);
-			p = uhci->urb_list.prev;	
-		}
-	}
-	spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-} 
-/*-------------------------------------------------------------------*/
-
-// Checks for URB timeout and removes bandwidth reclamation if URB idles too long
-static void uhci_check_timeouts(struct uhci_hcd *uhci)
-{
-	struct list_head *p,*p2;
-	struct urb *urb;
-	int type;	
-	
-	p = uhci->urb_list.prev;	
-
-	while (p != &uhci->urb_list) {
-		urb_priv_t *hcpriv;
-
-		p2 = p;
-		p = p->prev;
-		hcpriv = list_entry (p2,  urb_priv_t, urb_list);
-		urb = hcpriv->urb;
-		type = usb_pipetype (urb->pipe);
-
-		if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
-			urb->transfer_flags |= USB_TIMEOUT_KILLED;
-			async_dbg("uhci_check_timeout: timeout for %p",urb);
-			uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
-		}
-		else if (high_bw && ((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
-			 (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))
-			disable_desc_loop(uhci, urb);
-	}
-	uhci->timeout_check=jiffies;
-}
-/*###########################################################################*/
-//                        INTERRUPT PROCESSING ROUTINES
-/*###########################################################################*/
-/*
- * 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 0;
-	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 -EOVERFLOW;
-	if (status & TD_CTRL_DBUFERR)	/* Buffer error */
-		return -ENOSR;
-	if (status & TD_CTRL_STALLED)	/* Stalled */
-		return -EPIPE;
-	if (status & TD_CTRL_ACTIVE)	/* Active */
-		return 0;
-
-	return -EPROTO;
-}
-/*-------------------------------------------------------------------*/
-static void correct_data_toggles(struct urb *urb)
-{
-	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), 
-		       !uhci_get_toggle (urb));
-
-	while(urb) {
-		urb_priv_t *priv=urb->hcpriv;		
-		uhci_desc_t *qh = list_entry (priv->desc_list.next, uhci_desc_t, desc_list);
-		struct list_head *p = qh->vertical.next;
-		uhci_desc_t *td;
-		dbg("URB to correct %p\n", urb);
-	
-		for (; p != &qh->vertical; p = p->next) {
-			td = list_entry (p, uhci_desc_t, vertical);
-			td->hw.td.info^=cpu_to_le32(1<<TD_TOKEN_TOGGLE);
-		}
-		urb=priv->next_queued_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.
- * mode: PROCESS_TRANSFER_REGULAR: regular (unlink QH)
- *       PROCESS_TRANSFER_DONT_UNLINK: QHs already unlinked (for async unlink_urb)
- */
-
-static int process_transfer (struct uhci_hcd *uhci, struct urb *urb, int mode)
-{
-	urb_priv_t *urb_priv = urb->hcpriv;
-	struct list_head *qhl = urb_priv->desc_list.next;
-	uhci_desc_t *qh = list_entry (qhl, uhci_desc_t, desc_list);
-	struct list_head *p = qh->vertical.next;
-	uhci_desc_t *desc= list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
-	uhci_desc_t *last_desc = list_entry (desc->vertical.prev, uhci_desc_t, vertical);
-	int data_toggle = uhci_get_toggle (urb);	// save initial data_toggle
-	int maxlength; 	// extracted and remapped info from TD
-	int actual_length;
-	int status = 0, ret = 0;
-
-	//dbg("process_transfer: urb %p, urb_priv %p, qh %p last_desc %p\n",urb,urb_priv, qh, last_desc);
-
-	/* 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 (urb_priv->flags && 
-	    ((qh->hw.qh.element == cpu_to_le32(UHCI_PTR_TERM)) || !is_td_active(desc)))
-		goto transfer_finished;
-
-	urb->actual_length=0;
-
-	for (; p != &qh->vertical; p = p->next) {
-		desc = list_entry (p, uhci_desc_t, vertical);
-
-		if (is_td_active(desc)) {	// do not process active TDs
-			if (mode == CLEAN_TRANSFER_DELETION_MARK) // if called from async_unlink
-				uhci_clean_transfer(uhci, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
-			return ret;
-		}
-	
-		actual_length = uhci_actual_length(desc);		// extract transfer parameters from TD
-		maxlength = (((le32_to_cpu(desc->hw.td.info) >> 21) & 0x7ff) + 1) & 0x7ff;
-		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
-
-		if (status == -EPIPE) { 		// see if EP is stalled
-			// set up stalled condition
-			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-		}
-
-		if (status && (status != -EPIPE) && (status != -EOVERFLOW)) {	
-			// if any error occurred stop processing of further TDs
-			// only set ret if status returned an error
-			ret = status;
-			urb->error_count++;
-			break;
-		}
-		else if ((le32_to_cpu(desc->hw.td.info) & 0xff) != USB_PID_SETUP)
-			urb->actual_length += actual_length;
-
-		// got less data than requested
-		if ( (actual_length < maxlength)) {
-			if (urb->transfer_flags & USB_DISABLE_SPD) {
-				status = -EREMOTEIO;	// 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 (urb->pipe) == PIPE_CONTROL)) {
-				if (uhci_packetid(le32_to_cpu(last_desc->hw.td.info)) == USB_PID_OUT) {
-			
-					set_qh_element(qh, last_desc->dma_addr);  // re-trigger status stage
-					dbg("short packet during control transfer, retrigger status stage @ %p",last_desc);
-					urb_priv->flags = 1; // mark as short control packet
-					return 0;
-				}
-			}
-			// all other cases: short read is OK
-			data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info));
-			break;
-		}
-		else if (status) {
-			ret = status;
-			urb->error_count++;
-			break;
-		}
-
-		data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info));
-		queue_dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", 
-			  actual_length, le32_to_cpu(desc->hw.td.status),status, data_toggle);      
-
-	}
-
-	/* toggle correction for short bulk transfers (nonqueued/queued) */
-	if (usb_pipetype (urb->pipe) == PIPE_BULK ) {  
-
-		urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-		struct urb *next_queued_urb=priv->next_queued_urb;
-
-		if (next_queued_urb) {
-			urb_priv_t *next_priv=(urb_priv_t*)next_queued_urb->hcpriv;
-			uhci_desc_t *qh = list_entry (next_priv->desc_list.next, uhci_desc_t, desc_list);
-			uhci_desc_t *first_td=list_entry (qh->vertical.next, uhci_desc_t, vertical);
-
-			if (data_toggle == uhci_toggle (le32_to_cpu(first_td->hw.td.info))) {
-				err("process_transfer: fixed toggle");
-				correct_data_toggles(next_queued_urb);
-			}						
-		}
-		else
-			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), !data_toggle);		
-	}
-
- transfer_finished:
-    
-	uhci_clean_transfer(uhci, urb, qh, mode);
-	urb->status = status;
-
-	if (high_bw)
-		disable_desc_loop(uhci,urb);
-
-	dbg("process_transfer: (end) urb %p, wanted len %d, len %d status %x err %d",
-		urb,urb->transfer_buffer_length,urb->actual_length, urb->status, urb->error_count);
-	return ret;
-}
-/*-------------------------------------------------------------------*/
-static int process_interrupt (struct uhci_hcd *uhci, struct urb *urb, int mode)
-{
-	urb_priv_t *urb_priv = urb->hcpriv;
-	struct list_head *p = urb_priv->desc_list.next;
-	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
-	int actual_length, status = 0, i, ret = -EINPROGRESS;
-
-	//dbg("urb contains interrupt request");
-
-	for (i = 0; p != &urb_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 (is_td_active(desc) || !(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) {
-			// do not process active TDs or one-shot TDs (->no recycling)
-			//dbg("TD ACT Status @%p %08x",desc,le32_to_cpu(desc->hw.td.status));
-			break;
-		}
-	
-		// extract transfer parameters from TD
-		actual_length = uhci_actual_length(desc);
-		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
-
-		// see if EP is stalled
-		if (status == -EPIPE) {
-			// set up stalled condition
-			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-		}
-
-		// if any error occurred: ignore this td, and continue
-		if (status != 0) {
-			//uhci_show_td (desc);
-			urb->error_count++;
-			goto recycle;
-		}
-		else
-			urb->actual_length = actual_length;
-
-	recycle:
-		((urb_priv_t*)urb->hcpriv)->flags=1; // set to detect unlink during completion
-
-		uhci_urb_dma_sync(uhci, urb, urb->hcpriv);
-		if (urb->complete) {
-			//dbg("process_interrupt: calling completion, status %i",status);
-			urb->status = status;
-			spin_unlock(&uhci->urb_list_lock);
-			urb->complete ((struct urb *) urb);
-			spin_lock(&uhci->urb_list_lock);
-		}
-		
-		if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) &&
-			    (urb->status != -ENOENT) && ((urb_priv_t*)urb->hcpriv)->flags) {
-
-			urb->status = -EINPROGRESS;
-
-			// Recycle INT-TD if interval!=0, else mark TD as one-shot
-			if (urb->interval) {
-				
-				desc->hw.td.info &= cpu_to_le32(~(1 << TD_TOKEN_TOGGLE));
-				if (status==0) {
-					((urb_priv_t*)urb->hcpriv)->started=jiffies;
-					desc->hw.td.info |= cpu_to_le32((uhci_get_toggle (urb) << TD_TOKEN_TOGGLE));
-					uhci_do_toggle (urb);
-				} else {
-					desc->hw.td.info |= cpu_to_le32((!uhci_get_toggle (urb) << TD_TOKEN_TOGGLE));
-				}
-				desc->hw.td.status= cpu_to_le32(TD_CTRL_ACTIVE | TD_CTRL_IOC |
-					(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27));
-				if (urb->dev->speed == USB_SPEED_LOW)
-					desc->hw.td.status |=
-					    __constant_cpu_to_le32 (TD_CTRL_LS);
-				mb();
-			}
-			else {
-				uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
-				uhci_do_toggle (urb); // correct toggle after unlink
-				clr_td_ioc(desc);    // inactivate TD
-			}
-		}
-		if (mode == PROCESS_INT_REMOVE) {
-			INIT_LIST_HEAD(&desc->horizontal);
-			list_add_tail (&desc->horizontal, &uhci->free_desc_td);
-			desc->last_used=UHCI_GET_CURRENT_FRAME(uhci);
-		}
-	}
-
-	return ret;
-}
-/*-------------------------------------------------------------------*/
-// mode: PROCESS_ISO_REGULAR: processing only for done TDs, unlink TDs
-// mode: PROCESS_ISO_FORCE: force processing, don't unlink TDs (already unlinked)
-
-static int process_iso (struct uhci_hcd *uhci, struct urb *urb, int mode)
-{
-       	urb_priv_t *urb_priv = urb->hcpriv;
-	struct list_head *p = urb_priv->desc_list.next, *p_tmp;
-	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
-	int i, ret = 0;
-	int now=UHCI_GET_CURRENT_FRAME(uhci);
-
-	dbg("urb contains iso request");
-	if (is_td_active(desc) && mode==PROCESS_ISO_REGULAR)
-		return -EXDEV;	// last TD not finished
-
-	urb->error_count = 0;
-	urb->actual_length = 0;
-	urb->status = 0;
-	dbg("process iso urb %p, %li, %i, %i, %i %08x",urb,jiffies,UHCI_GET_CURRENT_FRAME(s),
-	    urb->number_of_packets,mode,le32_to_cpu(desc->hw.td.status));
-
-	for (i = 0; p != &urb_priv->desc_list;  i++) {
-		desc = list_entry (p, uhci_desc_t, desc_list);
-		
-		//uhci_show_td(desc);
-		if (is_td_active(desc)) {
-			// means we have completed the last TD, but not the TDs before
-			desc->hw.td.status &= cpu_to_le32(~TD_CTRL_ACTIVE);
-			dbg("TD still active (%x)- grrr. paranoia!", le32_to_cpu(desc->hw.td.status));
-			ret = -EXDEV;
-			urb->iso_frame_desc[i].status = ret;
-			unlink_td (uhci, desc, 1); 
-			goto err;
-		}
-
-		if (mode == PROCESS_ISO_REGULAR)
-			unlink_td (uhci, desc, 1);
-
-		if (urb->number_of_packets <= i) {
-			dbg("urb->number_of_packets (%d)<=(%d)", urb->number_of_packets, i);
-			ret = -EINVAL;
-			goto err;
-		}
-
-		urb->iso_frame_desc[i].actual_length = uhci_actual_length(desc);
-		urb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
-		urb->actual_length += urb->iso_frame_desc[i].actual_length;
-
-	err:
-		if (urb->iso_frame_desc[i].status != 0) {
-			urb->error_count++;
-			urb->status = urb->iso_frame_desc[i].status;
-		}
-		dbg("process_iso: %i: len:%d %08x status:%x",
-		     i, urb->iso_frame_desc[i].actual_length, le32_to_cpu(desc->hw.td.status),urb->iso_frame_desc[i].status);
-
-		p_tmp = p;
-		p = p->next;
-		list_del (p_tmp);
-
-		// add to cool down pool
-		INIT_LIST_HEAD(&desc->horizontal);
-		list_add_tail (&desc->horizontal, &uhci->free_desc_td);
-		desc->last_used=now;
-	}
-	
-	dbg("process_iso: exit %i (%d), actual_len %i", i, ret,urb->actual_length);
-	return ret;
-}
-
-/*-------------------------------------------------------------------*/
-// called with urb_list_lock set
-static int process_urb (struct uhci_hcd *uhci, struct list_head *p)
-{
-	struct urb *urb;	
-	urb_priv_t *priv;
-	int type, ret = 0;
-
-	priv=list_entry (p,  urb_priv_t, urb_list);
-	urb=priv->urb;
-//	dbg("process_urb p %p, udev %p",urb, urb->dev);
-	type=usb_pipetype (urb->pipe);
-
-	switch (type) {
-	case PIPE_CONTROL:
-		ret = process_transfer (uhci, urb, CLEAN_TRANSFER_REGULAR);
-		break;
-	case PIPE_BULK:
-		// if a submit is fiddling with bulk queues, ignore it for now
-		if (!uhci->avoid_bulk.counter)
-			ret = process_transfer (uhci, urb, CLEAN_TRANSFER_REGULAR);
-		else
-			return 0;
-		break;
-	case PIPE_ISOCHRONOUS:
-		ret = process_iso (uhci, urb, PROCESS_ISO_REGULAR);
-		break;
-	case PIPE_INTERRUPT:
-		ret = process_interrupt (uhci, urb, PROCESS_INT_REGULAR);
-		break;
-	}
-
-	if (urb->status != -EINPROGRESS && type != PIPE_INTERRUPT) {
-
-		dequeue_urb (uhci, urb);
- 		uhci_free_priv(uhci, urb, urb->hcpriv);
-
-		spin_unlock(&uhci->urb_list_lock);
-		dbg("giveback urb %p, status %i, length %i\n", 
-		    urb, urb->status, urb->transfer_buffer_length);
-		
-		usb_hcd_giveback_urb(&uhci->hcd, urb);
-		spin_lock(&uhci->urb_list_lock);
-
-	}
-	return ret;
-}
-/*###########################################################################*/
-//                        EMERGENCY ROOM
-/*###########################################################################*/
-/* used to reanimate a halted hostcontroller which signals no interrupts anymore.
-   This is a shortcut for unloading and reloading the module, and should be only
-   used as the last resort, but some VIA chips need it.
-*/
-static int hc_defibrillate(struct uhci_hcd *uhci)
-{
-	int ret;
-
-	err("Watchdog timeout, host controller obviously clinically dead, defibrillating...\n"
-	    "Expect disconnections for all devices on this controller!");
-
-	uhci->running=0;
-	outw (USBCMD_HCRESET, (int)uhci->hcd.regs + USBCMD);
-
-	uhci_stop(&uhci->hcd);
-
-	ret=init_skel(uhci);
-	if (ret)
-		return -ENOMEM;
-
-	set_td_ioc(uhci->td128ms); // enable watchdog interrupt
-	hc_irq_run(uhci);
-	uhci->reanimations++;
-	err("Host controller restart done...");
-	return 0;
-}
diff -Nru a/drivers/usb/host/usb-uhci.c b/drivers/usb/host/usb-uhci.c
--- a/drivers/usb/host/usb-uhci.c	Tue Jul 16 16:49:42 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,3095 +0,0 @@
-/* 
- * Universal Host Controller Interface driver for USB (take II).
- *
- * (c) 1999-2001 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)
- * (c) 2000      Yggdrasil Computing, Inc. (port of new PCI interface support
- *               from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
- * (C) 2000      David Brownell, david-b@pacbell.net (usb-ohci.c)
- *          
- * HW-initalization based on material of
- *
- * (C) Copyright 1999 Linus Torvalds
- * (C) Copyright 1999 Johannes Erdfelt
- * (C) Copyright 1999 Randy Dunlap
- * (C) Copyright 1999 Gregory P. Smith
- *
- * $Id: usb-uhci.c,v 1.275 2002/01/19 20:57:33 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/slab.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 <linux/version.h>
-#include <linux/pm.h>
-#include <linux/timer.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/byteorder.h>
-
-/* This enables more detailed sanity checks in submit_iso */
-//#define ISO_SANITY_CHECK
-
-/* This enables debug printks */
-#define DEBUG
-
-/* This enables all symbols to be exported, to ease debugging oopses */
-//#define DEBUG_SYMBOLS
-
-/* This enables an extra UHCI slab for memory debugging */
-#define DEBUG_SLAB
-
-#define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__
-
-#include <linux/usb.h>
-#include "../core/hcd.h"
-#include "usb-uhci.h"
-#include "usb-uhci-debug.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.275"
-#define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
-#define DRIVER_DESC "USB Universal Host Controller Interface driver"
-
-#undef DEBUG
-#undef dbg
-#define dbg(format, arg...) do {} while (0)
-#define DEBUG_SYMBOLS
-#ifdef DEBUG_SYMBOLS
-	#define _static
-	#ifndef EXPORT_SYMTAB
-		#define EXPORT_SYMTAB
-	#endif
-#else
-	#define _static static
-#endif
-
-#define queue_dbg dbg //err
-#define async_dbg dbg //err
-
-#ifdef DEBUG_SLAB
-	static kmem_cache_t *urb_priv_kmem;
-#endif
-
-#define SLAB_FLAG     (in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL)
-
-/* CONFIG_USB_UHCI_HIGH_BANDWITH turns on Full Speed Bandwidth
- * Reclamation: feature that puts loop on descriptor loop when
- * there's some transfer going on. With FSBR, USB performance
- * is optimal, but PCI can be slowed down up-to 5 times, slowing down
- * system performance (eg. framebuffer devices).
- */
-#define CONFIG_USB_UHCI_HIGH_BANDWIDTH 
-
-/* *_DEPTH_FIRST puts descriptor in depth-first mode. This has
- * somehow similar effect to FSBR (higher speed), but does not
- * slow PCI down. OTOH USB performace is slightly slower than
- * in FSBR case and single device could hog whole USB, starving
- * other devices.
- */
-#define USE_CTRL_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
-#define USE_BULK_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
-
-/* Turning off both CONFIG_USB_UHCI_HIGH_BANDWITH and *_DEPTH_FIRST
- * will lead to <64KB/sec performance over USB for bulk transfers targeting
- * one device's endpoint. You probably do not want to do that.
- */
-
-// stop bandwidth reclamation after (roughly) 50ms
-#define IDLE_TIMEOUT  (HZ/20)
-
-// Suppress HC interrupt error messages for 5s
-#define ERROR_SUPPRESSION_TIME (HZ*5)
-
-_static int rh_submit_urb (struct urb *urb);
-_static int rh_unlink_urb (struct urb *urb);
-_static int delete_qh (uhci_t *s, uhci_desc_t *qh);
-_static int process_transfer (uhci_t *s, struct urb *urb, int mode);
-_static int process_interrupt (uhci_t *s, struct urb *urb);
-_static int process_iso (uhci_t *s, struct urb *urb, int force);
-
-static uhci_t *devs = NULL;
-
-/* used by userspace UHCI data structure dumper */
-uhci_t **uhci_devices = &devs;
-
-/*-------------------------------------------------------------------*/
-// Cleans up collected QHs, but not more than 100 in one go
-void clean_descs(uhci_t *s, int force)
-{
-	struct list_head *q;
-	uhci_desc_t *qh;
-	int now=UHCI_GET_CURRENT_FRAME(s), n=0;
-
-	q=s->free_desc.prev;
-
-	while (q != &s->free_desc && (force || n<100)) {
-		qh = list_entry (q, uhci_desc_t, horizontal);		
-		q=qh->horizontal.prev;
-
-		if ((qh->last_used!=now) || force)
-			delete_qh(s,qh);
-		n++;
-	}
-}
-/*-------------------------------------------------------------------*/
-_static void uhci_switch_timer_int(uhci_t *s)
-{
-
-	if (!list_empty(&s->urb_unlinked))
-		set_td_ioc(s->td1ms);
-	else
-		clr_td_ioc(s->td1ms);
-
-	if (s->timeout_urbs)
-		set_td_ioc(s->td32ms);
-	else
-		clr_td_ioc(s->td32ms);
-	wmb();
-}
-/*-------------------------------------------------------------------*/
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-_static void enable_desc_loop(uhci_t *s, struct urb *urb)
-{
-	unsigned long flags;
-
-	if (urb->transfer_flags & USB_NO_FSBR)
-		return;
-
-	spin_lock_irqsave (&s->qh_lock, flags);
-	s->chain_end->hw.qh.head&=cpu_to_le32(~UHCI_PTR_TERM);
-	mb();
-	s->loop_usage++;
-	((urb_priv_t*)urb->hcpriv)->use_loop=1;
-	spin_unlock_irqrestore (&s->qh_lock, flags);
-}
-/*-------------------------------------------------------------------*/
-_static void disable_desc_loop(uhci_t *s, struct urb *urb)
-{
-	unsigned long flags;
-
-	if (urb->transfer_flags & USB_NO_FSBR)
-		return;
-
-	spin_lock_irqsave (&s->qh_lock, flags);
-	if (((urb_priv_t*)urb->hcpriv)->use_loop) {
-		s->loop_usage--;
-
-		if (!s->loop_usage) {
-			s->chain_end->hw.qh.head|=cpu_to_le32(UHCI_PTR_TERM);
-			mb();
-		}
-		((urb_priv_t*)urb->hcpriv)->use_loop=0;
-	}
-	spin_unlock_irqrestore (&s->qh_lock, flags);
-}
-#endif
-/*-------------------------------------------------------------------*/
-_static void queue_urb_unlocked (uhci_t *s, struct urb *urb)
-{
-	struct list_head *p=&urb->urb_list;
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-	{
-		int type;
-		type=usb_pipetype (urb->pipe);
-
-		if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
-			enable_desc_loop(s, urb);
-	}
-#endif
-	urb->status = -EINPROGRESS;
-	((urb_priv_t*)urb->hcpriv)->started=jiffies;
-	list_add (p, &s->urb_list);
-	if (urb->timeout)
-		s->timeout_urbs++;
-	uhci_switch_timer_int(s);
-}
-/*-------------------------------------------------------------------*/
-_static void queue_urb (uhci_t *s, struct urb *urb)
-{
-	unsigned long flags=0;
-
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-	queue_urb_unlocked(s,urb);
-	spin_unlock_irqrestore (&s->urb_list_lock, flags);
-}
-/*-------------------------------------------------------------------*/
-_static void dequeue_urb (uhci_t *s, struct urb *urb)
-{
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-	int type;
-
-	type=usb_pipetype (urb->pipe);
-
-	if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
-		disable_desc_loop(s, urb);
-#endif
-
-	list_del (&urb->urb_list);
-	if (urb->timeout && s->timeout_urbs)
-		s->timeout_urbs--;
-
-}
-/*-------------------------------------------------------------------*/
-_static int alloc_td (uhci_t *s, uhci_desc_t ** new, int flags)
-{
-	dma_addr_t dma_handle;
-
-	*new = pci_pool_alloc(s->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
-	if (!*new)
-		return -ENOMEM;
-	memset (*new, 0, sizeof (uhci_desc_t));
-	(*new)->dma_addr = dma_handle;
-	set_td_link((*new), 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;
-}
-/*-------------------------------------------------------------------*/
-// append a qh to td.link physically, the SW linkage is not affected
-_static void append_qh(uhci_t *s, uhci_desc_t *td, uhci_desc_t* qh, int  flags)
-{
-	unsigned long xxx;
-	
-	spin_lock_irqsave (&s->td_lock, xxx);
-
-	set_td_link(td, qh->dma_addr | (flags & UHCI_PTR_DEPTH) | UHCI_PTR_QH);
-       
-	mb();
-	spin_unlock_irqrestore (&s->td_lock, xxx);
-}
-/*-------------------------------------------------------------------*/
-/* insert td at last position in td-list of qh (vertical) */
-_static int insert_td (uhci_t *s, uhci_desc_t *qh, uhci_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);
-
-	prev = list_entry (new->vertical.prev, uhci_desc_t, vertical);
-
-	if (qh == prev ) {
-		// virgin qh without any tds
-		set_qh_element(qh, new->dma_addr | UHCI_PTR_TERM);
-	}
-	else {
-		// already tds inserted, implicitely remove TERM bit of prev
-		set_td_link(prev, new->dma_addr | (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 (uhci_t *s, uhci_desc_t *td, uhci_desc_t* new)
-{
-	uhci_desc_t *next;
-	unsigned long flags;
-	
-	spin_lock_irqsave (&s->td_lock, flags);
-
-	next = list_entry (td->horizontal.next, uhci_desc_t, horizontal);
-	list_add (&new->horizontal, &td->horizontal);
-	new->hw.td.link = td->hw.td.link;
-	set_td_link(td, new->dma_addr);
-	mb();
-	spin_unlock_irqrestore (&s->td_lock, flags);	
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static int unlink_td (uhci_t *s, uhci_desc_t *element, int phys_unlink)
-{
-	uhci_desc_t *next, *prev;
-	int dir = 0;
-	unsigned long flags;
-	
-	spin_lock_irqsave (&s->td_lock, flags);
-	
-	next = list_entry (element->vertical.next, uhci_desc_t, vertical);
-	
-	if (next == element) {
-		dir = 1;
-		prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
-	}
-	else 
-		prev = list_entry (element->vertical.prev, uhci_desc_t, vertical);
-	
-	if (phys_unlink) {
-		// really remove HW linking
-		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, flags);	
-	
-	return 0;
-}
-
-/*-------------------------------------------------------------------*/
-_static int delete_desc (uhci_t *s, uhci_desc_t *element)
-{
-	pci_pool_free(s->desc_pool, element, element->dma_addr);
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// Allocates qh element
-_static int alloc_qh (uhci_t *s, uhci_desc_t ** new)
-{
-	dma_addr_t dma_handle;
-
-	*new = pci_pool_alloc(s->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
-	if (!*new)
-		return -ENOMEM;
-	memset (*new, 0, sizeof (uhci_desc_t));
-	(*new)->dma_addr = dma_handle;
-	set_qh_head(*new, UHCI_PTR_TERM);
-	set_qh_element(*new, UHCI_PTR_TERM);
-	(*new)->type = QH_TYPE;
-	
-	mb();
-	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 (uhci_t *s, uhci_desc_t *pos, uhci_desc_t *new, int order)
-{
-	uhci_desc_t *old;
-	unsigned long flags;
-
-	spin_lock_irqsave (&s->qh_lock, flags);
-
-	if (!order) {
-		// (OLD) (POS) -> (OLD) (NEW) (POS)
-		old = list_entry (pos->horizontal.prev, uhci_desc_t, horizontal);
-		list_add_tail (&new->horizontal, &pos->horizontal);
-		set_qh_head(new, MAKE_QH_ADDR (pos)) ;
-		if (!(old->hw.qh.head & cpu_to_le32(UHCI_PTR_TERM)))
-			set_qh_head(old, 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);
-		set_qh_head(new, MAKE_QH_ADDR (old));
-		set_qh_head(pos, MAKE_QH_ADDR (new)) ;
-	}
-
-	mb ();
-	
-	spin_unlock_irqrestore (&s->qh_lock, flags);
-
-	return 0;
-}
-
-/*-------------------------------------------------------------------*/
-_static int unlink_qh (uhci_t *s, uhci_desc_t *element)
-{
-	uhci_desc_t  *prev;
-	unsigned long flags;
-
-	spin_lock_irqsave (&s->qh_lock, flags);
-	
-	prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
-	prev->hw.qh.head = element->hw.qh.head;
-
-	dbg("unlink qh %p, pqh %p, nxqh %p, to %08x", element, prev, 
-	    list_entry (element->horizontal.next, uhci_desc_t, horizontal),le32_to_cpu(element->hw.qh.head) &~15);
-	
-	list_del(&element->horizontal);
-
-	mb ();
-	spin_unlock_irqrestore (&s->qh_lock, flags);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static int delete_qh (uhci_t *s, uhci_desc_t *qh)
-{
-	uhci_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);
-		dbg("unlink td @ %p",td);
-		unlink_td (s, td, 0); // no physical unlink
-		delete_desc (s, td);
-	}
-
-	delete_desc (s, qh);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static void clean_td_chain (uhci_t *s, uhci_desc_t *td)
-{
-	struct list_head *p;
-	uhci_desc_t *td1;
-
-	if (!td)
-		return;
-	
-	while ((p = td->horizontal.next) != &td->horizontal) {
-		td1 = list_entry (p, uhci_desc_t, horizontal);
-		delete_desc (s, td1);
-	}
-	
-	delete_desc (s, td);
-}
-
-/*-------------------------------------------------------------------*/
-_static void fill_td (uhci_desc_t *td, int status, int info, __u32 buffer)
-{
-	td->hw.td.status = cpu_to_le32(status);
-	td->hw.td.info = cpu_to_le32(info);
-	td->hw.td.buffer = cpu_to_le32(buffer);
-}
-/*-------------------------------------------------------------------*/
-// Removes ALL qhs in chain (paranoia!)
-_static void cleanup_skel (uhci_t *s)
-{
-	unsigned int n;
-	uhci_desc_t *td;
-
-	dbg("cleanup_skel");
-
-	clean_descs(s,1);
-
-	
-	if (s->td32ms) {
-	
-		unlink_td(s,s->td32ms,1);
-		delete_desc(s, s->td32ms);
-	}
-
-	for (n = 0; n < 8; n++) {
-		td = s->int_chain[n];
-		clean_td_chain (s, td);
-	}
-
-	if (s->iso_td) {
-		for (n = 0; n < 1024; n++) {
-			td = s->iso_td[n];
-			clean_td_chain (s, td);
-		}
-		kfree (s->iso_td);
-	}
-
-	if (s->framelist)
-		pci_free_consistent(s->uhci_pci, PAGE_SIZE,
-				    s->framelist, s->framelist_dma);
-
-	if (s->control_chain) {
-		// completed init_skel?
-		struct list_head *p;
-		uhci_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->ls_control_chain)
-			delete_desc (s, s->ls_control_chain);
-		if (s->control_chain)
-			delete_desc (s, s->control_chain);
-		if (s->bulk_chain)
-			delete_desc (s, s->bulk_chain);
-		if (s->chain_end)
-			delete_desc (s, s->chain_end);
-	}
-
-	if (s->desc_pool) {
-		pci_pool_destroy(s->desc_pool);
-		s->desc_pool = NULL;
-	}
-
-	dbg("cleanup_skel finished");	
-}
-/*-------------------------------------------------------------------*/
-// allocates framelist and qh-skeletons
-// only HW-links provide continous linking, SW-links stay in their domain (ISO/INT)
-_static int init_skel (uhci_t *s)
-{
-	int n, ret;
-	uhci_desc_t *qh, *td;
-	
-	dbg("init_skel");
-	
-	s->framelist = pci_alloc_consistent(s->uhci_pci, PAGE_SIZE,
-					    &s->framelist_dma);
-
-	if (!s->framelist)
-		return -ENOMEM;
-
-	memset (s->framelist, 0, 4096);
-
-	dbg("creating descriptor pci_pool");
-
-	s->desc_pool = pci_pool_create("uhci_desc", s->uhci_pci,
-				       sizeof(uhci_desc_t), 16, 0,
-				       GFP_DMA | GFP_ATOMIC);	
-	if (!s->desc_pool)
-		goto init_skel_cleanup;
-
-	dbg("allocating iso desc pointer list");
-	s->iso_td = (uhci_desc_t **) kmalloc (1024 * sizeof (uhci_desc_t*), GFP_KERNEL);
-	
-	if (!s->iso_td)
-		goto init_skel_cleanup;
-
-	s->ls_control_chain = NULL;
-	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
-		if (alloc_td (s, &td, 0))
-			goto init_skel_cleanup;
-
-		s->iso_td[n] = td;
-		s->framelist[n] = cpu_to_le32((__u32) td->dma_addr);
-	}
-
-	dbg("allocating qh: chain_end");
-	if (alloc_qh (s, &qh))	
-		goto init_skel_cleanup;
-				
-	s->chain_end = qh;
-
-	if (alloc_td (s, &td, 0))
-		goto init_skel_cleanup;
-	
-	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand)
-	insert_td (s, qh, td, 0);
-	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM); // remove TERM bit
-	s->td1ms=td;
-
-	dbg("allocating qh: bulk_chain");
-	if (alloc_qh (s, &qh))
-		goto init_skel_cleanup;
-	
-	insert_qh (s, s->chain_end, qh, 0);
-	s->bulk_chain = qh;
-
-	dbg("allocating qh: control_chain");
-	ret = alloc_qh (s, &qh);
-	if (ret)
-		goto init_skel_cleanup;
-	
-	insert_qh (s, s->bulk_chain, qh, 0);
-	s->control_chain = qh;
-
-#ifdef	CONFIG_USB_UHCI_HIGH_BANDWIDTH
-	// disabled reclamation loop
-	set_qh_head(s->chain_end, s->control_chain->dma_addr | UHCI_PTR_QH | UHCI_PTR_TERM);
-#endif
-
-	dbg("allocating qh: ls_control_chain");
-	if (alloc_qh (s, &qh))
-		goto init_skel_cleanup;
-	
-	insert_qh (s, s->control_chain, qh, 0);
-	s->ls_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++) {
-		uhci_desc_t *td;
-
-		if (alloc_td (s, &td, 0))
-			goto init_skel_cleanup;
-
-		s->int_chain[n] = td;
-		if (n == 0) {
-			set_td_link(s->int_chain[0], s->ls_control_chain->dma_addr | UHCI_PTR_QH);
-		}
-		else {
-			set_td_link(s->int_chain[n], s->int_chain[0]->dma_addr);
-		}
-	}
-
-	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,le32_to_cpu(s->framelist[n]));
-		if ((n&127)==127) 
-			((uhci_desc_t*) s->iso_td[n])->hw.td.link = cpu_to_le32(s->int_chain[0]->dma_addr);
-		else 
-			for (o = 1, m = 2; m <= 128; o++, m += m)
-				if ((n & (m - 1)) == ((m - 1) / 2))
-					set_td_link(((uhci_desc_t*) s->iso_td[n]), s->int_chain[o]->dma_addr);
-	}
-
-	if (alloc_td (s, &td, 0))
-		goto init_skel_cleanup;
-	
-	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt (activated later)
-	s->td32ms=td;
-
-	insert_td_horizontal (s, s->int_chain[5], td);
-
-	mb();
-	dbg("init_skel exit");
-	return 0;
-
-      init_skel_cleanup:
-	cleanup_skel (s);
-	return -ENOMEM;
-}
-
-/*-------------------------------------------------------------------*/
-//                         LOW LEVEL STUFF
-//          assembles QHs und TDs for control, bulk and iso
-/*-------------------------------------------------------------------*/
-_static int uhci_submit_control_urb (struct urb *urb)
-{
-	uhci_desc_t *qh, *td;
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	unsigned long destination, status;
-	int maxsze = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
-	unsigned long len;
-	char *data;
-	int depth_first=USE_CTRL_DEPTH_FIRST;  // UHCI descriptor chasing method
-
-	dbg("uhci_submit_control start");
-	if (alloc_qh (s, &qh))		// alloc qh for this request
-		return -ENOMEM;
-
-	if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))		// get td for setup stage
-	{
-		delete_qh (s, qh);
-		return -ENOMEM;
-	}
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
-
-	/* 3 errors */
-	status = TD_CTRL_ACTIVE
-		| (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD)
-		| (3 << 27);
-	if (urb->dev->speed == USB_SPEED_LOW)
-		status |= TD_CTRL_LS;
-
-	/*  Build the TD for the control request, try forever, 8 bytes of data */
-	fill_td (td, status, destination | (7 << 21), urb_priv->setup_packet_dma);
-
-	insert_td (s, qh, td, 0);	// queue 'setup stage'-td in qh
-#if 0
-	{
-		char *sp=urb->setup_packet;
-		dbg("SETUP to pipe %x: %x %x %x %x %x %x %x %x", urb->pipe,
-		    sp[0],sp[1],sp[2],sp[3],sp[4],sp[5],sp[6],sp[7]);
-	}
-	//uhci_show_td(td);
-#endif
-
-	len = urb->transfer_buffer_length;
-	data = urb->transfer_buffer;
-
-	/* If direction is "send", change the frame from SETUP (0x2D)
-	   to OUT (0xE1). Else change it from SETUP to IN (0x69). */
-
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | (usb_pipeout (urb->pipe)?USB_PID_OUT:USB_PID_IN);
-
-	while (len > 0) {
-		int pktsze = len;
-
-		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))
-			goto fail_unmap_enomem;
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		destination ^= 1 << TD_TOKEN_TOGGLE;	// toggle DATA0/1
-
-		// Status, pktsze bytes of data
-		fill_td (td, status, destination | ((pktsze - 1) << 21),
-			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));
-
-		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// 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 &= ~UHCI_PID;
-
-	if (usb_pipeout (urb->pipe) || (urb->transfer_buffer_length == 0))
-		destination |= USB_PID_IN;
-	else
-		destination |= USB_PID_OUT;
-
-	destination |= 1 << TD_TOKEN_TOGGLE;	/* End in Data1 */
-
-	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
-		goto fail_unmap_enomem;
-
-	status &=~TD_CTRL_SPD;
-
-	/* 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 * depth_first);	// queue status td
-
-	list_add (&qh->desc_list, &urb_priv->desc_list);
-
-	queue_urb (s, urb);	// queue before inserting in desc chain
-
-	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);
-
-	/* Start it up... put low speed first */
-	if (urb->dev->speed == USB_SPEED_LOW)
-		insert_qh (s, s->control_chain, qh, 0);
-	else
-		insert_qh (s, s->bulk_chain, qh, 0);
-
-	dbg("uhci_submit_control end");
-	return 0;
-
-fail_unmap_enomem:
-	delete_qh(s, qh);
-	return -ENOMEM;
-}
-/*-------------------------------------------------------------------*/
-// For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh)
-// Due to the linking with other bulk urbs, it has to be locked with urb_list_lock!
-
-_static int uhci_submit_bulk_urb (struct urb *urb, struct urb *bulk_urb)
-{
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv, *upriv, *bpriv=NULL;
-	uhci_desc_t *qh, *td, *nqh=NULL, *bqh=NULL, *first_td=NULL;
-	unsigned long destination, status;
-	char *data;
-	unsigned int pipe = urb->pipe;
-	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
-	int info, len, last;
-	int depth_first=USE_BULK_DEPTH_FIRST;  // UHCI descriptor chasing method
-
-	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
-		return -EPIPE;
-
-	queue_dbg("uhci_submit_bulk_urb: urb %p, old %p, pipe %08x, len %i",
-		  urb,bulk_urb,urb->pipe,urb->transfer_buffer_length);
-
-	upriv = (urb_priv_t*)urb->hcpriv;
-
-	if (!bulk_urb) {
-		if (alloc_qh (s, &qh))		// get qh for this request
-			return -ENOMEM;
-
-		if (urb->transfer_flags & USB_QUEUE_BULK) {
-			if (alloc_qh(s, &nqh)) // placeholder for clean unlink
-			{
-				delete_desc (s, qh);
-				return -ENOMEM;
-			}
-			upriv->next_qh = nqh;
-			queue_dbg("new next qh %p",nqh);
-		}
-	}
-	else { 
-		bpriv = (urb_priv_t*)bulk_urb->hcpriv;
-		qh = bpriv->bottom_qh;  // re-use bottom qh and next qh
-		nqh = bpriv->next_qh;
-		upriv->next_qh=nqh;	
-		upriv->prev_queued_urb=bulk_urb;
-	}
-
-	if (urb->transfer_flags & USB_QUEUE_BULK) {
-		if (alloc_qh (s, &bqh))  // "bottom" QH
-		{
-			if (!bulk_urb) { 
-				delete_desc(s, qh);
-				delete_desc(s, nqh);
-			}
-			return -ENOMEM;
-		}
-		set_qh_element(bqh, UHCI_PTR_TERM);
-		set_qh_head(bqh, nqh->dma_addr | UHCI_PTR_QH); // element
-		upriv->bottom_qh = bqh;
-	}
-	queue_dbg("uhci_submit_bulk: qh %p bqh %p nqh %p",qh, bqh, nqh);
-
-	/* The "pipe" thing contains the destination in bits 8--18. */
-	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
-
-	/* 3 errors */
-	status = TD_CTRL_ACTIVE
-		| ((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD)
-		| (3 << 27);
-	if (urb->dev->speed == USB_SPEED_LOW)
-		status |= TD_CTRL_LS;
-
-	/* Build the TDs for the bulk request */
-	len = urb->transfer_buffer_length;
-	data = urb->transfer_buffer;
-	
-	do {					// TBD: Really allow zero-length packets?
-		int pktsze = len;
-
-		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))
-		{
-			delete_qh (s, qh);
-			return -ENOMEM;
-		}
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		// pktsze bytes of data 
-		info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) |
-			(usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
-
-		fill_td (td, status, info,
-			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));
-
-		data += pktsze;
-		len -= pktsze;
-		// Use USB_ZERO_PACKET to finish bulk OUTs always with a zero length packet
-		last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || !(urb->transfer_flags & USB_ZERO_PACKET)));
-
-		if (last)
-			set_td_ioc(td);	// last one generates INT
-
-		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);
-		if (!first_td)
-			first_td=td;
-		usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
-
-	} while (!last);
-
-	if (bulk_urb && bpriv)   // everything went OK, link with old bulk URB
-		bpriv->next_queued_urb=urb;
-
-	list_add (&qh->desc_list, &urb_priv->desc_list);
-
-	if (urb->transfer_flags & USB_QUEUE_BULK)
-		append_qh(s, td, bqh, UHCI_PTR_DEPTH * depth_first);
-
-	queue_urb_unlocked (s, urb);
-	
-	if (urb->transfer_flags & USB_QUEUE_BULK)
-		set_qh_element(qh, first_td->dma_addr);
-	else
-		qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);    // arm QH
-
-	if (!bulk_urb) { 					// new bulk queue	
-		if (urb->transfer_flags & USB_QUEUE_BULK) {
-			spin_lock (&s->td_lock);		// both QHs in one go
-			insert_qh (s, s->chain_end, qh, 0);	// Main QH
-			insert_qh (s, s->chain_end, nqh, 0);	// Helper QH
-			spin_unlock (&s->td_lock);
-		}
-		else
-			insert_qh (s, s->chain_end, qh, 0);
-	}
-	
-	//dbg("uhci_submit_bulk_urb: exit\n");
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static void uhci_clean_iso_step1(uhci_t *s, urb_priv_t *urb_priv)
-{
-	struct list_head *p;
-	uhci_desc_t *td;
-
-	for (p = urb_priv->desc_list.next; p != &urb_priv->desc_list; p = p->next) {
-				td = list_entry (p, uhci_desc_t, desc_list);
-				unlink_td (s, td, 1);
-	}
-}
-/*-------------------------------------------------------------------*/
-_static void uhci_clean_iso_step2(uhci_t *s, urb_priv_t *urb_priv)
-{
-	struct list_head *p;
-	uhci_desc_t *td;
-
-	while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) {
-				td = list_entry (p, uhci_desc_t, desc_list);
-				list_del (p);
-				delete_desc (s, td);
-	}
-}
-/*-------------------------------------------------------------------*/
-/* mode: CLEAN_TRANSFER_NO_DELETION: unlink but no deletion mark (step 1 of async_unlink)
-         CLEAN_TRANSFER_REGULAR: regular (unlink/delete-mark)
-         CLEAN_TRANSFER_DELETION_MARK: deletion mark for QH (step 2 of async_unlink)
- looks a bit complicated because of all the bulk queueing goodies
-*/
-
-_static void uhci_clean_transfer (uhci_t *s, struct urb *urb, uhci_desc_t *qh, int mode)
-{
-	uhci_desc_t *bqh, *nqh, *prevqh, *prevtd;
-	int now;
-	urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-
-	now=UHCI_GET_CURRENT_FRAME(s);
-
-	bqh=priv->bottom_qh;	
-	
-	if (!priv->next_queued_urb)  { // no more appended bulk queues
-
-		queue_dbg("uhci_clean_transfer: No more bulks for urb %p, qh %p, bqh %p, nqh %p", urb, qh, bqh, priv->next_qh);	
-	
-		if (priv->prev_queued_urb && mode != CLEAN_TRANSFER_DELETION_MARK) {  // qh not top of the queue
-				unsigned long flags; 
-				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
-
-				spin_lock_irqsave (&s->qh_lock, flags);
-				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
-				prevtd = list_entry (prevqh->vertical.prev, uhci_desc_t, vertical);
-				set_td_link(prevtd, priv->bottom_qh->dma_addr | UHCI_PTR_QH); // skip current qh
-				mb();
-				queue_dbg("uhci_clean_transfer: relink pqh %p, ptd %p",prevqh, prevtd);
-				spin_unlock_irqrestore (&s->qh_lock, flags);
-
-				ppriv->bottom_qh = priv->bottom_qh;
-				ppriv->next_queued_urb = NULL;
-			}
-		else {   // queue is dead, qh is top of the queue
-			
-			if (mode != CLEAN_TRANSFER_DELETION_MARK) 				
-				unlink_qh(s, qh); // remove qh from horizontal chain
-
-			if (bqh) {  // remove remainings of bulk queue
-				nqh=priv->next_qh;
-
-				if (mode != CLEAN_TRANSFER_DELETION_MARK) 
-					unlink_qh(s, nqh);  // remove nqh from horizontal chain
-				
-				if (mode != CLEAN_TRANSFER_NO_DELETION) {  // add helper QHs to free desc list
-					nqh->last_used = bqh->last_used = now;
-					list_add_tail (&nqh->horizontal, &s->free_desc);
-					list_add_tail (&bqh->horizontal, &s->free_desc);
-				}			
-			}
-		}
-	}
-	else { // there are queued urbs following
-	
-	  queue_dbg("uhci_clean_transfer: urb %p, prevurb %p, nexturb %p, qh %p, bqh %p, nqh %p",
-		       urb, priv->prev_queued_urb,  priv->next_queued_urb, qh, bqh, priv->next_qh);	
-       	
-		if (mode != CLEAN_TRANSFER_DELETION_MARK) {	// no work for cleanup at unlink-completion
-			struct urb *nurb;
-			unsigned long flags;
-
-			nurb = priv->next_queued_urb;
-			spin_lock_irqsave (&s->qh_lock, flags);		
-
-			if (!priv->prev_queued_urb) { // top QH
-				
-				prevqh = list_entry (qh->horizontal.prev, uhci_desc_t, horizontal);
-				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
-				list_del (&qh->horizontal);  // remove this qh form horizontal chain
-				list_add (&bqh->horizontal, &prevqh->horizontal); // insert next bqh in horizontal chain
-			}
-			else {		// intermediate QH
-				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
-				urb_priv_t* npriv=(urb_priv_t*)nurb->hcpriv;
-				uhci_desc_t * bnqh;
-				
-				bnqh = list_entry (npriv->desc_list.next, uhci_desc_t, desc_list);
-				ppriv->bottom_qh = bnqh;
-				ppriv->next_queued_urb = nurb;				
-				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
-				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
-			}
-
-			mb();
-			((urb_priv_t*)nurb->hcpriv)->prev_queued_urb=priv->prev_queued_urb;
-			spin_unlock_irqrestore (&s->qh_lock, flags);
-		}		
-	}
-
-	if (mode != CLEAN_TRANSFER_NO_DELETION) {
-		qh->last_used = now;	
-		list_add_tail (&qh->horizontal, &s->free_desc); // mark qh for later deletion/kfree
-	}
-}
-/*-------------------------------------------------------------------*/
-// Release bandwidth for Interrupt or Isoc. transfers 
-_static void uhci_release_bandwidth(struct urb *urb)
-{       
-	if (urb->bandwidth) {
-		switch (usb_pipetype(urb->pipe)) {
-		case PIPE_INTERRUPT:
-			usb_release_bandwidth (urb->dev, urb, 0);
-			break;
-		case PIPE_ISOCHRONOUS:
-			usb_release_bandwidth (urb->dev, urb, 1);
-			break;
-		default:
-			break;
-		}
-	}	
-}
-
-_static void uhci_urb_dma_sync(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
-{
-	if (urb_priv->setup_packet_dma)
-		pci_dma_sync_single(s->uhci_pci, urb_priv->setup_packet_dma,
-				    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-
-	if (urb_priv->transfer_buffer_dma)
-		pci_dma_sync_single(s->uhci_pci, urb_priv->transfer_buffer_dma,
-				    urb->transfer_buffer_length,
-				    usb_pipein(urb->pipe) ?
-				    PCI_DMA_FROMDEVICE :
-				    PCI_DMA_TODEVICE);
-}
-
-_static void uhci_urb_dma_unmap(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
-{
-	if (urb_priv->setup_packet_dma) {
-		pci_unmap_single(s->uhci_pci, urb_priv->setup_packet_dma,
-				 sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-		urb_priv->setup_packet_dma = 0;
-	}
-	if (urb_priv->transfer_buffer_dma) {
-		pci_unmap_single(s->uhci_pci, urb_priv->transfer_buffer_dma,
-				 urb->transfer_buffer_length,
-				 usb_pipein(urb->pipe) ?
-				 PCI_DMA_FROMDEVICE :
-				 PCI_DMA_TODEVICE);
-		urb_priv->transfer_buffer_dma = 0;
-	}
-}
-/*-------------------------------------------------------------------*/
-/* needs urb_list_lock!
-   mode: UNLINK_ASYNC_STORE_URB: unlink and move URB into unlinked list
-         UNLINK_ASYNC_DONT_STORE: unlink, don't move URB into unlinked list
-*/
-_static int uhci_unlink_urb_async (uhci_t *s, struct urb *urb, int mode)
-{
-	uhci_desc_t *qh;
-	urb_priv_t *urb_priv;
-	
-	async_dbg("unlink_urb_async called %p",urb);
-
-	if ((urb->status == -EINPROGRESS) ||
-	    ((usb_pipetype (urb->pipe) ==  PIPE_INTERRUPT) && ((urb_priv_t*)urb->hcpriv)->flags))
-	{
-		((urb_priv_t*)urb->hcpriv)->started = ~0;  // mark
-		dequeue_urb (s, urb);
-
-		if (mode==UNLINK_ASYNC_STORE_URB)
-			list_add_tail (&urb->urb_list, &s->urb_unlinked); // store urb
-
-		uhci_switch_timer_int(s);
-       		s->unlink_urb_done = 1;
-		uhci_release_bandwidth(urb);
-
-		urb->status = -ECONNABORTED;	// mark urb as "waiting to be killed"	
-		urb_priv = (urb_priv_t*)urb->hcpriv;
-
-		switch (usb_pipetype (urb->pipe)) {
-		case PIPE_INTERRUPT:
-			usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-
-		case PIPE_ISOCHRONOUS:
-			uhci_clean_iso_step1 (s, urb_priv);
-			break;
-
-		case PIPE_BULK:
-		case PIPE_CONTROL:
-			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
-			uhci_clean_transfer (s, urb, qh, CLEAN_TRANSFER_NO_DELETION);
-			break;
-		}
-		((urb_priv_t*)urb->hcpriv)->started = UHCI_GET_CURRENT_FRAME(s);
-		return -EINPROGRESS;  // completion will follow
-	}		
-
-	return 0;    // URB already dead
-}
-/*-------------------------------------------------------------------*/
-// kills an urb by unlinking descriptors and waiting for at least one frame
-_static int uhci_unlink_urb_sync (uhci_t *s, struct urb *urb)
-{
-	uhci_desc_t *qh;
-	urb_priv_t *urb_priv;
-	unsigned long flags=0;
-	struct usb_device *usb_dev;
-
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-
-	if (urb->status == -EINPROGRESS) {
-
-		// move descriptors out the the running chains, dequeue urb
-		uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_DONT_STORE);
-
-		urb_priv = urb->hcpriv;
-		urb->status = -ENOENT;	// prevent from double deletion after unlock		
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-		
-		// cleanup the rest
-		switch (usb_pipetype (urb->pipe)) {
-
-		case PIPE_INTERRUPT:
-		case PIPE_ISOCHRONOUS:
-			uhci_wait_ms(1);
-			uhci_clean_iso_step2(s, urb_priv);
-			break;
-
-		case PIPE_BULK:
-		case PIPE_CONTROL:
-			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
-			uhci_clean_transfer(s, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
-			uhci_wait_ms(1);
-		}
-		urb->status = -ENOENT;	// mark urb as killed		
-					
-		uhci_urb_dma_unmap(s, urb, urb->hcpriv);
-
-#ifdef DEBUG_SLAB
-		kmem_cache_free (urb_priv_kmem, urb->hcpriv);
-#else
-		kfree (urb->hcpriv);
-#endif
-		usb_dev = urb->dev;
-		if (urb->complete) {
-			dbg("unlink_urb: calling completion");
-			urb->dev = NULL;
-			urb->complete ((struct urb *) urb);
-		}
-		usb_put_dev (usb_dev);
-		usb_put_urb (urb);
-	}
-	else
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// async unlink_urb completion/cleanup work
-// has to be protected by urb_list_lock!
-// features: if set in transfer_flags, the resulting status of the killed
-// transaction is not overwritten
-
-_static void uhci_cleanup_unlink(uhci_t *s, int force)
-{
-	struct list_head *q;
-	struct urb *urb;
-	struct usb_device *dev;
-	int now, type;
-	urb_priv_t *urb_priv;
-
-	q=s->urb_unlinked.next;
-	now=UHCI_GET_CURRENT_FRAME(s);
-
-	while (q != &s->urb_unlinked) {
-
-		urb = list_entry (q, struct urb, urb_list);
-
-		urb_priv = (urb_priv_t*)urb->hcpriv;
-		q = urb->urb_list.next;
-		
-		if (!urb_priv) // avoid crash when URB is corrupted
-			break;
-			
-		if (force || ((urb_priv->started != ~0) && (urb_priv->started != now))) {
-			async_dbg("async cleanup %p",urb);
-			type=usb_pipetype (urb->pipe);
-
-			switch (type) { // process descriptors
-			case PIPE_CONTROL:
-				process_transfer (s, urb, CLEAN_TRANSFER_DELETION_MARK);  // don't unlink (already done)
-				break;
-			case PIPE_BULK:
-				if (!s->avoid_bulk.counter)
-					process_transfer (s, urb, CLEAN_TRANSFER_DELETION_MARK); // don't unlink (already done)
-				else
-					continue;
-				break;
-			case PIPE_ISOCHRONOUS:
-				process_iso (s, urb, PROCESS_ISO_FORCE); // force, don't unlink
-				break;
-			case PIPE_INTERRUPT:
-				process_interrupt (s, urb);
-				break;
-			}
-
-			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
-		  		urb->status = -ECONNRESET; // mark as asynchronously killed
-
-			dev = urb->dev;	// completion may destroy all...
-			urb_priv = urb->hcpriv;
-			list_del (&urb->urb_list);
-			
-			uhci_urb_dma_sync(s, urb, urb_priv);
-			if (urb->complete) {
-				spin_unlock(&s->urb_list_lock);
-				urb->dev = NULL;
-				urb->complete ((struct urb *) urb);
-				spin_lock(&s->urb_list_lock);
-			}
-
-			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
-				urb->status = -ENOENT;  // now the urb is really dead
-
-			switch (type) {
-			case PIPE_ISOCHRONOUS:
-			case PIPE_INTERRUPT:
-				uhci_clean_iso_step2(s, urb_priv);
-				break;
-			}
-	
-			uhci_urb_dma_unmap(s, urb, urb_priv);
-
-			usb_put_dev (dev);
-#ifdef DEBUG_SLAB
-			kmem_cache_free (urb_priv_kmem, urb_priv);
-#else
-			kfree (urb_priv);
-#endif
-			usb_put_urb (urb);
-		}
-	}
-}
- 
-/*-------------------------------------------------------------------*/
-_static int uhci_unlink_urb (struct urb *urb)
-{
-	uhci_t *s;
-	unsigned long flags=0;
-	dbg("uhci_unlink_urb called for %p",urb);
-	if (!urb || !urb->dev)		// you never know...
-		return -EINVAL;
-	
-	s = (uhci_t*) urb->dev->bus->hcpriv;
-
-	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
-		return rh_unlink_urb (urb);
-
-	if (!urb->hcpriv)
-		return -EINVAL;
-
-	if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-		int ret;
-       		spin_lock_irqsave (&s->urb_list_lock, flags);
-       		
-		uhci_release_bandwidth(urb);
-		ret = uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
-
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);	
-		return ret;
-	}
-	else
-		return uhci_unlink_urb_sync(s, urb);
-}
-/*-------------------------------------------------------------------*/
-// 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 (struct urb *urb, unsigned int *start, unsigned int *end)
-{
-	struct urb *u, *last_urb = NULL;
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	struct list_head *p;
-	int ret=-1;
-	unsigned long flags;
-	
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-	p=s->urb_list.prev;
-
-	for (; p != &s->urb_list; p = p->prev) {
-		u = list_entry (p, struct urb, urb_list);
-		// look for pending URBs with identical pipe handle
-		// works only because iso doesn't toggle the data bit!
-		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS)) {
-			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;
-}
-/*-------------------------------------------------------------------*/
-// adjust start_frame according to scheduling constraints (ASAP etc)
-
-_static int iso_find_start (struct urb *urb)
-{
-	uhci_t *s = (uhci_t*) urb->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) urb->number_of_packets > 900)
-		return -EFBIG;
-	
-	limits = find_iso_limits (urb, &start_limit, &stop_limit);
-	queued_size = (stop_limit - start_limit) & 1023;
-
-	if (urb->transfer_flags & USB_ISO_ASAP) {
-		// first iso
-		if (limits) {
-			// 10ms setup should be enough //FIXME!
-			urb->start_frame = (now + 10) & 1023;
-		}
-		else {
-			urb->start_frame = stop_limit;		//seamless linkage
-
-			if (((now - urb->start_frame) & 1023) <= (unsigned) urb->number_of_packets) {
-				info("iso_find_start: gap in seamless isochronous scheduling");
-				dbg("iso_find_start: now %u start_frame %u number_of_packets %u pipe 0x%08x",
-					now, urb->start_frame, urb->number_of_packets, urb->pipe);
-				urb->start_frame = (now + 5) & 1023;	// 5ms setup should be enough //FIXME!
-			}
-		}
-	}
-	else {
-		urb->start_frame &= 1023;
-		if (((now - urb->start_frame) & 1023) < (unsigned) urb->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 (((urb->start_frame - start_limit) & 1023) < queued_size ||
-	    ((urb->start_frame + urb->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",
-			urb->start_frame, urb->number_of_packets, start_limit, stop_limit);
-		return -EAGAIN;
-	}
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// submits USB interrupt (ie. polling ;-) 
-// ASAP-flag set implicitely
-// if period==0, the transfer is only done once
-
-_static int uhci_submit_int_urb (struct urb *urb)
-{
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	int nint, n;
-	uhci_desc_t *td;
-	int status, destination;
-	int info;
-	unsigned int pipe = urb->pipe;
-
-	if (urb->interval < 0 || urb->interval >= 256)
-		return -EINVAL;
-
-	if (urb->interval == 0)
-		nint = 0;
-	else {
-		for (nint = 0, n = 1; nint <= 8; nint++, n += n)	// round interval down to 2^n
-		 {
-			if (urb->interval < n) {
-				urb->interval = n / 2;
-				break;
-			}
-		}
-		nint--;
-	}
-
-	dbg("Rounded interval to %i, chain  %i", urb->interval, nint);
-
-	urb->start_frame = UHCI_GET_CURRENT_FRAME (s) & 1023;	// remember start frame, just in case...
-
-	urb->number_of_packets = 1;
-
-	// INT allows only one packet
-	if (urb->transfer_buffer_length > usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)))
-		return -EINVAL;
-
-	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
-		return -ENOMEM;
-
-	status = TD_CTRL_ACTIVE | TD_CTRL_IOC
-		| (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD)
-		| (3 << 27);
-	if (urb->dev->speed == USB_SPEED_LOW)
-		status |= TD_CTRL_LS;
-
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe) |
-		(((urb->transfer_buffer_length - 1) & 0x7ff) << 21);
-
-
-	info = destination | (usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
-
-	fill_td (td, status, info, urb_priv->transfer_buffer_dma);
-	list_add_tail (&td->desc_list, &urb_priv->desc_list);
-
-	queue_urb (s, urb);
-
-	insert_td_horizontal (s, s->int_chain[nint], td);	// store in INT-TDs
-
-	usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static int uhci_submit_iso_urb (struct urb *urb, int mem_flags)
-{
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv;
-#ifdef ISO_SANITY_CHECK
-	int pipe=urb->pipe;
-	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
-#endif
-	int n, ret, last=0;
-	uhci_desc_t *td, **tdm;
-	int status, destination;
-	unsigned long flags;
-
-	__save_flags(flags);
-	__cli();		      // Disable IRQs to schedule all ISO-TDs in time
-	ret = iso_find_start (urb);	// adjusts urb->start_frame for later use
-	
-	if (ret)
-		goto err;
-
-	tdm = (uhci_desc_t **) kmalloc (urb->number_of_packets * sizeof (uhci_desc_t*), mem_flags);
-
-	if (!tdm) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	memset(tdm, 0, urb->number_of_packets * sizeof (uhci_desc_t*));
-
-	// First try to get all TDs. Cause: Removing already inserted TDs can only be done 
-	// racefree in three steps: unlink TDs, wait one frame, delete TDs. 
-	// So, this solutions seems simpler...
-
-	for (n = 0; n < urb->number_of_packets; n++) {
-		dbg("n:%d urb->iso_frame_desc[n].length:%d", n, urb->iso_frame_desc[n].length);
-		if (!urb->iso_frame_desc[n].length)
-			continue;  // allows ISO striping by setting length to zero in iso_descriptor
-
-
-#ifdef ISO_SANITY_CHECK
-		if(urb->iso_frame_desc[n].length > maxsze) {
-
-			err("submit_iso: urb->iso_frame_desc[%d].length(%d)>%d",n , urb->iso_frame_desc[n].length, maxsze);
-			ret=-EINVAL;		
-		}
-		else
-#endif
-		if (alloc_td (s, &td, UHCI_PTR_DEPTH)) {
-			int i;	// Cleanup allocated TDs
-
-			for (i = 0; i < n; n++)
-				if (tdm[i])
-					 delete_desc(s, tdm[i]);
-			kfree (tdm);
-			goto err;
-		}
-		last=n;
-		tdm[n] = td;
-	}
-
-	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
-
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe);
-
-	// Queue all allocated TDs
-	for (n = 0; n < urb->number_of_packets; n++) {
-		td = tdm[n];
-		if (!td)
-			continue;
-			
-		if (n  == last) {
-			status |= TD_CTRL_IOC;
-			queue_urb (s, urb);
-		}
-
-		fill_td (td, status, destination | (((urb->iso_frame_desc[n].length - 1) & 0x7ff) << 21),
-			 urb_priv->transfer_buffer_dma + urb->iso_frame_desc[n].offset);
-		list_add_tail (&td->desc_list, &urb_priv->desc_list);
-	
-		insert_td_horizontal (s, s->iso_td[(urb->start_frame + n) & 1023], td);	// store in iso-tds
-	}
-
-	kfree (tdm);
-	dbg("ISO-INT# %i, start %i, now %i", urb->number_of_packets, urb->start_frame, UHCI_GET_CURRENT_FRAME (s) & 1023);
-	ret = 0;
-
-      err:
-	__restore_flags(flags);
-	return ret;
-}
-/*-------------------------------------------------------------------*/
-// returns: 0 (no transfer queued), urb* (this urb already queued)
- 
-_static struct urb* search_dev_ep (uhci_t *s, struct urb *urb)
-{
-	struct list_head *p;
-	struct urb *tmp;
-	unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0);
-
-	dbg("search_dev_ep:");
-
-	p=s->urb_list.next;
-
-	for (; p != &s->urb_list; p = p->next) {
-		tmp = list_entry (p, struct urb, 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_pipeisoc(urb->pipe) && (tmp->dev == urb->dev) && !((tmp->pipe ^ urb->pipe) & mask)) ||
-		    (urb == tmp)) {
-			return tmp;	// found another urb already queued for processing
-		}
-	}
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static int uhci_submit_urb (struct urb *urb, int mem_flags)
-{
-	uhci_t *s;
-	urb_priv_t *urb_priv;
-	int ret = 0, type;
-	unsigned long flags;
-	struct urb *queued_urb=NULL;
-	int bustime;
-		
-	if (!urb->dev || !urb->dev->bus)
-		return -ENODEV;
-
-	s = (uhci_t*) urb->dev->bus->hcpriv;
-	//dbg("submit_urb: %p type %d",urb,usb_pipetype(urb->pipe));
-	
-	if (!s->running)
-		return -ENODEV;
-	
-	type = usb_pipetype (urb->pipe);
-
-	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
-		return rh_submit_urb (urb);	/* virtual root hub */
-
-	// Sanity checks
-	if (usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe)) <= 0) {		
-		err("uhci_submit_urb: pipesize for pipe %x is zero", urb->pipe);
-		return -EMSGSIZE;
-	}
-
-	if (urb->transfer_buffer_length < 0 && type != PIPE_ISOCHRONOUS) {
-		err("uhci_submit_urb: Negative transfer length for urb %p", urb);
-		return -EINVAL;
-	}
-
-	/* increment the reference count of the urb, as we now also control it */
-	urb = usb_get_urb (urb);
-
-	usb_get_dev (urb->dev);
-
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-
-	queued_urb = search_dev_ep (s, urb); // returns already queued urb for that pipe
-
-	if (queued_urb) {
-
-		queue_dbg("found bulk urb %p\n", queued_urb);
-
-		if (( type != PIPE_BULK) ||
-		    ((type == PIPE_BULK) &&
-		     (!(urb->transfer_flags & USB_QUEUE_BULK) || !(queued_urb->transfer_flags & USB_QUEUE_BULK)))) {
-			spin_unlock_irqrestore (&s->urb_list_lock, flags);
-			usb_put_dev (urb->dev);
-			usb_put_urb (urb);
-			err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,queued_urb);
-			return -ENXIO;	// urb already queued
-		}
-	}
-
-#ifdef DEBUG_SLAB
-	urb_priv = kmem_cache_alloc(urb_priv_kmem, SLAB_FLAG);
-#else
-	urb_priv = kmalloc (sizeof (urb_priv_t), mem_flags);
-#endif
-	if (!urb_priv) {
-		usb_put_dev (urb->dev);
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-		usb_put_urb (urb);
-		return -ENOMEM;
-	}
-
-	memset(urb_priv, 0, sizeof(urb_priv_t));
-	urb->hcpriv = urb_priv;
-	INIT_LIST_HEAD (&urb_priv->desc_list);
-
-	dbg("submit_urb: scheduling %p", urb);
-	
-	if (type == PIPE_CONTROL)
-		urb_priv->setup_packet_dma = pci_map_single(s->uhci_pci, urb->setup_packet,
-							    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-
-	if (urb->transfer_buffer_length)
-		urb_priv->transfer_buffer_dma = pci_map_single(s->uhci_pci,
-							       urb->transfer_buffer,
-							       urb->transfer_buffer_length,
-							       usb_pipein(urb->pipe) ?
-							       PCI_DMA_FROMDEVICE :
-							       PCI_DMA_TODEVICE);
-
-	if (type == PIPE_BULK) {
-	
-		if (queued_urb) {
-			while (((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb)  // find last queued bulk
-				queued_urb=((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb;
-			
-			((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb=urb;
-		}
-		atomic_inc (&s->avoid_bulk);
-		ret = uhci_submit_bulk_urb (urb, queued_urb);
-		atomic_dec (&s->avoid_bulk);
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-	}
-	else {
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-		switch (type) {
-		case PIPE_ISOCHRONOUS:			
-			if (urb->bandwidth == 0) {      /* not yet checked/allocated */
-				if (urb->number_of_packets <= 0) {
-					ret = -EINVAL;
-					break;
-				}
-
-				bustime = usb_check_bandwidth (urb->dev, urb);
-				if (bustime < 0) 
-					ret = bustime;
-				else {
-					ret = uhci_submit_iso_urb(urb, mem_flags);
-					if (ret == 0)
-						usb_claim_bandwidth (urb->dev, urb, bustime, 1);
-				}
-			} else {        /* bandwidth is already set */
-				ret = uhci_submit_iso_urb(urb, mem_flags);
-			}
-			break;
-		case PIPE_INTERRUPT:
-			if (urb->bandwidth == 0) {      /* not yet checked/allocated */
-				bustime = usb_check_bandwidth (urb->dev, urb);
-				if (bustime < 0)
-					ret = bustime;
-				else {
-					ret = uhci_submit_int_urb(urb);
-					if (ret == 0)
-						usb_claim_bandwidth (urb->dev, urb, bustime, 0);
-				}
-			} else {        /* bandwidth is already set */
-				ret = uhci_submit_int_urb(urb);
-			}
-			break;
-		case PIPE_CONTROL:
-			ret = uhci_submit_control_urb (urb);
-			break;
-		default:
-			ret = -EINVAL;
-		}
-	}
-
-	dbg("submit_urb: scheduled with ret: %d", ret);
-	
-	if (ret != 0) {
-		uhci_urb_dma_unmap(s, urb, urb_priv);
-		usb_put_dev (urb->dev);
-#ifdef DEBUG_SLAB
-		kmem_cache_free(urb_priv_kmem, urb_priv);
-#else
-		kfree (urb_priv);
-#endif
-		usb_put_urb (urb);
-		return ret;
-	}
-
-	return 0;
-}
-
-// Checks for URB timeout and removes bandwidth reclamation if URB idles too long
-_static void uhci_check_timeouts(uhci_t *s)
-{
-	struct list_head *p,*p2;
-	struct urb *urb;
-	int type;	
-
-	p = s->urb_list.prev;	
-
-	while (p != &s->urb_list) {
-		urb_priv_t *hcpriv;
-
-		p2 = p;
-		p = p->prev;
-		urb = list_entry (p2, struct urb, urb_list);
-		type = usb_pipetype (urb->pipe);
-
-		hcpriv = (urb_priv_t*)urb->hcpriv;
-		
-		if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
-			urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
-			async_dbg("uhci_check_timeout: timeout for %p",urb);
-			uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
-		}
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-		else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
-			 (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))
-			disable_desc_loop(s, urb);
-#endif
-
-	}
-	s->timeout_check=jiffies;
-}
-
-/*-------------------------------------------------------------------
- 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; */
-	0x02,			/*  __u8  iProduct; */
-	0x01,			/*  __u8  iSerialNumber; */
-	0x01			/*  __u8  bNumConfigurations; */
-};
-
-
-/* Configuration descriptor */
-_static __u8 root_hub_config_des[] =
-{
-	0x09,			/*  __u8  bLength; */
-	0x02,			/*  __u8  bDescriptorType; Configuration */
-	0x19,			/*  __u16 wTotalLength; */
-	0x00,
-	0x01,			/*  __u8  bNumInterfaces; */
-	0x01,			/*  __u8  bConfigurationValue; */
-	0x00,			/*  __u8  iConfiguration; */
-	0x40,			/*  __u8  bmAttributes; 
-				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
-	0x00,			/*  __u8  MaxPower; */
-
-     /* interface */
-	0x09,			/*  __u8  if_bLength; */
-	0x04,			/*  __u8  if_bDescriptorType; Interface */
-	0x00,			/*  __u8  if_bInterfaceNumber; */
-	0x00,			/*  __u8  if_bAlternateSetting; */
-	0x01,			/*  __u8  if_bNumEndpoints; */
-	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-	0x00,			/*  __u8  if_bInterfaceSubClass; */
-	0x00,			/*  __u8  if_bInterfaceProtocol; */
-	0x00,			/*  __u8  if_iInterface; */
-
-     /* endpoint */
-	0x07,			/*  __u8  ep_bLength; */
-	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
-	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
-	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 (struct urb *urb)
-{
-	int len = 1;
-	int i;
-	uhci_t *uhci = urb->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 *) urb->transfer_buffer = cpu_to_le16 (data);
-	urb->actual_length = len;
-	urb->status = 0;
-	
-	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);
-		urb->complete (urb);
-	}
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
-_static int rh_init_int_timer (struct urb *urb);
-
-_static void rh_int_timer_do (unsigned long ptr)
-{
-	int len;
-	struct urb *urb = (struct urb *) ptr;
-	uhci_t *uhci = urb->dev->bus->hcpriv;
-
-	if (uhci->rh.send) {
-		len = rh_send_irq (urb);
-		if (len > 0) {
-			urb->actual_length = len;
-			if (urb->complete)
-				urb->complete (urb);
-		}
-	}
-	rh_init_int_timer (urb);
-}
-
-/*-------------------------------------------------------------------------*/
-/* Root Hub INTs are polled by this timer, polling interval 20ms */
-
-_static int rh_init_int_timer (struct urb *urb)
-{
-	uhci_t *uhci = urb->dev->bus->hcpriv;
-
-	uhci->rh.interval = urb->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) urb;
-	uhci->rh.rh_int_timer.expires = jiffies + (HZ * 20) / 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 (struct urb *urb)
-{
-	struct usb_device *usb_dev = urb->dev;
-	uhci_t *uhci = usb_dev->bus->hcpriv;
-	unsigned int pipe = urb->pipe;
-	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
-	void *data = urb->transfer_buffer;
-	int leni = urb->transfer_buffer_length;
-	int len = 0;
-	int status = 0;
-	int stat = 0;
-	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", urb->interval);
-		uhci->rh.urb = urb;
-		uhci->rh.send = 1;
-		uhci->rh.interval = urb->interval;
-		rh_init_int_timer (urb);
-
-		return 0;
-	}
-
-
-	bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
-	wValue = le16_to_cpu (cmd->wValue);
-	wIndex = le16_to_cpu (cmd->wIndex);
-	wLength = le16_to_cpu (cmd->wLength);
-
-	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);
-			uhci_wait_ms (10);
-			uhci->rh.c_p_r[wIndex - 1] = 1;
-			CLR_RH_PORTSTAT (USBPORTSC_PR);
-			udelay (10);
-			SET_RH_PORTSTAT (USBPORTSC_PE);
-			uhci_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_t(unsigned int, leni,
-				  min_t(unsigned int,
-				      sizeof (root_hub_dev_des), wLength));
-			memcpy (data, root_hub_dev_des, len);
-			OK (len);
-		case (0x02):	/* configuration descriptor */
-			len = min_t(unsigned int, leni,
-				  min_t(unsigned int,
-				      sizeof (root_hub_config_des), wLength));
-			memcpy (data, root_hub_config_des, len);
-			OK (len);
-		case (0x03):	/* string descriptors */
-			len = usb_root_hub_string (wValue & 0xff,
-			        uhci->io_addr, "UHCI",
-				data, wLength);
-			if (len > 0) {
-				OK(min_t(int, leni, len));
-			} else 
-				stat = -EPIPE;
-		}
-		break;
-
-	case RH_GET_DESCRIPTOR | RH_CLASS:
-		root_hub_hub_des[2] = uhci->rh.numports;
-		len = min_t(unsigned int, leni,
-			  min_t(unsigned int, 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));
-
-	urb->actual_length = len;
-	urb->status = stat;
-	urb->dev=NULL;
-	if (urb->complete)
-		urb->complete (urb);
-	return 0;
-}
-/*-------------------------------------------------------------------------*/
-
-_static int rh_unlink_urb (struct urb *urb)
-{
-	uhci_t *uhci = urb->dev->bus->hcpriv;
-
-	if (uhci->rh.urb==urb) {
-		dbg("Root-Hub unlink IRQ");
-		uhci->rh.send = 0;
-		del_timer (&uhci->rh.rh_int_timer);
-	}
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-
-/*
- * 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 0;
-	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 -EOVERFLOW;
-	if (status & TD_CTRL_DBUFERR)	/* Buffer error */
-		return -ENOSR;
-	if (status & TD_CTRL_STALLED)	/* Stalled */
-		return -EPIPE;
-	if (status & TD_CTRL_ACTIVE)	/* Active */
-		return 0;
-
-	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 void uhci_unlink_urbs(uhci_t *s, struct usb_device *usb_dev, int remove_all)
-{
-	unsigned long flags;
-	struct list_head *p;
-	struct list_head *p2;
-	struct urb *urb;
-
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-	p = s->urb_list.prev;	
-	while (p != &s->urb_list) {
-		p2 = p;
-		p = p->prev ;
-		urb = list_entry (p2, struct urb, urb_list);
-		dbg("urb: %p, dev %p, %p", urb, usb_dev,urb->dev);
-		
-		//urb->transfer_flags |=USB_ASYNC_UNLINK; 
-			
-		if (remove_all || (usb_dev == urb->dev)) {
-			spin_unlock_irqrestore (&s->urb_list_lock, flags);
-			warn("forced removing of queued URB %p due to disconnect",urb);
-			uhci_unlink_urb(urb);
-			urb->dev = NULL; // avoid further processing of this URB
-			spin_lock_irqsave (&s->urb_list_lock, flags);
-			p = s->urb_list.prev;	
-		}
-	}
-	spin_unlock_irqrestore (&s->urb_list_lock, flags);
-}
-
-_static int uhci_free_dev (struct usb_device *usb_dev)
-{
-	uhci_t *s;
-	
-
-	if(!usb_dev || !usb_dev->bus || !usb_dev->bus->hcpriv)
-		return -EINVAL;
-	
-	s=(uhci_t*) usb_dev->bus->hcpriv;	
-	uhci_unlink_urbs(s, usb_dev, 0);
-
-	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 ((uhci_t*) usb_dev->bus->hcpriv);
-}
-
-struct usb_operations uhci_device_operations =
-{
-	allocate:		uhci_alloc_dev,
-	deallocate:		uhci_free_dev,
-	get_frame_number:	uhci_get_current_frame_number,
-	submit_urb:		uhci_submit_urb,
-	unlink_urb:		uhci_unlink_urb,
-};
-
-_static void correct_data_toggles(struct urb *urb)
-{
-	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), 
-		       !usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)));
-
-	while(urb) {
-		urb_priv_t *priv=urb->hcpriv;		
-		uhci_desc_t *qh = list_entry (priv->desc_list.next, uhci_desc_t, desc_list);
-		struct list_head *p = qh->vertical.next;
-		uhci_desc_t *td;
-		dbg("URB to correct %p\n", urb);
-	
-		for (; p != &qh->vertical; p = p->next) {
-			td = list_entry (p, uhci_desc_t, vertical);
-			td->hw.td.info^=cpu_to_le32(1<<TD_TOKEN_TOGGLE);
-		}
-		urb=priv->next_queued_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.
- * mode: PROCESS_TRANSFER_REGULAR: regular (unlink QH)
- *       PROCESS_TRANSFER_DONT_UNLINK: QHs already unlinked (for async unlink_urb)
- */
-
-_static int process_transfer (uhci_t *s, struct urb *urb, int mode)
-{
-	int ret = 0;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	struct list_head *qhl = urb_priv->desc_list.next;
-	uhci_desc_t *qh = list_entry (qhl, uhci_desc_t, desc_list);
-	struct list_head *p = qh->vertical.next;
-	uhci_desc_t *desc= list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
-	uhci_desc_t *last_desc = list_entry (desc->vertical.prev, uhci_desc_t, vertical);
-	int data_toggle = usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));	// save initial data_toggle
-	int maxlength; 	// extracted and remapped info from TD
-	int actual_length;
-	int status = 0;
-
-	//dbg("process_transfer: urb %p, urb_priv %p, qh %p last_desc %p\n",urb,urb_priv, qh, last_desc);
-
-	/* 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 (urb_priv->flags && 
-	    ((qh->hw.qh.element == cpu_to_le32(UHCI_PTR_TERM)) || !is_td_active(desc)))
-		goto transfer_finished;
-
-	urb->actual_length=0;
-
-	for (; p != &qh->vertical; p = p->next) {
-		desc = list_entry (p, uhci_desc_t, vertical);
-
-		if (is_td_active(desc)) {	// do not process active TDs
-			if (mode == CLEAN_TRANSFER_DELETION_MARK) // if called from async_unlink
-				uhci_clean_transfer(s, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
-			return ret;
-		}
-	
-		actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));		// extract transfer parameters from TD
-		maxlength = (((le32_to_cpu(desc->hw.td.info) >> 21) & 0x7ff) + 1) & 0x7ff;
-		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
-
-		if (status == -EPIPE) { 		// see if EP is stalled
-			// set up stalled condition
-			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-		}
-
-		if (status && (status != -EPIPE)) {	// if any error occurred stop processing of further TDs
-			// only set ret if status returned an error
-  is_error:
-			ret = status;
-			urb->error_count++;
-			break;
-		}
-		else if ((le32_to_cpu(desc->hw.td.info) & 0xff) != USB_PID_SETUP)
-			urb->actual_length += actual_length;
-
-		// got less data than requested
-		if ( (actual_length < maxlength)) {
-			if (urb->transfer_flags & USB_DISABLE_SPD) {
-				status = -EREMOTEIO;	// 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 (urb->pipe) == PIPE_CONTROL)) {
-				if (uhci_packetid(le32_to_cpu(last_desc->hw.td.info)) == USB_PID_OUT) {
-			
-					set_qh_element(qh, last_desc->dma_addr);  // re-trigger status stage
-					dbg("short packet during control transfer, retrigger status stage @ %p",last_desc);
-					urb_priv->flags = 1; // mark as short control packet
-					return 0;
-				}
-			}
-			// all other cases: short read is OK
-			data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info));
-			break;
-		}
-		else if (status)
-			goto is_error;
-
-		data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info));
-		queue_dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", actual_length, le32_to_cpu(desc->hw.td.status),status, data_toggle);      
-
-	}
-
-	if (usb_pipetype (urb->pipe) == PIPE_BULK ) {  /* toggle correction for short bulk transfers (nonqueued/queued) */
-
-		urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-		struct urb *next_queued_urb=priv->next_queued_urb;
-
-		if (next_queued_urb) {
-			urb_priv_t *next_priv=(urb_priv_t*)next_queued_urb->hcpriv;
-			uhci_desc_t *qh = list_entry (next_priv->desc_list.next, uhci_desc_t, desc_list);
-			uhci_desc_t *first_td=list_entry (qh->vertical.next, uhci_desc_t, vertical);
-
-			if (data_toggle == uhci_toggle (le32_to_cpu(first_td->hw.td.info))) {
-				err("process_transfer: fixed toggle");
-				correct_data_toggles(next_queued_urb);
-			}						
-		}
-		else
-			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), !data_toggle);		
-	}
-
- transfer_finished:
-	
-	uhci_clean_transfer(s, urb, qh, mode);
-
-	urb->status = status;
-
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH	
-	disable_desc_loop(s,urb);
-#endif	
-
-	queue_dbg("process_transfer: (end) urb %p, wanted len %d, len %d status %x err %d",
-		urb,urb->transfer_buffer_length,urb->actual_length, urb->status, urb->error_count);
-	return ret;
-}
-
-_static int process_interrupt (uhci_t *s, struct urb *urb)
-{
-	int i, ret = -EINPROGRESS;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	struct list_head *p = urb_priv->desc_list.next;
-	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
-
-	int actual_length;
-	int status = 0;
-
-	//dbg("urb contains interrupt request");
-
-	for (i = 0; p != &urb_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 (is_td_active(desc)) {
-			// do not process active TDs
-			//dbg("TD ACT Status @%p %08x",desc,le32_to_cpu(desc->hw.td.status));
-			break;
-		}
-
-		if (!(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) {
-			// do not process one-shot TDs, no recycling
-			break;
-		}
-		// extract transfer parameters from TD
-
-		actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));
-		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
-
-		// see if EP is stalled
-		if (status == -EPIPE) {
-			// set up stalled condition
-			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-		}
-
-		// if any error occurred: ignore this td, and continue
-		if (status != 0) {
-			//uhci_show_td (desc);
-			urb->error_count++;
-			goto recycle;
-		}
-		else
-			urb->actual_length = actual_length;
-
-	recycle:
-		uhci_urb_dma_sync(s, urb, urb->hcpriv);
-		if (urb->complete) {
-			//dbg("process_interrupt: calling completion, status %i",status);
-			urb->status = status;
-			((urb_priv_t*)urb->hcpriv)->flags=1; // if unlink_urb is called during completion
-
-			spin_unlock(&s->urb_list_lock);
-			
-			urb->complete ((struct urb *) urb);
-			
-			spin_lock(&s->urb_list_lock);
-
-			((urb_priv_t*)urb->hcpriv)->flags=0;		       			
-		}
-		
-		if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) &&
-			    (urb->status != -ENOENT)) {
-
-			urb->status = -EINPROGRESS;
-
-			// Recycle INT-TD if interval!=0, else mark TD as one-shot
-			if (urb->interval) {
-				
-				desc->hw.td.info &= cpu_to_le32(~(1 << TD_TOKEN_TOGGLE));
-				if (status==0) {
-					((urb_priv_t*)urb->hcpriv)->started=jiffies;
-					desc->hw.td.info |= cpu_to_le32((usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
-									    usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE));
-					usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-				} else {
-					desc->hw.td.info |= cpu_to_le32((!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
-									     usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE));
-				}
-				desc->hw.td.status= cpu_to_le32(TD_CTRL_ACTIVE | TD_CTRL_IOC |
-					(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27));
-				if (urb->dev->speed == USB_SPEED_LOW)
-					desc->hw.td.status |=
-					    __constant_cpu_to_le32 (TD_CTRL_LS);
-				mb();
-			}
-			else {
-				uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
-				// correct toggle after unlink
-				usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-				clr_td_ioc(desc); // inactivate TD
-			}
-		}
-	}
-
-	return ret;
-}
-
-// mode: PROCESS_ISO_REGULAR: processing only for done TDs, unlink TDs
-// mode: PROCESS_ISO_FORCE: force processing, don't unlink TDs (already unlinked)
-
-_static int process_iso (uhci_t *s, struct urb *urb, int mode)
-{
-	int i;
-	int ret = 0;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	struct list_head *p = urb_priv->desc_list.next, *p_tmp;
-	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
-
-	dbg("urb contains iso request");
-	if (is_td_active(desc) && mode==PROCESS_ISO_REGULAR)
-		return -EXDEV;	// last TD not finished
-
-	urb->error_count = 0;
-	urb->actual_length = 0;
-	urb->status = 0;
-	dbg("process iso urb %p, %li, %i, %i, %i %08x",urb,jiffies,UHCI_GET_CURRENT_FRAME(s),
-	    urb->number_of_packets,mode,le32_to_cpu(desc->hw.td.status));
-
-	for (i = 0; p != &urb_priv->desc_list;  i++) {
-		desc = list_entry (p, uhci_desc_t, desc_list);
-		
-		//uhci_show_td(desc);
-		if (is_td_active(desc)) {
-			// means we have completed the last TD, but not the TDs before
-			desc->hw.td.status &= cpu_to_le32(~TD_CTRL_ACTIVE);
-			dbg("TD still active (%x)- grrr. paranoia!", le32_to_cpu(desc->hw.td.status));
-			ret = -EXDEV;
-			urb->iso_frame_desc[i].status = ret;
-			unlink_td (s, desc, 1);
-			// FIXME: immediate deletion may be dangerous
-			goto err;
-		}
-
-		if (mode == PROCESS_ISO_REGULAR)
-			unlink_td (s, desc, 1);
-
-		if (urb->number_of_packets <= i) {
-			dbg("urb->number_of_packets (%d)<=(%d)", urb->number_of_packets, i);
-			ret = -EINVAL;
-			goto err;
-		}
-
-		urb->iso_frame_desc[i].actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));
-		urb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
-		urb->actual_length += urb->iso_frame_desc[i].actual_length;
-
-	      err:
-
-		if (urb->iso_frame_desc[i].status != 0) {
-			urb->error_count++;
-			urb->status = urb->iso_frame_desc[i].status;
-		}
-		dbg("process_iso: %i: len:%d %08x status:%x",
-		     i, urb->iso_frame_desc[i].actual_length, le32_to_cpu(desc->hw.td.status),urb->iso_frame_desc[i].status);
-
-		p_tmp = p;
-		p = p->next;
-		list_del (p_tmp);
-		delete_desc (s, desc);
-	}
-	
-	dbg("process_iso: exit %i (%d), actual_len %i", i, ret,urb->actual_length);
-	return ret;
-}
-
-
-_static int process_urb (uhci_t *s, struct list_head *p)
-{
-	int ret = 0;
-	struct urb *urb;
-
-	urb=list_entry (p, struct urb, urb_list);
-	//dbg("process_urb: found queued urb: %p", urb);
-
-	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-		ret = process_transfer (s, urb, CLEAN_TRANSFER_REGULAR);
-		break;
-	case PIPE_BULK:
-		if (!s->avoid_bulk.counter)
-			ret = process_transfer (s, urb, CLEAN_TRANSFER_REGULAR);
-		else
-			return 0;
-		break;
-	case PIPE_ISOCHRONOUS:
-		ret = process_iso (s, urb, PROCESS_ISO_REGULAR);
-		break;
-	case PIPE_INTERRUPT:
-		ret = process_interrupt (s, urb);
-		break;
-	}
-
-	if (urb->status != -EINPROGRESS) {
-		urb_priv_t *urb_priv;
-		struct usb_device *usb_dev;
-		
-		usb_dev=urb->dev;
-
-		/* Release bandwidth for Interrupt or Iso transfers */
-		if (urb->bandwidth) {
-			if (usb_pipetype(urb->pipe)==PIPE_ISOCHRONOUS)
-				usb_release_bandwidth (urb->dev, urb, 1);
-			else if (usb_pipetype(urb->pipe)==PIPE_INTERRUPT && urb->interval)
-				usb_release_bandwidth (urb->dev, urb, 0);
-		}
-
-		dbg("dequeued urb: %p", urb);
-		dequeue_urb (s, urb);
-
-		urb_priv = urb->hcpriv;
-
-		uhci_urb_dma_unmap(s, urb, urb_priv);
-
-#ifdef DEBUG_SLAB
-		kmem_cache_free(urb_priv_kmem, urb_priv);
-#else
-		kfree (urb_priv);
-#endif
-
-		if ((usb_pipetype (urb->pipe) != PIPE_INTERRUPT)) {  // process_interrupt does completion on its own		
-			
-			// Completion
-			if (urb->complete) {
-				urb->dev = NULL;
-				spin_unlock(&s->urb_list_lock);
-				urb->complete ((struct urb *) urb);
-				spin_lock(&s->urb_list_lock);
-			}
-			
-			usb_put_dev (usb_dev);
-			usb_put_urb (urb);
-		}
-	}
-
-	return ret;
-}
-
-_static void uhci_interrupt (int irq, void *__uhci, struct pt_regs *regs)
-{
-	uhci_t *s = __uhci;
-	unsigned int io_addr = s->io_addr;
-	unsigned short status;
-	struct list_head *p, *p2;
-	int restarts, work_done;
-	
-	/*
-	 * 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");
-
-	if (status != 1) {
-		// Avoid too much error messages at a time
-		if (time_after(jiffies, s->last_error_time + ERROR_SUPPRESSION_TIME)) {
-			warn("interrupt, status %x, frame# %i", status, 
-			     UHCI_GET_CURRENT_FRAME(s));
-			s->last_error_time = jiffies;
-		}
-		
-		// remove host controller halted state
-		if ((status&0x20) && (s->running)) {
-			err("Host controller halted, trying to restart.");
-			outw (USBCMD_RS | inw(io_addr + USBCMD), io_addr + USBCMD);
-		}
-		//uhci_show_status (s);
-	}
-	/*
-	 * 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
-	 * New: check for max. workload and restart count
-	 */
-
-	spin_lock (&s->urb_list_lock);
-
-	restarts=0;
-	work_done=0;
-
-restart:
-	s->unlink_urb_done=0;
-	p = s->urb_list.prev;	
-
-	while (p != &s->urb_list && (work_done < 1024)) {
-		p2 = p;
-		p = p->prev;
-
-		process_urb (s, p2);
-		
-		work_done++;
-
-		if (s->unlink_urb_done) {
-			s->unlink_urb_done=0;
-			restarts++;
-			
-			if (restarts<16)	// avoid endless restarts
-				goto restart;
-			else 
-				break;
-		}
-	}
-	if (time_after(jiffies, s->timeout_check + (HZ/30)))
-		uhci_check_timeouts(s);
-
-	clean_descs(s, CLEAN_NOT_FORCED);
-	uhci_cleanup_unlink(s, CLEAN_NOT_FORCED);
-	uhci_switch_timer_int(s);
-							
-	spin_unlock (&s->urb_list_lock);
-	
-	outw (status, io_addr + USBSTS);
-
-	//dbg("uhci_interrupt: done");
-}
-
-_static void reset_hc (uhci_t *s)
-{
-	unsigned int io_addr = s->io_addr;
-
-	s->apm_state = 0;
-	/* Global reset for 50ms */
-	outw (USBCMD_GRESET, io_addr + USBCMD);
-	uhci_wait_ms (50);
-	outw (0, io_addr + USBCMD);
-	uhci_wait_ms (10);
-}
-
-_static void start_hc (uhci_t *s)
-{
-	unsigned int io_addr = s->io_addr;
-	int timeout = 10;
-
-	/*
-	 * 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;
-		}
-		udelay(1);
-	}
-
-	/* 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 (s->framelist_dma, 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;
-}
-
-/* No  __devexit, since it maybe called from alloc_uhci() */
-_static void
-uhci_pci_remove (struct pci_dev *dev)
-{
-	uhci_t *s = pci_get_drvdata(dev);
-	struct usb_device *root_hub = s->bus->root_hub;
-
-	s->running = 0;		    // Don't allow submit_urb
-
-	if (root_hub)
-		usb_disconnect (&root_hub);
-
-	reset_hc (s);
-	wait_ms (1);
-
-	uhci_unlink_urbs (s, 0, CLEAN_FORCED);  // Forced unlink of remaining URBs
-	uhci_cleanup_unlink (s, CLEAN_FORCED);  // force cleanup of async killed URBs
-	
-	usb_deregister_bus (s->bus);
-
-	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 (uhci_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_register_root_hub (usb_dev, &s->uhci_pci->dev) != 0) {
-		usb_free_dev (usb_dev);
-		return -1;
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-_static int
-uhci_pci_suspend (struct pci_dev *dev, u32 state)
-{
-	reset_hc((uhci_t *) pci_get_drvdata(dev));
-	return 0;
-}
-
-_static int
-uhci_pci_resume (struct pci_dev *dev)
-{
-	start_hc((uhci_t *) pci_get_drvdata(dev));
-	return 0;
-}
-#endif
-
-_static int __devinit alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
-{
-	uhci_t *s;
-	struct usb_bus *bus;
-	char buf[8], *bufp = buf;
-
-#ifndef __sparc__
-	sprintf(buf, "%d", irq);
-#else
-	bufp = __irq_itoa(irq);
-#endif
-	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
-		io_addr, bufp);
-
-	s = kmalloc (sizeof (uhci_t), GFP_KERNEL);
-	if (!s)
-		return -1;
-
-	memset (s, 0, sizeof (uhci_t));
-	INIT_LIST_HEAD (&s->free_desc);
-	INIT_LIST_HEAD (&s->urb_list);
-	INIT_LIST_HEAD (&s->urb_unlinked);
-	spin_lock_init (&s->urb_list_lock);
-	spin_lock_init (&s->qh_lock);
-	spin_lock_init (&s->td_lock);
-	atomic_set(&s->avoid_bulk, 0);
-	s->irq = -1;
-	s->io_addr = io_addr;
-	s->io_size = io_size;
-	s->uhci_pci=dev;
-
-	bus = usb_alloc_bus (&uhci_device_operations);
-	if (!bus) {
-		kfree (s);
-		return -1;
-	}
-
-	s->bus = bus;
-	bus->hcpriv = s;
-	bus->bus_name = dev->slot_name;
-
-	/* 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;
-	}
-	warn("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;
-	s->loop_usage=0;
-	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;
-	}
-
-	/* Enable PIRQ */
-	pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
-
-	s->irq = irq;
-
-	if(uhci_start_usb (s) < 0) {
-		uhci_pci_remove(dev);
-		return -1;
-	}
-
-	//chain new uhci device into global list
-	pci_set_drvdata(dev, s);
-	devs=s;
-
-	return 0;
-}
-
-_static int __devinit
-uhci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
-{
-	int i;
-
-	if (pci_enable_device(dev) < 0)
-		return -ENODEV;
-		
-	if (!dev->irq) {
-		err("found UHCI device with no IRQ assigned. check BIOS settings!");
-		return -ENODEV;
-	}
-	
-	pci_set_master(dev);
-
-	/* Search for the IO base address.. */
-	for (i = 0; i < 6; i++) {
-
-		unsigned int io_addr = pci_resource_start(dev, i);
-		unsigned int io_size = pci_resource_len(dev, i);
-		if (!(pci_resource_flags(dev,i) & IORESOURCE_IO))
-			continue;
-
-		/* Is it already in use? */
-		if (check_region (io_addr, io_size))
-			break;
-		/* disable legacy emulation */
-		pci_write_config_word (dev, USBLEGSUP, 0);
-	
-		return alloc_uhci(dev, dev->irq, io_addr, io_size);
-	}
-	return -ENODEV;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static const struct pci_device_id __devinitdata uhci_pci_ids [] = { {
-
-	/* handle any USB UHCI controller */
-	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x00),
-	class_mask: 	~0,
-
-	/* no matter who makes it */
-	vendor:		PCI_ANY_ID,
-	device:		PCI_ANY_ID,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
-
-	}, { /* end: all zeroes */ }
-};
-
-MODULE_DEVICE_TABLE (pci, uhci_pci_ids);
-
-static struct pci_driver uhci_pci_driver = {
-	name:		"usb-uhci",
-	id_table:	&uhci_pci_ids [0],
-
-	probe:		uhci_pci_probe,
-	remove:		uhci_pci_remove,
-
-#ifdef	CONFIG_PM
-	suspend:	uhci_pci_suspend,
-	resume:		uhci_pci_resume,
-#endif	/* PM */
-
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int __init uhci_hcd_init (void) 
-{
-	int retval;
-
-#ifdef DEBUG_SLAB
-	urb_priv_kmem = kmem_cache_create("urb_priv", 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);
-
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-	info("High bandwidth mode enabled");	
-#endif
-
-	retval = pci_module_init (&uhci_pci_driver);
-
-#ifdef DEBUG_SLAB
-	if (retval < 0 ) {
-		if (kmem_cache_destroy(urb_priv_kmem))
-			err("urb_priv_kmem remained");
-	}
-#endif
-	
-	info(DRIVER_VERSION ":" DRIVER_DESC);
-
-	return retval;
-}
-
-static void __exit uhci_hcd_cleanup (void) 
-{      
-	pci_unregister_driver (&uhci_pci_driver);
-	
-#ifdef DEBUG_SLAB
-	if(kmem_cache_destroy(urb_priv_kmem))
-		err("urb_priv_kmem remained");
-#endif
-}
-
-module_init (uhci_hcd_init);
-module_exit (uhci_hcd_cleanup);
-
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/host/usb-uhci.h b/drivers/usb/host/usb-uhci.h
--- a/drivers/usb/host/usb-uhci.h	Tue Jul 16 16:49:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,307 +0,0 @@
-#ifndef __LINUX_UHCI_H
-#define __LINUX_UHCI_H
-
-/*
-   $Id: usb-uhci.h,v 1.58 2001/08/28 16:45:00 acher Exp $
- */
-#define MODNAME "usb-uhci"
-#define UHCI_LATENCY_TIMER 0
-
-static __inline__ void uhci_wait_ms(unsigned int ms)
-{
-	if(!in_interrupt())
-	{
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1 + ms * HZ / 1000);
-	}
-	else
-		mdelay(ms);
-}
-
-/* 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_PID 		0xff	/* PID MASK */
-
-#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 */
-
-/*
- * 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;
-	dma_addr_t dma_addr;
-	struct list_head horizontal;
-	struct list_head vertical;
-	struct list_head desc_list;
-	int last_used;
-} uhci_desc_t, *puhci_desc_t;
-
-typedef struct {
-	struct list_head desc_list;	// list pointer to all corresponding TDs/QHs associated with this request
-	dma_addr_t setup_packet_dma;
-	dma_addr_t transfer_buffer_dma;
-	unsigned long started;
-	struct urb *next_queued_urb;	// next queued urb for this EP
-	struct urb *prev_queued_urb;
-	uhci_desc_t *bottom_qh;
-	uhci_desc_t *next_qh;       	// next helper QH
-	char use_loop;
-	char flags;
-} 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 
-
-	int unlink_urb_done;
-	atomic_t avoid_bulk;
-	
-	struct usb_bus *bus;	// our bus
-
-	__u32 *framelist;
-	dma_addr_t framelist_dma;
-	uhci_desc_t **iso_td;
-	uhci_desc_t *int_chain[8];
-	uhci_desc_t *ls_control_chain;
-	uhci_desc_t *control_chain;
-	uhci_desc_t *bulk_chain;
-	uhci_desc_t *chain_end;
-	uhci_desc_t *td1ms;
-	uhci_desc_t *td32ms;
-	struct list_head free_desc;
-	spinlock_t qh_lock;
-	spinlock_t td_lock;
-	struct virt_root_hub rh;	//private data of the virtual root hub
-	int loop_usage;            // URBs using bandwidth reclamation
-
-	struct list_head urb_unlinked;	// list of all unlinked  urbs
-	long timeout_check;
-	int timeout_urbs;
-	struct pci_dev *uhci_pci;
-	struct pci_pool *desc_pool;
-	long last_error_time;          // last error output in uhci_interrupt()
-} uhci_t, *puhci_t;
-
-
-#define MAKE_TD_ADDR(a) ((a)->dma_addr&~UHCI_PTR_QH)
-#define MAKE_QH_ADDR(a) ((a)->dma_addr|UHCI_PTR_QH)
-#define UHCI_GET_CURRENT_FRAME(uhci) (inw ((uhci)->io_addr + USBFRNUM))
-
-#define CLEAN_TRANSFER_NO_DELETION 0
-#define CLEAN_TRANSFER_REGULAR 1
-#define CLEAN_TRANSFER_DELETION_MARK 2
-
-#define CLEAN_NOT_FORCED 0
-#define CLEAN_FORCED 1
-
-#define PROCESS_ISO_REGULAR 0
-#define PROCESS_ISO_FORCE 1
-
-#define UNLINK_ASYNC_STORE_URB 0
-#define UNLINK_ASYNC_DONT_STORE 1
-
-#define is_td_active(desc) (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE))
-
-#define set_qh_head(desc,val) (desc)->hw.qh.head=cpu_to_le32(val)
-#define set_qh_element(desc,val) (desc)->hw.qh.element=cpu_to_le32(val)
-#define set_td_link(desc,val) (desc)->hw.td.link=cpu_to_le32(val)
-#define set_td_ioc(desc) (desc)->hw.td.status |= cpu_to_le32(TD_CTRL_IOC)
-#define clr_td_ioc(desc) (desc)->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC)
-
-
-/* ------------------------------------------------------------------------------------ 
-   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
-
-#endif
diff -Nru a/drivers/usb/input/Config.help b/drivers/usb/input/Config.help
--- a/drivers/usb/input/Config.help	Tue Jul 16 16:49:43 2002
+++ b/drivers/usb/input/Config.help	Tue Jul 16 16:49:43 2002
@@ -23,6 +23,23 @@
 
   If unsure, say Y.
 
+CONFIG_HID_FF
+  Say Y here is you want force feedback support for a few hid devices. See
+  below for a list of supported devices.
+  See Documentation/input/ff.txt for a description of the force feedback API.
+
+  If unsure, say N.
+
+CONFIG_LOGITECH_RUMBLE
+  Say Y here if you have a Logitech WingMan Cordless rumble pad and if you
+  want to enable force feedback. Note: if you say N here, this device will
+  still be supported, but without force feedback.
+
+CONFIG_HID_PID
+  Say Y yes if you have a PID-compliant joystick and wish to enable force
+  feedback for it. The Microsoft Sidewinder Force Feedback 2 is one such
+  device.
+
 CONFIG_USB_HIDDEV
   Say Y here if you want to support HID devices (from the USB
   specification standpoint) that aren't strictly user interface
@@ -83,3 +100,31 @@
   inserted in and removed from the running kernel whenever you want).
   The module will be called wacom.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_POWERMATE
+  Say Y here if you want to use  Griffin PowerMate or Contour Jog devices.
+  These are stainless steel dials which can measure clockwise and
+  anticlockwise rotation. The dial also acts as a pushbutton. The base
+  contains an LED which can be instructed to pulse or to switch to a
+  particular intensity.
+
+  You can download userspace tools from http://sowerbutts.com/powermate/
+
+  This driver 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 powermate.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_XPAD
+  Say Y here if you want to use the X-Box pad with your computer.
+  Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV)
+  and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well.
+
+  For information about how to connect the X-Box pad to USB, see
+  Documentation/input/xpad.txt.
+
+  This driver 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 wacom.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
diff -Nru a/drivers/usb/input/Config.in b/drivers/usb/input/Config.in
--- a/drivers/usb/input/Config.in	Tue Jul 16 16:49:43 2002
+++ b/drivers/usb/input/Config.in	Tue Jul 16 16:49:43 2002
@@ -3,10 +3,16 @@
 #
 comment 'USB Human Interface Devices (HID)'
 dep_tristate '  USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB
+
 if [ "$CONFIG_INPUT" = "n" ]; then
    comment '    Input core support is needed for USB HID input layer or HIDBP support'
 fi
+
 dep_mbool '    HID input layer support' CONFIG_USB_HIDINPUT $CONFIG_INPUT $CONFIG_USB_HID
+dep_mbool '      Force feedback support (EXPERIMENTAL)' CONFIG_HID_FF $CONFIG_USB_HIDINPUT $CONFIG_EXPERIMENTAL
+dep_mbool '        PID Devices' CONFIG_HID_PID $CONFIG_USB_HID $CONFIG_HID_FF
+dep_mbool '        Logitech RumblePad support' CONFIG_LOGITECH_RUMBLE $CONFIG_USB_HID $CONFIG_HID_FF
+dep_mbool '        Logitech WingMan Force 3D support' CONFIG_LOGITECH_3D $CONFIG_USB_HID $CONFIG_HID_FF
 dep_mbool '    /dev/hiddev raw HID device support' CONFIG_USB_HIDDEV $CONFIG_USB_HID
 
 if [ "$CONFIG_USB_HID" != "y" ]; then
@@ -16,4 +22,5 @@
 
 dep_tristate '  Aiptek 6000U/8000U tablet support' CONFIG_USB_AIPTEK $CONFIG_USB $CONFIG_INPUT
 dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
-   
+dep_tristate '  Griffin PowerMate and Contour Jog support' CONFIG_USB_POWERMATE $CONFIG_USB $CONFIG_INPUT
+dep_tristate '  X-Box gamepad support' CONFIG_USB_XPAD $CONFIG_USB $CONFIG_INPUT
diff -Nru a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
--- a/drivers/usb/input/Makefile	Tue Jul 16 16:49:41 2002
+++ b/drivers/usb/input/Makefile	Tue Jul 16 16:49:41 2002
@@ -6,18 +6,32 @@
 hid-objs	:= hid-core.o
 
 # Optional parts of multipart objects.
+
 ifeq ($(CONFIG_USB_HIDDEV),y)
 	hid-objs        += hiddev.o
 endif
 ifeq ($(CONFIG_USB_HIDINPUT),y)
 	hid-objs        += hid-input.o
 endif
+ifeq ($(CONFIG_HID_PID),y)
+	hid-objs	+= pid.o
+endif
+ifeq ($(CONFIG_LOGITECH_RUMBLE),y)
+	hid-objs	+= hid-lgff.o
+endif
+ifeq ($(CONFIG_LOGITECH_3D),y)
+	hid-objs	+= hid-lg3dff.o
+endif
+ifeq ($(CONFIG_HID_FF),y)
+	hid-objs	+= hid-ff.o
+endif
 
 obj-$(CONFIG_USB_AIPTEK)	+= aiptek.o
 obj-$(CONFIG_USB_HID)		+= hid.o
 obj-$(CONFIG_USB_KBD)		+= usbkbd.o
 obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o
 obj-$(CONFIG_USB_WACOM)		+= wacom.o
-
+obj-$(CONFIG_USB_POWERMATE)	+= powermate.o
+obj-$(CONFIG_USB_XPAD)		+= xpad.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/usb/input/fixp-arith.h b/drivers/usb/input/fixp-arith.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/input/fixp-arith.h	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,84 @@
+#ifndef _FIXP_ARITH_H
+#define _FIXP_ARITH_H
+
+/*
+ * $$
+ *
+ * Simplistic fixed-point arithmetics.
+ * Hmm, I'm probably duplicating some code :(
+ *
+ * Copyright (c) 2002 Johann Deneux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <deneux@ifrance.com>
+ */
+
+#include <linux/types.h>
+
+// The type representing fixed-point values
+typedef s16 fixp_t;
+
+#define FRAC_N 8
+#define FRAC_MASK ((1<<FRAC_N)-1)
+
+// Not to be used directly. Use fixp_{cos,sin}
+fixp_t cos_table[45] = {
+	0x0100,	0x00FF,	0x00FF,	0x00FE,	0x00FD,	0x00FC,	0x00FA,	0x00F8,
+	0x00F6,	0x00F3,	0x00F0,	0x00ED,	0x00E9,	0x00E6,	0x00E2,	0x00DD,
+	0x00D9,	0x00D4,	0x00CF,	0x00C9,	0x00C4,	0x00BE,	0x00B8,	0x00B1,
+	0x00AB,	0x00A4,	0x009D,	0x0096,	0x008F,	0x0087,	0x0080,	0x0078,
+	0x0070,	0x0068,	0x005F,	0x0057,	0x004F,	0x0046,	0x003D,	0x0035,
+	0x002C,	0x0023,	0x001A,	0x0011,	0x0008
+};
+
+
+/* a: 123 -> 123.0 */
+inline fixp_t fixp_new(s16 a)
+{
+	return a<<FRAC_N;
+}
+
+/* a: 0xFFFF -> -1.0
+      0x8000 -> 1.0
+      0x0000 -> 0.0
+*/
+inline fixp_t fixp_new16(s16 a)
+{
+	return ((s32)a)>>(16-FRAC_N);
+}
+
+inline fixp_t fixp_cos(unsigned int degrees)
+{
+	int quadrant = (degrees / 90) & 3;
+	unsigned int i = (degrees % 90) >> 1;
+
+	return (quadrant == 1 || quadrant == 2)? -cos_table[i] : cos_table[i];
+}
+
+inline fixp_t fixp_sin(unsigned int degrees)
+{
+	return -fixp_cos(degrees + 90);
+}
+
+inline fixp_t fixp_mult(fixp_t a, fixp_t b)
+{
+	return ((s32)(a*b))>>FRAC_N;
+}
+
+#endif
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/input/hid-core.c	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: hid-core.c,v 1.42 2002/01/27 00:22:46 vojtech Exp $
+ * $Id: hid-core.c,v 1.6 2002/06/09 17:34:55 jdeneux Exp $
  *
  *  Copyright (c) 1999 Andreas Gal
  *  Copyright (c) 2000-2001 Vojtech Pavlik
@@ -108,11 +108,10 @@
 	memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
 		+ values * sizeof(unsigned));
 
-	report->field[report->maxfield] = field;
+	report->field[report->maxfield++] = field;
 	field->usage = (struct hid_usage *)(field + 1);
 	field->value = (unsigned *)(field->usage + usages);
 	field->report = report;
-	field->index = report->maxfield++;
 
 	return field;
 }
@@ -128,18 +127,41 @@
 
 	usage = parser->local.usage[0];
 
-	if (type == HID_COLLECTION_APPLICATION
-		&& parser->device->maxapplication < HID_MAX_APPLICATIONS)
-			parser->device->application[parser->device->maxapplication++] = usage;
-
 	if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
 		dbg("collection stack overflow");
 		return -1;
 	}
 
-	collection = parser->collection_stack + parser->collection_stack_ptr++;
+	if (parser->device->maxcollection == parser->device->collection_size) {
+		collection = kmalloc(sizeof(struct hid_collection) *
+				     parser->device->collection_size * 2,
+				     GFP_KERNEL);
+		if (collection == NULL) {
+			dbg("failed to reallocate collection array");
+			return -1;
+		}
+		memcpy(collection, parser->device->collection,
+		       sizeof(struct hid_collection) *
+		       parser->device->collection_size);
+		memset(collection + parser->device->collection_size, 0,
+		       sizeof(struct hid_collection) *
+		       parser->device->collection_size);
+		kfree(parser->device->collection);
+		parser->device->collection = collection;
+		parser->device->collection_size *= 2;
+	}
+
+	parser->collection_stack[parser->collection_stack_ptr++] =
+		parser->device->maxcollection;
+
+	collection = parser->device->collection + 
+		parser->device->maxcollection++;
 	collection->type = type;
 	collection->usage = usage;
+	collection->level = parser->collection_stack_ptr - 1;
+	
+	if (type == HID_COLLECTION_APPLICATION)
+		parser->device->maxapplication++;
 
 	return 0;
 }
@@ -167,8 +189,8 @@
 {
 	int n;
 	for (n = parser->collection_stack_ptr - 1; n >= 0; n--)
-		if (parser->collection_stack[n].type == type)
-			return parser->collection_stack[n].usage;
+		if (parser->device->collection[parser->collection_stack[n]].type == type)
+			return parser->device->collection[parser->collection_stack[n]].usage;
 	return 0; /* we know nothing about this usage type */
 }
 
@@ -182,7 +204,11 @@
 		dbg("usage index exceeded");
 		return -1;
 	}
-	parser->local.usage[parser->local.usage_index++] = usage;
+	parser->local.usage[parser->local.usage_index] = usage;
+	parser->local.collection_index[parser->local.usage_index] =
+		parser->collection_stack_ptr ? 
+		parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
+	parser->local.usage_index++;
 	return 0;
 }
 
@@ -222,8 +248,11 @@
 	field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
 	field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
 
-	for (i = 0; i < usages; i++)
+	for (i = 0; i < usages; i++) {
 		field->usage[i].hid = parser->local.usage[i];
+		field->usage[i].collection_index =
+			parser->local.collection_index[i];
+	}
 
 	field->maxusage = usages;
 	field->flags = flags;
@@ -461,7 +490,7 @@
 
 	switch (item->tag) {
 		case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
-			ret = open_collection(parser, data & 3);
+			ret = open_collection(parser, data & 0xff);
 			break;
 		case HID_MAIN_ITEM_TAG_END_COLLECTION:
 			ret = close_collection(parser);
@@ -518,6 +547,8 @@
 {
 	unsigned i,j;
 
+	hid_ff_exit(device);
+
 	for (i = 0; i < HID_REPORT_TYPES; i++) {
 		struct hid_report_enum *report_enum = device->report_enum + i;
 
@@ -620,17 +651,30 @@
 		return NULL;
 	memset(device, 0, sizeof(struct hid_device));
 
+	if (!(device->collection = kmalloc(sizeof(struct hid_collection) *
+					   HID_DEFAULT_NUM_COLLECTIONS,
+					   GFP_KERNEL))) {
+		kfree(device);
+		return NULL;
+	}
+	memset(device->collection, 0, sizeof(struct hid_collection) *
+	       HID_DEFAULT_NUM_COLLECTIONS);
+	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+
 	for (i = 0; i < HID_REPORT_TYPES; i++)
 		INIT_LIST_HEAD(&device->report_enum[i].report_list);
 
 	if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) {
+		kfree(device->collection);
 		kfree(device);
 		return NULL;
 	}
 	memcpy(device->rdesc, start, size);
+	device->rsize = size;
 
 	if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
 		kfree(device->rdesc);
+		kfree(device->collection);
 		kfree(device);
 		return NULL;
 	}
@@ -642,6 +686,8 @@
 
 		if (item.format != HID_ITEM_FORMAT_SHORT) {
 			dbg("unexpected long global item");
+			kfree(device->rdesc);
+			kfree(device->collection);
 			hid_free_device(device);
 			kfree(parser);
 			return NULL;
@@ -650,6 +696,8 @@
 		if (dispatch_type[item.type](parser, &item)) {
 			dbg("item %u %u %u %u parsing failed\n",
 				item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
+			kfree(device->rdesc);
+			kfree(device->collection);
 			hid_free_device(device);
 			kfree(parser);
 			return NULL;
@@ -658,12 +706,16 @@
 		if (start == end) {
 			if (parser->collection_stack_ptr) {
 				dbg("unbalanced collection at end of report description");
+				kfree(device->rdesc);
+				kfree(device->collection);
 				hid_free_device(device);
 				kfree(parser);
 				return NULL;
 			}
 			if (parser->local.delimiter_depth) {
 				dbg("unbalanced delimiter at end of report description");
+				kfree(device->rdesc);
+				kfree(device->collection);
 				hid_free_device(device);
 				kfree(parser);
 				return NULL;
@@ -674,6 +726,8 @@
 	}
 
 	dbg("item fetching failed at offset %d\n", (int)(end - start));
+	kfree(device->rdesc);
+	kfree(device->collection);
 	hid_free_device(device);
 	kfree(parser);
 	return NULL;
@@ -739,22 +793,8 @@
 	hid_dump_input(usage, value);
 	if (hid->claimed & HID_CLAIMED_INPUT)
 		hidinput_hid_event(hid, field, usage, value);
-#ifdef CONFIG_USB_HIDDEV
-	if (hid->claimed & HID_CLAIMED_HIDDEV) {
-		struct hiddev_usage_ref uref;
-		unsigned type = field->report_type;
-		uref.report_type = 
-		  (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
-		  ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : 
-		   ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
-		uref.report_id = field->report->id;
-		uref.field_index = field->index;
-		uref.usage_index = (usage - field->usage);
-		uref.usage_code = usage->hid;
-		uref.value = value;
-		hiddev_hid_event(hid, &uref);
-	}
-#endif
+	if (hid->claimed & HID_CLAIMED_HIDDEV)
+		hiddev_hid_event(hid, field, usage, value);
 }
 
 /*
@@ -850,21 +890,6 @@
 		return -1;
 	}
 
-#ifdef CONFIG_USB_HIDDEV
-	/* Notify listeners that a report has been received */
-	if (hid->claimed & HID_CLAIMED_HIDDEV) {
-		struct hiddev_usage_ref uref;
-		memset(&uref, 0, sizeof(uref));
-		uref.report_type = 
-		  (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
-		  ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : 
-		   ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
-		uref.report_id = report->id;
-		uref.field_index = HID_FIELD_INDEX_NONE;
-		hiddev_hid_event(hid, &uref);
-	}
-#endif
-
 	size = ((report->size - 1) >> 3) + 1;
 
 	if (len < size) {
@@ -872,6 +897,9 @@
 		return -1;
 	}
 
+	if (hid->claimed & HID_CLAIMED_HIDDEV)
+		hiddev_report_event(hid, report);
+
 	for (n = 0; n < report->maxfield; n++)
 		hid_input_field(hid, report->field[n], data);
 
@@ -1171,8 +1199,8 @@
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	add_wait_queue(&hid->wait, &wait);
 
-	while (timeout && test_bit(HID_CTRL_RUNNING, &hid->iofl) &&
-			  test_bit(HID_OUT_RUNNING, &hid->iofl))
+	while (timeout && (test_bit(HID_CTRL_RUNNING, &hid->iofl) ||
+			   test_bit(HID_OUT_RUNNING, &hid->iofl)))
 		timeout = schedule_timeout(timeout);
 
 	set_current_state(TASK_RUNNING);
@@ -1223,6 +1251,7 @@
 	struct hid_report *report;
 	struct list_head *list;
 	int len;
+	int err, ret;
 
 	report_enum = hid->report_enum + HID_INPUT_REPORT;
 	list = report_enum->report_list.next;
@@ -1240,7 +1269,16 @@
 		list = list->next;
 	}
 
-	if (hid_wait_io(hid)) {
+	err = 0;
+	while ((ret = hid_wait_io(hid))) {
+		err |= ret;
+		if (test_bit(HID_CTRL_RUNNING, &hid->iofl))
+			usb_unlink_urb(hid->urbctrl);
+		if (test_bit(HID_OUT_RUNNING, &hid->iofl))
+			usb_unlink_urb(hid->urbout);
+	}
+
+	if (err) {
 		warn("timeout initializing reports\n");
 		return;
 	}
@@ -1273,6 +1311,10 @@
 #define USB_DEVICE_ID_ATEN_2PORTKVM    0x2204
 #define USB_DEVICE_ID_ATEN_4PORTKVM    0x2205
 
+#define USB_VENDOR_ID_MGE              0x0463
+#define USB_DEVICE_ID_MGE_UPS          0xffff
+#define USB_DEVICE_ID_MGE_UPS1         0x0001
+
 struct hid_blacklist {
 	__u16 idVendor;
 	__u16 idProduct;
@@ -1290,6 +1332,8 @@
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV },
+	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV },
 	{ 0, 0 }
 };
 
@@ -1299,7 +1343,7 @@
 	struct hid_descriptor *hdesc;
 	struct hid_device *hid;
 	unsigned quirks = 0, rsize = 0;
-	char *buf;
+	char *buf, *rdesc;
 	int n;
 
 	for (n = 0; hid_blacklist[n].idVendor; n++)
@@ -1325,27 +1369,31 @@
 		return NULL;
 	}
 
-	{
-		__u8 rdesc[rsize];
+	if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
+		dbg("couldn't allocate rdesc memory");
+		return NULL;
+	}
 
-		if ((n = hid_get_class_descriptor(dev, interface->bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
-			dbg("reading report descriptor failed");
-			return NULL;
-		}
+	if ((n = hid_get_class_descriptor(dev, interface->bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
+		dbg("reading report descriptor failed");
+		kfree(rdesc);
+		return NULL;
+	}
 
 #ifdef DEBUG_DATA
-		printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
-		for (n = 0; n < rsize; n++)
-			printk(" %02x", (unsigned) rdesc[n]);
-		printk("\n");
+	printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
+	for (n = 0; n < rsize; n++)
+		printk(" %02x", (unsigned) rdesc[n]);
+	printk("\n");
 #endif
 
-		if (!(hid = hid_parse_report(rdesc, rsize))) {
-			dbg("parsing report descriptor failed");
-			return NULL;
-		}
+	if (!(hid = hid_parse_report(rdesc, rsize))) {
+		dbg("parsing report descriptor failed");
+		kfree(rdesc);
+		return NULL;
 	}
 
+	kfree(rdesc);
 	hid->quirks = quirks;
 
 	for (n = 0; n < interface->bNumEndpoints; n++) {
@@ -1423,6 +1471,27 @@
 	return NULL;
 }
 
+static void hid_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct hid_device *hid = ptr;
+
+	usb_unlink_urb(hid->urbin);
+	usb_unlink_urb(hid->urbout);
+	usb_unlink_urb(hid->urbctrl);
+
+	if (hid->claimed & HID_CLAIMED_INPUT)
+		hidinput_disconnect(hid);
+	if (hid->claimed & HID_CLAIMED_HIDDEV)
+		hiddev_disconnect(hid);
+
+	usb_free_urb(hid->urbin);
+	usb_free_urb(hid->urbctrl);
+	if (hid->urbout)
+		usb_free_urb(hid->urbout);
+
+	hid_free_device(hid);
+}
+
 static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
 		       const struct usb_device_id *id)
 {
@@ -1439,13 +1508,15 @@
 	hid_init_reports(hid);
 	hid_dump_device(hid);
 
+	hid_ff_init(hid);
+
 	if (!hidinput_connect(hid))
 		hid->claimed |= HID_CLAIMED_INPUT;
 	if (!hiddev_connect(hid))
 		hid->claimed |= HID_CLAIMED_HIDDEV;
 
 	if (!hid->claimed) {
-		hid_free_device(hid);
+		hid_disconnect(dev, hid);
 		return NULL;
 	}
 
@@ -1459,11 +1530,14 @@
 		printk("hiddev%d", hid->minor);
 
 	c = "Device";
-	for (i = 0; i < hid->maxapplication; i++)
-		if ((hid->application[i] & 0xffff) < ARRAY_SIZE(hid_types)) {
-			c = hid_types[hid->application[i] & 0xffff];
+	for (i = 0; i < hid->maxcollection; i++) {
+		if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
+		    (hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
+		    (hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) {
+			c = hid_types[hid->collection[i].usage & 0xffff];
 			break;
 		}
+	}
 
 	usb_make_path(dev, path, 63);
 
@@ -1471,27 +1545,6 @@
 		hid->version >> 8, hid->version & 0xff, c, hid->name, path);
 
 	return hid;
-}
-
-static void hid_disconnect(struct usb_device *dev, void *ptr)
-{
-	struct hid_device *hid = ptr;
-
-	dbg("cleanup called");
-	usb_unlink_urb(hid->urbin);
-	usb_unlink_urb(hid->urbout);
-	usb_unlink_urb(hid->urbctrl);
-
-	usb_free_urb(hid->urbin);
-	usb_free_urb(hid->urbctrl);
-	if (hid->urbout)
-		usb_free_urb(hid->urbout);
-
-	if (hid->claimed & HID_CLAIMED_INPUT)
-		hidinput_disconnect(hid);
-	if (hid->claimed & HID_CLAIMED_HIDDEV)
-		hiddev_disconnect(hid);
-	hid_free_device(hid);
 }
 
 static struct usb_device_id hid_usb_ids [] = {
diff -Nru a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h
--- a/drivers/usb/input/hid-debug.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/usb/input/hid-debug.h	Tue Jul 16 16:49:41 2002
@@ -345,19 +345,13 @@
 	printk(")\n");
 }
 
-static void hid_dump_device(struct hid_device *device) {
+static void __attribute__((unused)) hid_dump_device(struct hid_device *device) {
 	struct hid_report_enum *report_enum;
 	struct hid_report *report;
 	struct list_head *list;
 	unsigned i,k;
 	static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
 	
-	for (i = 0; i < device->maxapplication; i++) {
-		printk("Application(");
-		resolv_usage(device->application[i]);
-		printk(")\n");
-	}
-
 	for (i = 0; i < HID_REPORT_TYPES; i++) {
 		report_enum = device->report_enum + i;
 		list = report_enum->report_list.next;
@@ -379,7 +373,7 @@
 	}
 }
 
-static void hid_dump_input(struct hid_usage *usage, __s32 value) {
+static void __attribute__((unused)) hid_dump_input(struct hid_usage *usage, __s32 value) {
 	printk("hid-debug: input ");
 	resolv_usage(usage->hid);
 	printk(" = %d\n", value);
diff -Nru a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/input/hid-ff.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,90 @@
+/*
+ * $Id: hid-ff.c,v 1.3 2002/06/09 11:06:38 jdeneux Exp $
+ *
+ *  Force feedback support for hid devices.
+ *  Not all hid devices use the same protocol. For example, some use PID,
+ *  other use their own proprietary procotol.
+ *
+ *  Copyright (c) 2002 Johann Deneux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <deneux@ifrance.com>
+ */
+
+#include <linux/input.h>
+
+#define DEBUG
+#include <linux/usb.h>
+
+#include "hid.h"
+
+/* Drivers' initializing functions */
+extern int hid_lgff_init(struct hid_device* hid);
+extern int hid_lg3d_init(struct hid_device* hid);
+extern int hid_pid_init(struct hid_device* hid);
+
+/*
+ * This table contains pointers to initializers. To add support for new
+ * devices, you need to add the USB vendor and product ids here.
+ */
+struct hid_ff_initializer {
+	__u16 idVendor;
+	__u16 idProduct;
+	int (*init)(struct hid_device*);
+};
+
+static struct hid_ff_initializer inits[] = {
+#ifdef CONFIG_LOGITECH_RUMBLE
+	{0x46d, 0xc211, hid_lgff_init},
+#endif
+#ifdef CONFIG_LOGITECH_3D
+	{0x46d, 0xc283, hid_lg3d_init},
+#endif
+#ifdef CONFIG_HID_PID
+	{0x45e, 0x001b, hid_pid_init},
+#endif
+	{0, 0, NULL} /* Terminating entry */
+};
+
+static struct hid_ff_initializer *hid_get_ff_init(__u16 idVendor,
+						  __u16 idProduct)
+{
+	struct hid_ff_initializer *init;
+	for (init = inits;
+	     init->idVendor
+		     && !(init->idVendor == idVendor
+			  && init->idProduct == idProduct);
+	     init++);
+
+	return init->idVendor? init : NULL;
+}
+
+int hid_ff_init(struct hid_device* hid)
+{
+	struct hid_ff_initializer *init;
+
+	init = hid_get_ff_init(hid->dev->descriptor.idVendor,
+			       hid->dev->descriptor.idProduct);
+
+	if (!init) {
+		warn("hid_ff_init could not find initializer");
+		return -ENOSYS;
+	}
+	return init->init(hid);
+}
diff -Nru a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
--- a/drivers/usb/input/hid-input.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/input/hid-input.c	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: hid-input.c,v 1.18 2001/11/07 09:01:18 vojtech Exp $
+ * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $
  *
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
@@ -273,9 +273,53 @@
 
 			usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
 			break;
+			
+		case HID_UP_PID:
 
+			usage->type = EV_FF; bit = input->ffbit; max = FF_MAX;
+			
+			switch(usage->hid & HID_USAGE) {
+				case 0x26: set_bit(FF_CONSTANT, input->ffbit); break;
+				case 0x27: set_bit(FF_RAMP,     input->ffbit); break;
+				case 0x28: set_bit(FF_CUSTOM,   input->ffbit); break;
+				case 0x30: set_bit(FF_SQUARE,   input->ffbit);
+				           set_bit(FF_PERIODIC, input->ffbit); break;
+				case 0x31: set_bit(FF_SINE,     input->ffbit);
+				           set_bit(FF_PERIODIC, input->ffbit); break;
+				case 0x32: set_bit(FF_TRIANGLE, input->ffbit);
+				           set_bit(FF_PERIODIC, input->ffbit); break;
+				case 0x33: set_bit(FF_SAW_UP,   input->ffbit);
+				           set_bit(FF_PERIODIC, input->ffbit); break;
+				case 0x34: set_bit(FF_SAW_DOWN, input->ffbit);
+				           set_bit(FF_PERIODIC, input->ffbit); break;
+				case 0x40: set_bit(FF_SPRING,   input->ffbit); break;
+				case 0x41: set_bit(FF_DAMPER,   input->ffbit); break;
+				case 0x42: set_bit(FF_INERTIA , input->ffbit); break;
+				case 0x43: set_bit(FF_FRICTION, input->ffbit); break;
+				case 0x7e: usage->code = FF_GAIN;       break;
+				case 0x83:  /* Simultaneous Effects Max */
+					input->ff_effects_max = (field->value[0]);
+					dbg("Maximum Effects - %d",input->ff_effects_max);
+					break;
+				case 0x98:  /* Device Control */
+					usage->code = FF_AUTOCENTER;    break;
+				case 0xa4:  /* Safety Switch */
+					usage->code = BTN_DEAD;
+					bit = input->keybit;
+					usage->type = EV_KEY;
+					max = KEY_MAX;
+					dbg("Safety Switch Report\n");
+					break;
+				case 0x9f: /* Device Paused */
+				case 0xa0: /* Actuators Enabled */
+					dbg("Not telling the input API about ");
+					resolv_usage(usage->hid);
+					return;
+			}
+			break;
 		default:
 		unknown:
+			resolv_usage(usage->hid);
 
 			if (field->report_size == 1) {
 
@@ -365,6 +409,16 @@
 		input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
 	}
 
+	if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
+		input->ff_effects_max = value;
+		dbg("Maximum Effects - %d",input->ff_effects_max);
+		return;
+	}
+	if (usage->hid == (HID_UP_PID | 0x7fUL)) {
+		dbg("PID Pool Report\n");
+		return;
+	}
+
 	if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UKNOWN */
 		return;
 
@@ -380,6 +434,9 @@
 	struct hid_field *field = NULL;
 	int offset;
 
+	if (type == EV_FF)
+		return hid_ff_event(hid, dev, type, code, value);
+
 	if ((offset = hid_find_field(hid, type, code, &field)) == -1) {
 		warn("event field not found");
 		return -1;
@@ -417,11 +474,12 @@
 	struct list_head *list;
 	int i, j, k;
 
-	for (i = 0; i < hid->maxapplication; i++)
-		if (IS_INPUT_APPLICATION(hid->application[i]))
+	for (i = 0; i < hid->maxcollection; i++)
+		if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
+		    IS_INPUT_APPLICATION(hid->collection[i].usage))
 			break;
 
-	if (i == hid->maxapplication)
+	if (i == hid->maxcollection)
 		return -1;
 
 	hid->input.private = hid;
diff -Nru a/drivers/usb/input/hid-lg3dff.c b/drivers/usb/input/hid-lg3dff.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/input/hid-lg3dff.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,444 @@
+/*
+ * $$
+ *
+ *  Force feedback support for hid-compliant devices of the Logitech *3D family
+ *
+ *  Copyright (c) 2002 Johann Deneux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <deneux@ifrance.com>
+ */
+
+#include <linux/input.h>
+#include <linux/sched.h>
+
+#define DEBUG
+#include <linux/usb.h>
+
+#include <linux/circ_buf.h>
+
+#include "hid.h"
+#include "fixp-arith.h"
+
+#define RUN_AT(t) (jiffies + (t))
+
+/* Periodicity of the update */
+#define PERIOD (HZ/10)
+
+/* Effect status: lg3d_effect::flags */
+#define EFFECT_STARTED 0     /* Effect is going to play after some time
+				(ff_replay.delay) */
+#define EFFECT_PLAYING 1     /* Effect is being played */
+#define EFFECT_USED    2
+
+/* Check that the current process can access an effect */
+#define CHECK_OWNERSHIP(i, l) \
+        (i>=0 && i<N_EFFECTS \
+        && test_bit(EFFECT_USED, l->effects[i].flags) \
+        && (current->pid == 0 \
+            || l->effects[i].owner == current->pid))
+
+#define N_EFFECTS 8
+
+struct lg3d_effect {
+	pid_t owner;
+
+	struct ff_effect effect;   /* Description of the effect */
+
+	unsigned int count;        /* Number of times left to play */
+	unsigned long flags[1];
+
+	unsigned long started_at;  /* When the effect started to play */
+};
+
+// For lg3d_device::flags
+#define DEVICE_USB_XMIT 0          /* An URB is being sent */
+#define DEVICE_CLOSING 1           /* The driver is being unitialised */
+
+struct lg3d_device {
+	struct hid_device* hid;
+
+	struct urb* urbffout;        /* Output URB used to send ff commands */
+	struct usb_ctrlrequest ffcr; /* ff commands use control URBs */
+	char buf[8];
+
+	struct lg3d_effect effects[N_EFFECTS];
+	spinlock_t lock;             /* device-level lock. Having locks on
+					a per-effect basis could be nice, but
+					isn't really necessary */
+	struct timer_list timer;
+	unsigned long last_time;     /* Last time the timer handler was
+					executed */
+
+	unsigned long flags[1];      /* Contains various information about the
+				        state of the driver for this device */
+};
+
+static void hid_lg3d_ctrl_out(struct urb *urb);
+static void hid_lg3d_exit(struct hid_device* hid);
+static int hid_lg3d_event(struct hid_device *hid, struct input_dev *input,
+			  unsigned int type, unsigned int code, int value);
+static int hid_lg3d_flush(struct input_dev *input, struct file *file);
+static int hid_lg3d_upload_effect(struct input_dev *input,
+				  struct ff_effect *effect);
+static int hid_lg3d_erase(struct input_dev *input, int id);
+static void hid_lg3d_timer(unsigned long timer_data);
+
+
+int hid_lg3d_init(struct hid_device* hid)
+{
+	struct lg3d_device *private;
+
+	/* Private data */
+	private = kmalloc(sizeof(struct lg3d_device), GFP_KERNEL);
+	if (!private) return -1;
+
+	memset(private, 0, sizeof(struct lg3d_device));
+
+	hid->ff_private = private;
+
+	private->hid = hid;
+	spin_lock_init(&private->lock);
+
+	/* Timer for the periodic update task */
+	init_timer(&private->timer);
+	private->timer.data = (unsigned long)private;
+	private->timer.function = hid_lg3d_timer;
+
+	/* Event and exit callbacks */
+	hid->ff_exit = hid_lg3d_exit;
+	hid->ff_event = hid_lg3d_event;
+
+	/* USB init */
+	if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) {
+		kfree(hid->ff_private);
+		return -1;
+	}
+
+	usb_fill_control_urb(private->urbffout, hid->dev, 0,
+			     (void*) &private->ffcr, private->buf, 8,
+			     hid_lg3d_ctrl_out, hid);
+	dbg("Created ff output control urb");
+
+	/* Input init */
+	hid->input.upload_effect = hid_lg3d_upload_effect;
+	hid->input.flush = hid_lg3d_flush;
+	set_bit(FF_CONSTANT, hid->input.ffbit);
+	set_bit(EV_FF, hid->input.evbit);
+	hid->input.ff_effects_max = N_EFFECTS;
+
+	printk(KERN_INFO "Force feedback for Logitech *3D devices by Johann Deneux <deneux@ifrance.com>\n");
+
+	/* Start the update task */
+	private->timer.expires = RUN_AT(PERIOD);
+	add_timer(&private->timer);  /*TODO: only run the timer when at least
+				       one effect is playing */
+
+	return 0;
+}
+
+static void hid_lg3d_exit(struct hid_device* hid)
+{
+	struct lg3d_device *lg3d = hid->ff_private;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&lg3d->lock, flags);
+	set_bit(DEVICE_CLOSING, lg3d->flags);
+	spin_unlock_irqrestore(&lg3d->lock, flags);
+
+	del_timer_sync(&lg3d->timer);
+
+	if (lg3d->urbffout) {
+		usb_unlink_urb(lg3d->urbffout);
+		usb_free_urb(lg3d->urbffout);
+	}
+
+	kfree(lg3d);
+}
+
+static int hid_lg3d_event(struct hid_device *hid, struct input_dev* input,
+			  unsigned int type, unsigned int code, int value)
+{
+	struct lg3d_device *lg3d = hid->ff_private;
+	struct lg3d_effect *effect = lg3d->effects + code;
+	unsigned long flags;
+
+	if (type != EV_FF)                return -EINVAL;
+       	if (!CHECK_OWNERSHIP(code, lg3d)) return -EACCES;
+	if (value < 0)                    return -EINVAL;
+
+	spin_lock_irqsave(&lg3d->lock, flags);
+	
+	if (value > 0) {
+		if (test_bit(EFFECT_STARTED, effect->flags)) {
+			spin_unlock_irqrestore(&lg3d->lock, flags);
+			return -EBUSY;
+		}
+		if (test_bit(EFFECT_PLAYING, effect->flags)) {
+			spin_unlock_irqrestore(&lg3d->lock, flags);
+			return -EBUSY;
+		}
+
+		effect->count = value;
+
+		if (effect->effect.replay.delay) {
+			set_bit(EFFECT_STARTED, effect->flags);
+		} else {
+			set_bit(EFFECT_PLAYING, effect->flags);
+		}
+		effect->started_at = jiffies;
+	}
+	else { /* value == 0 */
+		clear_bit(EFFECT_STARTED, effect->flags);
+		clear_bit(EFFECT_PLAYING, effect->flags);
+	}
+
+	spin_unlock_irqrestore(&lg3d->lock, flags);
+
+	return 0;
+}
+
+/* Erase all effects this process owns */
+static int hid_lg3d_flush(struct input_dev *dev, struct file *file)
+{
+	struct hid_device *hid = dev->private;
+	struct lg3d_device *lg3d = hid->ff_private;
+	int i;
+
+	for (i=0; i<dev->ff_effects_max; ++i) {
+
+		/*NOTE: no need to lock here. The only times EFFECT_USED is
+		  modified is when effects are uploaded or when an effect is
+		  erased. But a process cannot close its dev/input/eventX fd
+		  and perform ioctls on the same fd all at the same time */
+		if ( current->pid == lg3d->effects[i].owner
+		     && test_bit(EFFECT_USED, lg3d->effects[i].flags)) {
+			
+			if (hid_lg3d_erase(dev, i))
+				warn("erase effect %d failed", i);
+		}
+
+	}
+
+	return 0;
+}
+
+static int hid_lg3d_erase(struct input_dev *dev, int id)
+{
+	struct hid_device *hid = dev->private;
+	struct lg3d_device *lg3d = hid->ff_private;
+	unsigned long flags;
+
+	if (!CHECK_OWNERSHIP(id, lg3d)) return -EACCES;
+
+	spin_lock_irqsave(&lg3d->lock, flags);
+	lg3d->effects[id].flags[0] = 0;
+	spin_unlock_irqrestore(&lg3d->lock, flags);
+
+	return 0;
+}
+
+static int hid_lg3d_upload_effect(struct input_dev* input,
+				  struct ff_effect* effect)
+{
+	struct hid_device *hid = input->private;
+	struct lg3d_device *lg3d = hid->ff_private;
+	struct lg3d_effect new;
+	int id;
+	unsigned long flags;
+	
+	dbg("ioctl upload");
+
+	if (!test_bit(effect->type, input->ffbit)) return -EINVAL;
+
+	if (effect->type != FF_CONSTANT) return -EINVAL;
+
+	spin_lock_irqsave(&lg3d->lock, flags);
+
+	if (effect->id == -1) {
+		int i;
+
+		for (i=0; i<N_EFFECTS && test_bit(EFFECT_USED, lg3d->effects[i].flags); ++i);
+		if (i >= N_EFFECTS) {
+			spin_unlock_irqrestore(&lg3d->lock, flags);
+			return -ENOSPC;
+		}
+
+		effect->id = i;
+		lg3d->effects[i].owner = current->pid;
+		lg3d->effects[i].flags[0] = 0;
+		set_bit(EFFECT_USED, lg3d->effects[i].flags);
+	}
+	else if (!CHECK_OWNERSHIP(effect->id, lg3d)) {
+		spin_unlock_irqrestore(&lg3d->lock, flags);
+		return -EACCES;
+	}
+
+	id = effect->id;
+	new = lg3d->effects[id];
+
+	new.effect = *effect;
+	new.effect.replay = effect->replay;
+
+	if (test_bit(EFFECT_STARTED, lg3d->effects[id].flags)
+	    || test_bit(EFFECT_STARTED, lg3d->effects[id].flags)) {
+
+		/* Changing replay parameters is not allowed (for the time
+		   being) */
+		if (new.effect.replay.delay != lg3d->effects[id].effect.replay.delay
+		    || new.effect.replay.length != lg3d->effects[id].effect.replay.length) {
+			spin_unlock_irqrestore(&lg3d->lock, flags);
+			return -ENOSYS;
+		}
+
+		lg3d->effects[id] = new;
+
+	} else {
+		lg3d->effects[id] = new;
+	}
+
+	spin_unlock_irqrestore(&lg3d->lock, flags);
+	return 0;
+}
+
+static void hid_lg3d_ctrl_out(struct urb *urb)
+{
+	struct hid_device *hid = urb->context;
+	struct lg3d_device *lg3d = hid->ff_private;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lg3d->lock, flags);
+
+	if (urb->status)
+		warn("hid_irq_ffout status %d received", urb->status);
+	clear_bit(DEVICE_USB_XMIT, lg3d->flags);
+	dbg("xmit = 0");
+
+	spin_unlock_irqrestore(&lg3d->lock, flags);
+}
+
+static void hid_lg3d_timer(unsigned long timer_data)
+{
+	struct lg3d_device *lg3d = (struct lg3d_device*)timer_data;
+	struct hid_device *hid = lg3d->hid;
+	unsigned long flags;
+	int x, y;
+	int i;
+	int err;
+
+	spin_lock_irqsave(&lg3d->lock, flags);
+
+	if (test_bit(DEVICE_USB_XMIT, lg3d->flags)) {
+		if (lg3d->urbffout->status != -EINPROGRESS) {
+			warn("xmit *not* in progress");
+		}
+		else {
+			dbg("xmit in progress");
+		}
+
+		spin_unlock_irqrestore(&lg3d->lock, flags);
+
+		lg3d->timer.expires = RUN_AT(PERIOD);
+		add_timer(&lg3d->timer);
+
+		return;
+	}
+
+	x = 0x7f;
+	y = 0x7f;
+
+ 	for (i=0; i<N_EFFECTS; ++i) {
+		struct lg3d_effect* effect = lg3d->effects +i;
+
+		if (test_bit(EFFECT_PLAYING, effect->flags)) {
+
+			if (effect->effect.type == FF_CONSTANT) {
+				//TODO: handle envelopes
+				int degrees = effect->effect.direction * 360 >> 16;
+				x += fixp_mult(fixp_sin(degrees),
+					       fixp_new16(effect->effect.u.constant.level));
+				y += fixp_mult(-fixp_cos(degrees),
+					       fixp_new16(effect->effect.u.constant.level));
+			}
+
+			/* One run of the effect is finished playing */
+			if (time_after(jiffies,
+					effect->started_at
+					+ effect->effect.replay.delay*HZ/1000
+					+ effect->effect.replay.length*HZ/1000)) {
+				dbg("Finished playing once");
+				if (--effect->count <= 0) {
+					dbg("Stopped");
+					clear_bit(EFFECT_PLAYING, effect->flags);
+				}
+				else {
+					dbg("Start again");
+					if (effect->effect.replay.length != 0) {
+						clear_bit(EFFECT_PLAYING, effect->flags);
+						set_bit(EFFECT_STARTED, effect->flags);
+					}
+					effect->started_at = jiffies;
+				}
+			}
+
+		} else if (test_bit(EFFECT_STARTED, lg3d->effects[i].flags)) {
+			dbg("Started");
+			/* Check if we should start playing the effect */
+			if (time_after(jiffies,
+					lg3d->effects[i].started_at
+					+ lg3d->effects[i].effect.replay.delay*HZ/1000)) {
+				dbg("Now playing");
+				clear_bit(EFFECT_STARTED, lg3d->effects[i].flags);
+				set_bit(EFFECT_PLAYING, lg3d->effects[i].flags);
+			}
+		}
+ 	}
+
+	if (x < 0) x = 0;
+	if (x > 0xff) x = 0xff;
+	if (y < 0) y = 0;
+	if (y > 0xff) y = 0xff;
+	
+	lg3d->urbffout->pipe = usb_sndctrlpipe(hid->dev, 0);
+	lg3d->ffcr.bRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
+	lg3d->urbffout->transfer_buffer_length = lg3d->ffcr.wLength = 8;
+	lg3d->ffcr.bRequest = 9;
+	lg3d->ffcr.wValue = 0x0200;    /*NOTE: Potential problem with 
+					 little/big endian */
+	lg3d->ffcr.wIndex = 0;
+	
+	lg3d->urbffout->dev = hid->dev;
+	
+	lg3d->buf[0] = 0x51;
+	lg3d->buf[1] = 0x08;
+	lg3d->buf[2] = x;
+	lg3d->buf[3] = y;
+
+	if ((err=usb_submit_urb(lg3d->urbffout, GFP_ATOMIC)))
+		warn("usb_submit_urb returned %d", err);
+	else
+		set_bit(DEVICE_USB_XMIT, lg3d->flags);
+
+	if (!test_bit(DEVICE_CLOSING, lg3d->flags)) {
+		lg3d->timer.expires = RUN_AT(PERIOD);
+		add_timer(&lg3d->timer);
+	}
+
+ 	spin_unlock_irqrestore(&lg3d->lock, flags);
+}
diff -Nru a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/input/hid-lgff.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,495 @@
+/*
+ * $$
+ *
+ * Force feedback support for hid-compliant for some of the devices from
+ * Logitech, namely:
+ * - WingMan Cordless RumblePad
+ *
+ *  Copyright (c) 2002 Johann Deneux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <deneux@ifrance.com>
+ */
+
+#include <linux/input.h>
+#include <linux/sched.h>
+
+#define DEBUG
+#include <linux/usb.h>
+
+#include <linux/circ_buf.h>
+
+#include "hid.h"
+
+#define RUN_AT(t) (jiffies + (t))
+
+/* Transmition state */
+#define XMIT_RUNNING 0
+
+/* Effect status */
+#define EFFECT_STARTED 0     /* Effect is going to play after some time
+				(ff_replay.delay) */
+#define EFFECT_PLAYING 1     /* Effect is being played */
+#define EFFECT_USED    2
+
+/* Check that the current process can access an effect */
+#define CHECK_OWNERSHIP(effect) (current->pid == 0 \
+        || effect.owner == current->pid)
+
+/* **************************************************************************/
+/* Implements the protocol used by the Logitech WingMan Cordless RumblePad */
+/* **************************************************************************/
+
+#define LGFF_CHECK_OWNERSHIP(i, l) \
+        (i>=0 && i<LGFF_EFFECTS \
+        && test_bit(EFFECT_USED, l->effects[i].flags) \
+        && CHECK_OWNERSHIP(l->effects[i]))
+
+#define LGFF_BUFFER_SIZE 64
+#define LGFF_EFFECTS 8
+
+struct lgff_magnitudes {
+	unsigned char left;
+	unsigned char right;
+};
+
+struct lgff_effect {
+	int id;
+	struct hid_ff_logitech* lgff;
+
+	pid_t owner;
+	unsigned char left;        /* Magnitude of vibration for left motor */
+	unsigned char right;       /* Magnitude of vibration for right motor */
+	struct ff_replay replay;
+	unsigned int count;        /* Number of times to play */
+	struct timer_list timer;
+	unsigned long flags[1];
+};
+
+struct hid_ff_logitech {
+	struct hid_device* hid;
+
+	struct urb* urbffout;        /* Output URB used to send ff commands */
+	struct usb_ctrlrequest ffcr; /* ff commands use control URBs */
+	char buf[8];
+
+	spinlock_t xmit_lock;
+	unsigned int xmit_head, xmit_tail;
+	struct lgff_magnitudes xmit_data[LGFF_BUFFER_SIZE];
+	long xmit_flags[1];
+
+	struct lgff_effect effects[LGFF_EFFECTS];
+	spinlock_t lock;             /* device-level lock. Having locks on
+					a per-effect basis could be nice, but
+					isn't really necessary */
+};
+
+static void hid_lgff_ctrl_out(struct urb *urb);
+static void hid_lgff_exit(struct hid_device* hid);
+static int hid_lgff_event(struct hid_device *hid, struct input_dev *input,
+			  unsigned int type, unsigned int code, int value);
+static void hid_lgff_make_rumble(struct hid_device* hid);
+
+static int hid_lgff_flush(struct input_dev *input, struct file *file);
+static int hid_lgff_upload_effect(struct input_dev *input,
+				  struct ff_effect *effect);
+static int hid_lgff_erase(struct input_dev *input, int id);
+static void hid_lgff_ctrl_playback(struct hid_device* hid, struct lgff_effect*,
+				   int play);
+static void hid_lgff_timer(unsigned long timer_data);
+
+
+int hid_lgff_init(struct hid_device* hid)
+{
+	struct hid_ff_logitech *private;
+	int i;
+
+	/* Private data */
+	private = kmalloc(sizeof(struct hid_ff_logitech), GFP_KERNEL);
+	if (!private) return -1;
+
+	memset(private, 0, sizeof(struct hid_ff_logitech));
+
+	hid->ff_private = private;
+
+	private->hid = hid;
+	spin_lock_init(&private->lock);
+	spin_lock_init(&private->xmit_lock);
+
+	private->buf[0] = 0x03;
+	private->buf[1] = 0x42;
+
+	for (i=0; i<LGFF_EFFECTS; ++i) {
+		struct lgff_effect* effect = &private->effects[i];
+		struct timer_list* timer = &effect->timer;
+
+		init_timer(timer);
+		effect->id = i;
+		effect->lgff = private;
+		timer->data = (unsigned long)effect;
+		timer->function = hid_lgff_timer;
+	}
+
+	/* Event and exit callbacks */
+	hid->ff_exit = hid_lgff_exit;
+	hid->ff_event = hid_lgff_event;
+
+	/* USB init */
+	if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) {
+		kfree(hid->ff_private);
+		return -1;
+	}
+
+	usb_fill_control_urb(private->urbffout, hid->dev, 0,
+			     (void*) &private->ffcr, private->buf, 8,
+			     hid_lgff_ctrl_out, hid);
+	dbg("Created ff output control urb");
+
+	/* Input init */
+	hid->input.upload_effect = hid_lgff_upload_effect;
+	hid->input.flush = hid_lgff_flush;
+	set_bit(FF_RUMBLE, hid->input.ffbit);
+	set_bit(EV_FF, hid->input.evbit);
+	hid->input.ff_effects_max = LGFF_EFFECTS;
+
+	printk(KERN_INFO "Force feedback for Logitech rumble devices by Johann Deneux <deneux@ifrance.com>\n");
+
+	return 0;
+}
+
+static void hid_lgff_exit(struct hid_device* hid)
+{
+	struct hid_ff_logitech *lgff = hid->ff_private;
+
+	if (lgff->urbffout) {
+		usb_unlink_urb(lgff->urbffout);
+		usb_free_urb(lgff->urbffout);
+	}
+}
+
+static int hid_lgff_event(struct hid_device *hid, struct input_dev* input,
+			  unsigned int type, unsigned int code, int value)
+{
+	struct hid_ff_logitech *lgff = hid->ff_private;
+	struct lgff_effect *effect = lgff->effects + code;
+	unsigned long flags;
+
+	if (type != EV_FF)                     return -EINVAL;
+       	if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES;
+	if (value < 0)                         return -EINVAL;
+
+	spin_lock_irqsave(&lgff->lock, flags);
+	
+	if (value > 0) {
+		if (test_bit(EFFECT_STARTED, effect->flags)) {
+			spin_unlock_irqrestore(&lgff->lock, flags);
+			return -EBUSY;
+		}
+		if (test_bit(EFFECT_PLAYING, effect->flags)) {
+			spin_unlock_irqrestore(&lgff->lock, flags);
+			return -EBUSY;
+		}
+
+		effect->count = value;
+
+		if (effect->replay.delay) {
+			set_bit(EFFECT_STARTED, effect->flags);
+			effect->timer.expires = RUN_AT(effect->replay.delay * HZ / 1000);
+		} else {
+			hid_lgff_ctrl_playback(hid, effect, value);
+			effect->timer.expires = RUN_AT(effect->replay.length * HZ / 1000);
+		}
+
+		add_timer(&effect->timer);
+	}
+	else { /* value == 0 */
+		if (test_and_clear_bit(EFFECT_STARTED, effect->flags)) {
+			del_timer(&effect->timer);
+
+		} else if (test_and_clear_bit(EFFECT_PLAYING, effect->flags)) {
+			del_timer(&effect->timer);
+			hid_lgff_ctrl_playback(hid, effect, value);
+		}
+
+		if (test_bit(EFFECT_PLAYING, effect->flags))
+			warn("Effect %d still playing", code);
+	}
+
+	spin_unlock_irqrestore(&lgff->lock, flags);
+
+	return 0;
+
+}
+
+/* Erase all effects this process owns */
+static int hid_lgff_flush(struct input_dev *dev, struct file *file)
+{
+	struct hid_device *hid = dev->private;
+	struct hid_ff_logitech *lgff = hid->ff_private;
+	int i;
+
+	for (i=0; i<dev->ff_effects_max; ++i) {
+
+		/*NOTE: no need to lock here. The only times EFFECT_USED is
+		  modified is when effects are uploaded or when an effect is
+		  erased. But a process cannot close its dev/input/eventX fd
+		  and perform ioctls on the same fd all at the same time */
+		if ( current->pid == lgff->effects[i].owner
+		     && test_bit(EFFECT_USED, lgff->effects[i].flags)) {
+			
+			if (hid_lgff_erase(dev, i))
+				warn("erase effect %d failed", i);
+		}
+
+	}
+
+	return 0;
+}
+
+static int hid_lgff_erase(struct input_dev *dev, int id)
+{
+	struct hid_device *hid = dev->private;
+	struct hid_ff_logitech *lgff = hid->ff_private;
+	unsigned long flags;
+
+	if (!LGFF_CHECK_OWNERSHIP(id, lgff)) return -EACCES;
+
+	spin_lock_irqsave(&lgff->lock, flags);
+	hid_lgff_ctrl_playback(hid, lgff->effects + id, 0);
+	lgff->effects[id].flags[0] = 0;
+	spin_unlock_irqrestore(&lgff->lock, flags);
+
+	return 0;
+}
+
+static int hid_lgff_upload_effect(struct input_dev* input,
+				  struct ff_effect* effect)
+{
+	struct hid_device *hid = input->private;
+	struct hid_ff_logitech *lgff = hid->ff_private;
+	struct lgff_effect new;
+	int id;
+	unsigned long flags;
+	
+	dbg("ioctl rumble");
+
+	if (!test_bit(effect->type, input->ffbit)) return -EINVAL;
+
+	if (effect->type != FF_RUMBLE) return -EINVAL;
+
+	spin_lock_irqsave(&lgff->lock, flags);
+
+	if (effect->id == -1) {
+		int i;
+
+		for (i=0; i<LGFF_EFFECTS && test_bit(EFFECT_USED, lgff->effects[i].flags); ++i);
+		if (i >= LGFF_EFFECTS) {
+			spin_unlock_irqrestore(&lgff->lock, flags);
+			return -ENOSPC;
+		}
+
+		effect->id = i;
+		lgff->effects[i].owner = current->pid;
+		lgff->effects[i].flags[0] = 0;
+		set_bit(EFFECT_USED, lgff->effects[i].flags);
+	}
+	else if (!LGFF_CHECK_OWNERSHIP(effect->id, lgff)) {
+		spin_unlock_irqrestore(&lgff->lock, flags);
+		return -EACCES;
+	}
+
+	id = effect->id;
+	new = lgff->effects[id];
+
+	new.right = effect->u.rumble.strong_magnitude >> 9;
+	new.left = effect->u.rumble.weak_magnitude >> 9;
+	new.replay = effect->replay;
+
+	/* If we updated an effect that was being played, we need to remake
+	   the rumble effect */
+	if (test_bit(EFFECT_STARTED, lgff->effects[id].flags)
+	    || test_bit(EFFECT_STARTED, lgff->effects[id].flags)) {
+
+		/* Changing replay parameters is not allowed (for the time
+		   being) */
+		if (new.replay.delay != lgff->effects[id].replay.delay
+		    || new.replay.length != lgff->effects[id].replay.length) {
+			spin_unlock_irqrestore(&lgff->lock, flags);
+			return -ENOSYS;
+		}
+
+		lgff->effects[id] = new;
+		hid_lgff_make_rumble(hid);
+
+	} else {
+		lgff->effects[id] = new;
+	}
+
+	spin_unlock_irqrestore(&lgff->lock, flags);
+	return 0;
+}
+
+static void hid_lgff_xmit(struct hid_device* hid)
+{
+	struct hid_ff_logitech *lgff = hid->ff_private;
+	int err;
+	int tail;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lgff->xmit_lock, flags);
+
+	tail = lgff->xmit_tail;
+	if (lgff->xmit_head == tail) {
+		clear_bit(XMIT_RUNNING, lgff->xmit_flags);
+		spin_unlock_irqrestore(&lgff->xmit_lock, flags);
+		return;
+	}
+	lgff->buf[3] = lgff->xmit_data[tail].left;
+	lgff->buf[4] = lgff->xmit_data[tail].right;
+	tail++; tail &= LGFF_BUFFER_SIZE -1;
+	lgff->xmit_tail = tail;
+
+	spin_unlock_irqrestore(&lgff->xmit_lock, flags);
+
+	lgff->urbffout->pipe = usb_sndctrlpipe(hid->dev, 0);
+	lgff->ffcr.bRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
+	lgff->urbffout->transfer_buffer_length = lgff->ffcr.wLength = 8;
+	lgff->ffcr.bRequest = 9;
+	lgff->ffcr.wValue = 0x0203;    /*NOTE: Potential problem with 
+					 little/big endian */
+	lgff->ffcr.wIndex = 0;
+	
+	lgff->urbffout->dev = hid->dev;
+	
+	if ((err=usb_submit_urb(lgff->urbffout, GFP_ATOMIC)))
+		warn("usb_submit_urb returned %d", err);
+}
+
+static void hid_lgff_make_rumble(struct hid_device* hid)
+{
+	struct hid_ff_logitech *lgff = hid->ff_private;
+	int left = 0, right = 0;
+	int i;
+	int head, tail;
+	unsigned long flags;
+
+	for (i=0; i<LGFF_EFFECTS; ++i) {
+		if (test_bit(EFFECT_USED, lgff->effects[i].flags)
+		    && test_bit(EFFECT_PLAYING, lgff->effects[i].flags)) {
+			left += lgff->effects[i].left;
+			right += lgff->effects[i].right;
+		}
+	}
+
+	spin_lock_irqsave(&lgff->xmit_lock, flags);
+
+	head = lgff->xmit_head;
+	tail = lgff->xmit_tail;	
+
+	if (CIRC_SPACE(head, tail, LGFF_BUFFER_SIZE) < 1) {
+		warn("not enough space in xmit buffer to send new packet");
+		spin_unlock_irqrestore(&lgff->xmit_lock, flags);
+		return;
+	}
+
+	lgff->xmit_data[head].left = left > 0x7f ? 0x7f : left;
+	lgff->xmit_data[head].right = right > 0x7f ? 0x7f : right;
+	head++; head &= LGFF_BUFFER_SIZE -1;
+	lgff->xmit_head = head;
+
+	if (test_and_set_bit(XMIT_RUNNING, lgff->xmit_flags))
+		spin_unlock_irqrestore(&lgff->xmit_lock, flags);
+	else {
+		spin_unlock_irqrestore(&lgff->xmit_lock, flags);
+		hid_lgff_xmit(hid);
+	}
+}
+
+static void hid_lgff_ctrl_out(struct urb *urb)
+{
+	struct hid_device *hid = urb->context;
+
+	if (urb->status)
+		warn("hid_irq_ffout status %d received", urb->status);
+
+	hid_lgff_xmit(hid);
+}
+
+/* Lock must be held by caller */
+static void hid_lgff_ctrl_playback(struct hid_device *hid,
+				   struct lgff_effect *effect, int play)
+{
+	if (play) {
+		set_bit(EFFECT_PLAYING, effect->flags);
+		hid_lgff_make_rumble(hid);
+
+	} else {
+		clear_bit(EFFECT_PLAYING, effect->flags);
+		hid_lgff_make_rumble(hid);
+	}
+}
+
+static void hid_lgff_timer(unsigned long timer_data)
+{
+	struct lgff_effect *effect = (struct lgff_effect*) timer_data;
+	struct hid_ff_logitech* lgff = effect->lgff;
+	int id = effect->id;
+
+	unsigned long flags;
+
+	dbg("in hid_lgff_timer");
+
+	if (id < 0 || id >= LGFF_EFFECTS) {
+		warn("Bad effect id %d", id);
+		return;
+	}
+
+	effect = lgff->effects + id;
+
+	spin_lock_irqsave(&lgff->lock, flags);
+
+	if (!test_bit(EFFECT_USED, effect->flags)) {
+		warn("Unused effect id %d", id);
+
+	} else if (test_bit(EFFECT_STARTED, effect->flags)) {
+		clear_bit(EFFECT_STARTED, effect->flags);
+		set_bit(EFFECT_PLAYING, effect->flags);
+		hid_lgff_ctrl_playback(lgff->hid, effect, 1);
+		effect->timer.expires = RUN_AT(effect->replay.length * HZ / 1000);
+		add_timer(&effect->timer);
+
+		dbg("Effect %d starts playing", id);
+	} else if (test_bit(EFFECT_PLAYING, effect->flags)) {
+		clear_bit(EFFECT_PLAYING, effect->flags);
+		hid_lgff_ctrl_playback(lgff->hid, effect, 0);
+		if (--effect->count > 0) {
+			/*TODO: check that replay.delay is non-null */
+			set_bit(EFFECT_STARTED, effect->flags);
+			effect->timer.expires = RUN_AT(effect->replay.delay * HZ / 1000);
+			add_timer(&effect->timer);
+			dbg("Effect %d restarted", id);
+		} else {
+			dbg("Effect %d stopped", id);
+		}
+	} else {
+		warn("Effect %d is not started nor playing", id);
+	}
+
+	spin_unlock_irqrestore(&lgff->lock, flags);
+}
diff -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
--- a/drivers/usb/input/hid.h	Tue Jul 16 16:49:41 2002
+++ b/drivers/usb/input/hid.h	Tue Jul 16 16:49:41 2002
@@ -205,6 +205,7 @@
 #define HID_QUIRK_NOTOUCH	0x02
 #define HID_QUIRK_IGNORE	0x04
 #define HID_QUIRK_NOGET		0x08
+#define HID_QUIRK_HIDDEV	0x10
 
 /*
  * This is the global enviroment of the parser. This information is
@@ -231,10 +232,11 @@
 
 #define HID_MAX_DESCRIPTOR_SIZE		4096
 #define HID_MAX_USAGES			1024
-#define HID_MAX_APPLICATIONS		16
+#define HID_DEFAULT_NUM_COLLECTIONS	16
 
 struct hid_local {
 	unsigned usage[HID_MAX_USAGES]; /* usage array */
+	unsigned collection_index[HID_MAX_USAGES]; /* collection index array */
 	unsigned usage_index;
 	unsigned usage_minimum;
 	unsigned delimiter_depth;
@@ -249,10 +251,12 @@
 struct hid_collection {
 	unsigned type;
 	unsigned usage;
+	unsigned level;
 };
 
 struct hid_usage {
 	unsigned  hid;			/* hid usage code */
+	unsigned  collection_index;	/* index into collection array */
 	__u16     code;			/* input driver code */
 	__u8      type;			/* input driver type */
 	__s8	  hat_min;		/* hat switch fun */
@@ -319,7 +323,9 @@
 struct hid_device {							/* device report descriptor */
 	 __u8 *rdesc;
 	unsigned rsize;
-	unsigned application[HID_MAX_APPLICATIONS];			/* List of HID applications */
+	struct hid_collection *collection;				/* List of HID collections */
+	unsigned collection_size;					/* Number of allocated hid_collections */
+	unsigned maxcollection;						/* Number of parsed collections */
 	unsigned maxapplication;					/* Number of applications */
 	unsigned version;						/* HID version */
 	unsigned country;						/* HID country */
@@ -359,6 +365,11 @@
 	char name[128];							/* Device name */
 	char phys[64];							/* Device physical location */
 	char uniq[64];							/* Device unique identifier (serial #) */
+
+	void *ff_private;                                               /* Private data for the force-feedback driver */
+	void (*ff_exit)(struct hid_device*);                            /* Called by hid_exit_ff(hid) */
+	int (*ff_event)(struct hid_device *hid, struct input_dev *input,
+			unsigned int type, unsigned int code, int value);
 };
 
 #define HID_GLOBAL_STACK_SIZE 4
@@ -369,7 +380,7 @@
 	struct hid_global     global_stack[HID_GLOBAL_STACK_SIZE];
 	unsigned              global_stack_ptr;
 	struct hid_local      local;
-	struct hid_collection collection_stack[HID_COLLECTION_STACK_SIZE];
+	unsigned              collection_stack[HID_COLLECTION_STACK_SIZE];
 	unsigned              collection_stack_ptr;
 	struct hid_device    *device;
 };
@@ -395,6 +406,7 @@
 #define hid_dump_input(a,b)	do { } while (0)
 #define hid_dump_device(c)	do { } while (0)
 #define hid_dump_field(a,b)	do { } while (0)
+#define resolv_usage(a)		do { } while (0)
 #endif
 
 #endif
@@ -419,3 +431,23 @@
 int hid_set_field(struct hid_field *, unsigned, __s32);
 void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir);
 void hid_init_reports(struct hid_device *hid);
+int hid_find_report_by_usage(struct hid_device *hid, __u32 wanted_usage, struct hid_report **report, int type);
+
+
+#ifdef CONFIG_HID_FF
+int hid_ff_init(struct hid_device *hid);
+#else
+static inline int hid_ff_init(struct hid_device *hid) { return -1; }
+#endif
+static inline void hid_ff_exit(struct hid_device *hid)
+{
+	if (hid->ff_exit)
+		hid->ff_exit(hid);
+}
+static inline int hid_ff_event(struct hid_device *hid, struct input_dev *input,
+			unsigned int type, unsigned int code, int value)
+{
+	if (hid->ff_event)
+		return hid->ff_event(hid, input, type, code, value);
+	return -ENOSYS;
+}
diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
--- a/drivers/usb/input/hiddev.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/input/hiddev.c	Tue Jul 16 16:49:42 2002
@@ -80,6 +80,7 @@
 static struct hid_report *
 hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
 {
+	unsigned flags = rinfo->report_id & ~HID_REPORT_ID_MASK;
 	struct hid_report_enum *report_enum;
 	struct list_head *list;
 
@@ -88,27 +89,28 @@
 
 	report_enum = hid->report_enum +
 		(rinfo->report_type - HID_REPORT_TYPE_MIN);
-	if ((rinfo->report_id & ~HID_REPORT_ID_MASK) != 0) {
-		switch (rinfo->report_id & ~HID_REPORT_ID_MASK) {
-		case HID_REPORT_ID_FIRST:
-			list = report_enum->report_list.next;
-			if (list == &report_enum->report_list) return NULL;
-			rinfo->report_id = ((struct hid_report *) list)->id;
-			break;
-
-		case HID_REPORT_ID_NEXT:
-			list = (struct list_head *)
-				report_enum->report_id_hash[rinfo->report_id &
-							   HID_REPORT_ID_MASK];
-			if (list == NULL) return NULL;
-			list = list->next;
-			if (list == &report_enum->report_list) return NULL;
-			rinfo->report_id = ((struct hid_report *) list)->id;
-			break;
 
-		default:
-			return NULL;
-		}
+	switch (flags) {
+	case 0: /* Nothing to do -- report_id is already set correctly */
+		break;
+
+	case HID_REPORT_ID_FIRST:
+		list = report_enum->report_list.next;
+		if (list == &report_enum->report_list) return NULL;
+		rinfo->report_id = ((struct hid_report *) list)->id;
+		break;
+		
+	case HID_REPORT_ID_NEXT:
+		list = (struct list_head *)
+			report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK];
+		if (list == NULL) return NULL;
+		list = list->next;
+		if (list == &report_enum->report_list) return NULL;
+		rinfo->report_id = ((struct hid_report *) list)->id;
+		break;
+		
+	default:
+		return NULL;
 	}
 
 	return report_enum->report_id_hash[rinfo->report_id];
@@ -152,11 +154,8 @@
 	return NULL;
 }
 
-/*
- * This is where hid.c calls into hiddev to pass an event that occurred over
- * the interrupt pipe
- */
-void hiddev_hid_event(struct hid_device *hid, struct hiddev_usage_ref *uref)
+static void hiddev_send_event(struct hid_device *hid,
+			      struct hiddev_usage_ref *uref)
 {
 	struct hiddev *hiddev = hid->hiddev;
 	struct hiddev_list *list = hiddev->list;
@@ -177,6 +176,44 @@
 }
 
 /*
+ * This is where hid.c calls into hiddev to pass an event that occurred over
+ * the interrupt pipe
+ */
+void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
+		      struct hid_usage *usage, __s32 value)
+{
+	unsigned type = field->report_type;
+	struct hiddev_usage_ref uref;
+
+	uref.report_type = 
+	  (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
+	  ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : 
+	   ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
+	uref.report_id = field->report->id;
+	uref.field_index = field->index;
+	uref.usage_index = (usage - field->usage);
+	uref.usage_code = usage->hid;
+	uref.value = value;
+
+	hiddev_send_event(hid, &uref);
+}
+
+
+void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
+{
+	unsigned type = report->type;
+	struct hiddev_usage_ref uref;
+
+	memset(&uref, 0, sizeof(uref));
+	uref.report_type = 
+	  (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
+	  ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : 
+	   ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
+	uref.report_id = report->id;
+
+	hiddev_send_event(hid, &uref);
+}
+/*
  * fasync file op
  */
 static int hiddev_fasync(int fd, struct file *file, int on)
@@ -256,8 +293,7 @@
 /*
  * "write" file op
  */
-static ssize_t hiddev_write(struct file * file, const char * buffer,
-			    size_t count, loff_t *ppos)
+static ssize_t hiddev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
 {
 	return -EINVAL;
 }
@@ -265,8 +301,7 @@
 /*
  * "read" file op
  */
-static ssize_t hiddev_read(struct file * file, char * buffer, size_t count,
-			   loff_t *ppos)
+static ssize_t hiddev_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct hiddev_list *list = file->private_data;
@@ -354,17 +389,20 @@
 /*
  * "ioctl" file op
  */
-static int hiddev_ioctl(struct inode *inode, struct file *file,
-			unsigned int cmd, unsigned long arg)
+static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct hiddev_list *list = file->private_data;
 	struct hiddev *hiddev = list->hiddev;
 	struct hid_device *hid = hiddev->hid;
 	struct usb_device *dev = hid->dev;
+	struct hiddev_collection_info cinfo;
 	struct hiddev_report_info rinfo;
+	struct hiddev_field_info finfo;
 	struct hiddev_usage_ref uref;
+	struct hiddev_devinfo dinfo;
 	struct hid_report *report;
 	struct hid_field *field;
+	int i;
 
 	if (!hiddev->exist) return -EIO;
 
@@ -376,11 +414,18 @@
 	case HIDIOCAPPLICATION:
 		if (arg < 0 || arg >= hid->maxapplication)
 			return -EINVAL;
-		return hid->application[arg];
+
+		for (i = 0; i < hid->maxcollection; i++)
+			if (hid->collection[i].type == 
+			    HID_COLLECTION_APPLICATION && arg-- == 0)
+				break;
+		
+		if (i == hid->maxcollection)
+			return -EINVAL;
+
+		return hid->collection[i].usage;
 
 	case HIDIOCGDEVINFO:
-	{
-		struct hiddev_devinfo dinfo;
 		dinfo.bustype = BUS_USB;
 		dinfo.busnum = dev->bus->busnum;
 		dinfo.devnum = dev->devnum;
@@ -391,11 +436,10 @@
 		dinfo.num_applications = hid->maxapplication;
 		if (copy_to_user((void *) arg, &dinfo, sizeof(dinfo)))
 			return -EFAULT;
-		return 0;
-	}
 
 	case HIDIOCGFLAG:
-		return put_user(list->flags, (int *) arg);
+		if (put_user(list->flags, (int *) arg))
+			return -EFAULT;
 
 	case HIDIOCSFLAG:
 		{
@@ -440,7 +484,6 @@
 		}
 
 	case HIDIOCINITREPORT:
-
 		hid_init_reports(hid);
 
 		return 0;
@@ -484,11 +527,8 @@
 
 		if (copy_to_user((void *) arg, &rinfo, sizeof(rinfo)))
 			return -EFAULT;
-		return 0;
 
 	case HIDIOCGFIELDINFO:
-	{
-		struct hiddev_field_info finfo;
 		if (copy_from_user(&finfo, (void *) arg, sizeof(finfo)))
 			return -EFAULT;
 		rinfo.report_type = finfo.report_type;
@@ -518,8 +558,6 @@
 
 		if (copy_to_user((void *) arg, &finfo, sizeof(finfo)))
 			return -EFAULT;
-		return 0;
-	}
 
 	case HIDIOCGUCODE:
 		if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
@@ -541,16 +579,15 @@
 
 		if (copy_to_user((void *) arg, &uref, sizeof(uref)))
 			return -EFAULT;
-		return 0;
 
 	case HIDIOCGUSAGE:
 	case HIDIOCSUSAGE:
+	case HIDIOCGCOLLECTIONINDEX:
 		if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
 			return -EFAULT;
 
-		if (cmd == HIDIOCSUSAGE &&
-		    uref.report_type != HID_REPORT_TYPE_OUTPUT)
-			return -EINVAL;
+		if (cmd != HIDIOCGUSAGE && uref.report_type == HID_REPORT_TYPE_INPUT)
+				return -EINVAL;
 
 		if (uref.report_id == HID_REPORT_ID_UNKNOWN) {
 			field = hiddev_lookup_usage(hid, &uref);
@@ -570,17 +607,38 @@
 				return -EINVAL;
 		}
 
-		if (cmd == HIDIOCGUSAGE) {
-			uref.value = field->value[uref.usage_index];
-			if (copy_to_user((void *) arg, &uref, sizeof(uref)))
-				return -EFAULT;
-			return 0;
-		} else {
-			field->value[uref.usage_index] = uref.value;
+		switch (cmd) {
+			case HIDIOCGUSAGE:
+				uref.value = field->value[uref.usage_index];
+				if (copy_to_user((void *) arg, &uref, sizeof(uref)))
+					return -EFAULT;
+				return 0;
+
+			case HIDIOCSUSAGE:
+				field->value[uref.usage_index] = uref.value;
+				return 0;
+
+			case HIDIOCGCOLLECTIONINDEX:
+				return field->usage[uref.usage_index].collection_index;
 		}
 
 		return 0;
 
+	case HIDIOCGCOLLECTIONINFO:
+		if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo)))
+			return -EFAULT;
+
+		if (cinfo.index >= hid->maxcollection)
+			return -EINVAL;
+
+		cinfo.type = hid->collection[cinfo.index].type;
+		cinfo.usage = hid->collection[cinfo.index].usage;
+		cinfo.level = hid->collection[cinfo.index].level;
+
+		if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo)))
+			return -EFAULT;
+		return 0;
+
 	default:
 
 		if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
@@ -619,16 +677,18 @@
 	int retval;
 	char devfs_name[16];
 
-	for (i = 0; i < hid->maxapplication; i++)
-		if (!IS_INPUT_APPLICATION(hid->application[i]))
+	for (i = 0; i < hid->maxcollection; i++)
+		if (hid->collection[i].type == 
+		    HID_COLLECTION_APPLICATION &&
+		    !IS_INPUT_APPLICATION(hid->collection[i].usage))
 			break;
 
-	if (i == hid->maxapplication)
+	if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
 		return -1;
 
-	retval = usb_register_dev (&hiddev_fops, HIDDEV_MINOR_BASE, 1, &minor);
+	retval = usb_register_dev(&hiddev_fops, HIDDEV_MINOR_BASE, 1, &minor);
 	if (retval) {
-		err ("Not able to get a minor for this device.");
+		err("Not able to get a minor for this device.");
 		return -1;
 	}
 
@@ -648,10 +708,8 @@
 
 	sprintf(devfs_name, "hiddev%d", minor);
 	hiddev->devfs = devfs_register(hiddev_devfs_handle, devfs_name,
-				       DEVFS_FL_DEFAULT, USB_MAJOR,
-				       minor + HIDDEV_MINOR_BASE,
-				       S_IFCHR | S_IRUGO | S_IWUSR,
-				       &hiddev_fops, NULL);
+		DEVFS_FL_DEFAULT, USB_MAJOR, minor + HIDDEV_MINOR_BASE,
+		S_IFCHR | S_IRUGO | S_IWUSR, &hiddev_fops, NULL);
 	hid->minor = minor;
 	hid->hiddev = hiddev;
 
diff -Nru a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/input/pid.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,311 @@
+/*
+ *  PID Force feedback support for hid devices.
+ *
+ *  Copyright (c) 2002 Rodrigo Damazio.
+ *  Portions by Johann Deneux and Bjorn Augustson
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <rdamazio@lsi.usp.br>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include "hid.h"
+#include "pid.h"
+
+#define DEBUG
+
+#define CHECK_OWNERSHIP(i, hid_pid)	\
+	((i) < FF_EFFECTS_MAX && i >= 0 && \
+	test_bit(FF_PID_FLAGS_USED, &hid_pid->effects[(i)].flags) && \
+	(current->pid == 0 || \
+	(hid_pid)->effects[(i)].owner == current->pid))
+
+/* Called when a transfer is completed */
+static void hid_pid_ctrl_out(struct urb *u)
+{
+#ifdef DEBUG
+    printk("hid_pid_ctrl_out - Transfer Completed\n");
+#endif
+}
+
+static void hid_pid_exit(struct hid_device* hid)
+{
+    struct hid_ff_pid *private = hid->ff_private;
+    
+    if (private->urbffout) {
+	usb_unlink_urb(private->urbffout);
+	usb_free_urb(private->urbffout);
+    }
+}
+
+static int pid_upload_periodic(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) {
+    
+    printk("Requested periodic force upload\n");
+    return 0;
+}
+
+static int pid_upload_constant(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) {
+    printk("Requested constant force upload\n");
+    return 0;
+}
+
+static int pid_upload_condition(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) {
+    printk("Requested Condition force upload\n");
+    return 0;
+}
+
+static int pid_upload_ramp(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) {
+    printk("Request ramp force upload\n");
+    return 0;
+}
+
+static int hid_pid_event(struct hid_device *hid, struct input_dev *input,
+			  unsigned int type, unsigned int code, int value)
+{
+#ifdef DEBUG
+    printk ("PID event received: type=%d,code=%d,value=%d.\n",type,code,value);
+#endif
+
+    if (type != EV_FF)
+	return -1;
+
+    
+
+    return 0;
+}
+
+/* Lock must be held by caller */
+static void hid_pid_ctrl_playback(struct hid_device *hid,
+				   struct hid_pid_effect *effect, int play)
+{
+	if (play) {
+		set_bit(FF_PID_FLAGS_PLAYING, &effect->flags);
+
+	} else {
+		clear_bit(FF_PID_FLAGS_PLAYING, &effect->flags);
+	}
+}
+
+
+static int hid_pid_erase(struct input_dev *dev, int id)
+{
+	struct hid_device *hid = dev->private;
+	struct hid_field* field;
+	struct hid_report* report;
+	struct hid_ff_pid *pid = hid->ff_private;
+	unsigned long flags;
+	unsigned wanted_report = HID_UP_PID | FF_PID_USAGE_BLOCK_FREE;  /*  PID Block Free Report */
+	int ret;
+
+	if (!CHECK_OWNERSHIP(id, pid)) return -EACCES;
+
+	/* Find report */
+	ret =  hid_find_report_by_usage(hid, wanted_report, &report, HID_OUTPUT_REPORT);
+	if(!ret) {
+		printk("Couldn't find report\n");
+		return ret;
+	}
+
+	/* Find field */
+	field = (struct hid_field *) kmalloc(sizeof(struct hid_field), GFP_KERNEL);
+	ret = hid_set_field(field, ret, pid->effects[id].device_id);
+	if(!ret) {
+		printk("Couldn't set field\n");
+		return ret;
+	}
+
+	hid_submit_report(hid, report, USB_DIR_OUT);
+
+	spin_lock_irqsave(&pid->lock, flags);
+	hid_pid_ctrl_playback(hid, pid->effects + id, 0);
+	pid->effects[id].flags = 0;
+	spin_unlock_irqrestore(&pid->lock, flags);
+
+	return ret;
+}
+
+/* Erase all effects this process owns */
+static int hid_pid_flush(struct input_dev *dev, struct file *file)
+{
+	struct hid_device *hid = dev->private;
+	struct hid_ff_pid *pid = hid->ff_private;
+	int i;
+
+	/*NOTE: no need to lock here. The only times EFFECT_USED is
+	  modified is when effects are uploaded or when an effect is
+	  erased. But a process cannot close its dev/input/eventX fd
+	  and perform ioctls on the same fd all at the same time */
+	for (i=0; i<dev->ff_effects_max; ++i)
+		if ( current->pid == pid->effects[i].owner
+		     && test_bit(FF_PID_FLAGS_USED, &pid->effects[i].flags))
+			if (hid_pid_erase(dev, i))
+				warn("erase effect %d failed", i);
+
+	return 0;
+}
+
+
+static int hid_pid_upload_effect(struct input_dev *dev,
+				  struct ff_effect *effect)
+{
+	struct hid_ff_pid* pid_private  = (struct hid_ff_pid*)(dev->private);
+	int ret;
+	int is_update;
+	int flags=0;
+
+#ifdef DEBUG
+        printk("Upload effect called: effect_type=%x\n",effect->type);
+#endif
+	/* Check this effect type is supported by this device */
+	if (!test_bit(effect->type, dev->ffbit)) {
+#ifdef DEBUG
+		printk("Invalid kind of effect requested.\n");
+#endif
+		return -EINVAL;
+	}
+
+	/*
+	 * If we want to create a new effect, get a free id
+	 */
+	if (effect->id == -1) {
+		int id=0;
+
+		// Spinlock so we don`t get a race condition when choosing IDs
+		spin_lock_irqsave(&pid_private->lock,flags);
+
+		while(id < FF_EFFECTS_MAX)
+			if (!test_and_set_bit(FF_PID_FLAGS_USED, &pid_private->effects[id++].flags)) 
+			    break;
+
+		if ( id == FF_EFFECTS_MAX) {
+// TEMP - We need to get ff_effects_max correctly first:  || id >= dev->ff_effects_max) {
+#ifdef DEBUG
+			printk("Not enough device memory\n");
+#endif
+			return -ENOMEM;
+		}
+
+		effect->id = id;
+#ifdef DEBUG
+		printk("Effect ID is %d\n.",id);
+#endif
+		pid_private->effects[id].owner = current->pid;
+		pid_private->effects[id].flags = (1<<FF_PID_FLAGS_USED);
+		spin_unlock_irqrestore(&pid_private->lock,flags);
+
+		is_update = FF_PID_FALSE;
+	}
+	else {
+		/* We want to update an effect */
+		if (!CHECK_OWNERSHIP(effect->id, pid_private)) return -EACCES;
+
+		/* Parameter type cannot be updated */
+		if (effect->type != pid_private->effects[effect->id].effect.type)
+			return -EINVAL;
+
+		/* Check the effect is not already being updated */
+		if (test_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags)) {
+			return -EAGAIN;
+		}
+
+		is_update = FF_PID_TRUE;
+	}
+
+	/*
+	 * Upload the effect
+	 */
+	switch (effect->type) {
+		case FF_PERIODIC:
+			ret = pid_upload_periodic(pid_private, effect, is_update);
+			break;
+
+		case FF_CONSTANT:
+			ret = pid_upload_constant(pid_private, effect, is_update);
+			break;
+
+		case FF_SPRING:
+		case FF_FRICTION:
+		case FF_DAMPER:
+		case FF_INERTIA:
+			ret = pid_upload_condition(pid_private, effect, is_update);
+			break;
+
+		case FF_RAMP:
+			ret = pid_upload_ramp(pid_private, effect, is_update);
+			break;
+
+		default:
+#ifdef DEBUG
+			printk("Invalid type of effect requested - %x.\n", effect->type);
+#endif
+			return -EINVAL;
+	}
+	/* If a packet was sent, forbid new updates until we are notified
+	 * that the packet was updated
+	 */
+	if (ret == 0)
+		set_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags);
+	pid_private->effects[effect->id].effect = *effect;
+	return ret;
+}
+
+int hid_pid_init(struct hid_device *hid)
+{
+    struct hid_ff_pid *private;
+    
+    private = hid->ff_private = kmalloc(sizeof(struct hid_ff_pid), GFP_KERNEL);
+    if (!private) return -1;
+    
+    memset(private,0,sizeof(struct hid_ff_pid));
+
+    hid->ff_private = private; /* 'cause memset can move the block away */
+
+    private->hid = hid;
+    
+    hid->ff_exit = hid_pid_exit;
+    hid->ff_event = hid_pid_event;
+    
+    /* Open output URB */
+    if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) {
+	kfree(private);
+	return -1;
+    }
+
+    usb_fill_control_urb(private->urbffout, hid->dev,0,(void *) &private->ffcr,private->ctrl_buffer,8,hid_pid_ctrl_out,hid);
+    hid->input.upload_effect = hid_pid_upload_effect;
+    hid->input.flush = hid_pid_flush;
+    hid->input.ff_effects_max = 8;  // A random default
+    set_bit(EV_FF, hid->input.evbit);
+    set_bit(EV_FF_STATUS, hid->input.evbit);
+
+    spin_lock_init(&private->lock);
+
+    printk(KERN_INFO "Force feedback driver for PID devices by Rodrigo Damazio <rdamazio@lsi.usp.br>.\n");
+    
+    return 0;    
+}
diff -Nru a/drivers/usb/input/pid.h b/drivers/usb/input/pid.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/input/pid.h	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,62 @@
+/*
+ *  PID Force feedback support for hid devices.
+ *
+ *  Copyright (c) 2002 Rodrigo Damazio.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <rdamazio@lsi.usp.br>
+ */
+
+#define FF_EFFECTS_MAX 64
+
+#define FF_PID_FLAGS_USED	1  /* If the effect exists */
+#define FF_PID_FLAGS_UPDATING	2  /* If the effect is being updated */
+#define FF_PID_FLAGS_PLAYING	3  /* If the effect is currently being played */
+
+#define FF_PID_FALSE	0
+#define FF_PID_TRUE	1
+
+struct hid_pid_effect {
+    unsigned long flags;
+    pid_t owner;
+    unsigned int device_id;  // The device-assigned ID
+    struct ff_effect effect;
+};
+
+struct hid_ff_pid {
+    struct hid_device *hid;
+    unsigned long int gain;
+
+    struct urb *urbffout;
+    struct usb_ctrlrequest ffcr;
+    spinlock_t lock;
+
+    char ctrl_buffer[8];
+
+    struct hid_pid_effect effects[FF_EFFECTS_MAX];
+};
+
+/*
+ * Constants from the PID usage table (still far from complete)
+ */
+
+#define FF_PID_USAGE_BLOCK_LOAD 	0x89UL
+#define FF_PID_USAGE_BLOCK_FREE		0x90UL
+#define FF_PID_USAGE_NEW_EFFECT 	0xABUL
+#define FF_PID_USAGE_POOL_REPORT	0x7FUL
diff -Nru a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/input/powermate.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,360 @@
+/*
+ * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial.
+ *
+ * v1.0, (c)2002 William R Sowerbutts <will@sowerbutts.com>
+ *
+ * This device is a stainless steel knob which connects over USB. It can measure
+ * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with
+ * a spring for automatic release. The base contains a pair of LEDs which illuminate
+ * the translucent base. It rotates without limit and reports its relative rotation
+ * back to the host when polled by the USB controller.
+ *
+ * Testing with the knob I have has shown that it measures approximately 94 "clicks"
+ * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was 
+ * a variable speed cordless electric drill) has shown that the device can measure
+ * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
+ * the host. If it counts more than 7 clicks before it is polled, it will wrap back
+ * to zero and start counting again. This was at quite high speed, however, almost
+ * certainly faster than the human hand could turn it.
+ *
+ * The device's microcontroller can be programmed to set the LED to either a constant
+ * intensity, or to a rhythmic pulsing. Several patterns and speeds are available.
+ *
+ * Griffin were very happy to provide documentation and free hardware for development.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+#define POWERMATE_VENDOR	0x077d	/* Griffin Technology, Inc. */
+#define POWERMATE_PRODUCT_NEW	0x0410	/* Griffin PowerMate */
+#define POWERMATE_PRODUCT_OLD	0x04AA	/* Griffin soundKnob */
+
+#define CONTOUR_VENDOR		0x05f3	/* Contour Design, Inc. */
+#define CONTOUR_JOG		0x0240	/* Jog and Shuttle */
+
+/* these are the command codes we send to the device */
+#define SET_STATIC_BRIGHTNESS  0x01
+#define SET_PULSE_ASLEEP       0x02
+#define SET_PULSE_AWAKE        0x03
+#define SET_PULSE_MODE         0x04
+
+/* these refer to bits in the powermate_device's requires_update field. */
+#define UPDATE_STATIC_BRIGHTNESS (1<<0)
+#define UPDATE_PULSE_ASLEEP      (1<<1)
+#define UPDATE_PULSE_AWAKE       (1<<2)
+#define UPDATE_PULSE_MODE        (1<<3)
+
+#define POWERMATE_PAYLOAD_SIZE 3
+struct powermate_device {
+	signed char data[POWERMATE_PAYLOAD_SIZE];
+	struct urb irq, config;
+	struct usb_ctrlrequest configcr;
+	struct usb_device *udev;
+	struct input_dev input;
+	struct semaphore lock;
+	int static_brightness;
+	int pulse_speed;
+	int pulse_table;
+	int pulse_asleep;
+	int pulse_awake;
+	int requires_update; // physical settings which are out of sync
+	char phys[64];
+};
+
+static char pm_name_powermate[] = "Griffin PowerMate";
+static char pm_name_soundknob[] = "Griffin SoundKnob";
+
+static void powermate_config_complete(struct urb *urb); /* forward declararation of callback */
+
+/* Callback for data arriving from the PowerMate over the USB interrupt pipe */
+static void powermate_irq(struct urb *urb)
+{
+	struct powermate_device *pm = urb->context;
+
+	if(urb->status)
+		return;
+
+	/* handle updates to device state */
+	input_report_key(&pm->input, BTN_0, pm->data[0] & 0x01);
+	input_report_rel(&pm->input, REL_DIAL, pm->data[1]);
+}
+
+/* Decide if we need to issue a control message and do so. Must be called with pm->lock down */
+static void powermate_sync_state(struct powermate_device *pm)
+{
+	if(pm->requires_update == 0) 
+		return; /* no updates are required */
+	if(pm->config.status == -EINPROGRESS) 
+		return; /* an update is already in progress; it'll issue this update when it completes */
+
+	if(pm->requires_update & UPDATE_STATIC_BRIGHTNESS){
+		pm->configcr.wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS );
+		pm->configcr.wIndex = cpu_to_le16( pm->static_brightness );
+		pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS;
+	}else if(pm->requires_update & UPDATE_PULSE_ASLEEP){
+		pm->configcr.wValue = cpu_to_le16( SET_PULSE_ASLEEP );
+		pm->configcr.wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 );
+		pm->requires_update &= ~UPDATE_PULSE_ASLEEP;
+	}else if(pm->requires_update & UPDATE_PULSE_AWAKE){
+		pm->configcr.wValue = cpu_to_le16( SET_PULSE_AWAKE );
+		pm->configcr.wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 );
+		pm->requires_update &= ~UPDATE_PULSE_AWAKE;
+	}else if(pm->requires_update & UPDATE_PULSE_MODE){
+		int op, arg;
+		/* the powermate takes an operation and an argument for its pulse algorithm.
+		   the operation can be:
+		   0: divide the speed
+		   1: pulse at normal speed
+		   2: multiply the speed
+		   the argument only has an effect for operations 0 and 2, and ranges between
+		   1 (least effect) to 255 (maximum effect).
+       
+		   thus, several states are equivalent and are coalesced into one state.
+
+		   we map this onto a range from 0 to 510, with:
+		   0 -- 254    -- use divide (0 = slowest)
+		   255         -- use normal speed
+		   256 -- 510  -- use multiple (510 = fastest).
+
+		   Only values of 'arg' quite close to 255 are particularly useful/spectacular.
+		*/    
+		if(pm->pulse_speed < 255){
+			op = 0;                   // divide
+			arg = 255 - pm->pulse_speed;
+		}else if(pm->pulse_speed > 255){
+			op = 2;                   // multiply
+			arg = pm->pulse_speed - 255;
+		}else{
+			op = 1;                   // normal speed
+			arg = 0;                  // can be any value
+		}
+		pm->configcr.wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE );
+		pm->configcr.wIndex = cpu_to_le16( (arg << 8) | op );
+		pm->requires_update &= ~UPDATE_PULSE_MODE;
+	}else{
+		printk(KERN_ERR "powermate: unknown update required");
+		pm->requires_update = 0; /* fudge the bug */
+		return;
+	}
+
+/*	printk("powermate: %04x %04x\n", pm->configcr.wValue, pm->configcr.wIndex); */
+
+	pm->config.dev = pm->udev; /* is this necessary? */
+	pm->configcr.bRequestType = 0x41; /* vendor request */
+	pm->configcr.bRequest = 0x01;
+	pm->configcr.wLength = 0;
+
+        FILL_CONTROL_URB(&pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0), 
+			 (void*)&pm->configcr, 0, 0, powermate_config_complete, pm);	
+
+	if(usb_submit_urb(&pm->config, GFP_ATOMIC))
+		printk(KERN_ERR "powermate: usb_submit_urb(config) failed");
+}
+
+/* Called when our asynchronous control message completes. We may need to issue another immediately */
+static void powermate_config_complete(struct urb *urb)
+{
+	struct powermate_device *pm = urb->context;
+
+	if(urb->status)
+		printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
+	
+	down(&pm->lock);
+	powermate_sync_state(pm);
+	up(&pm->lock);
+}
+
+/* Set the LED up as described and begin the sync with the hardware if required */
+static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, 
+				int pulse_table, int pulse_asleep, int pulse_awake)
+{
+	if(pulse_speed < 0)
+		pulse_speed = 0;
+	if(pulse_table < 0)
+		pulse_table = 0;
+	if(pulse_speed > 510)
+		pulse_speed = 510;
+	if(pulse_table > 2)
+		pulse_table = 2;
+
+	pulse_asleep = !!pulse_asleep;
+	pulse_awake = !!pulse_awake;
+
+	down(&pm->lock);
+
+	/* mark state updates which are required */
+	if(static_brightness != pm->static_brightness){
+		pm->static_brightness = static_brightness;
+		pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;		
+	}
+	if(pulse_asleep != pm->pulse_asleep){
+		pm->pulse_asleep = pulse_asleep;
+		pm->requires_update |= UPDATE_PULSE_ASLEEP;
+	}
+	if(pulse_awake != pm->pulse_awake){
+		pm->pulse_awake = pulse_awake;
+		pm->requires_update |= UPDATE_PULSE_AWAKE;
+	}
+	if(pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table){
+		pm->pulse_speed = pulse_speed;
+		pm->pulse_table = pulse_table;
+		pm->requires_update |= UPDATE_PULSE_MODE;
+	}
+
+	powermate_sync_state(pm);
+   
+	up(&pm->lock);
+}
+
+/* Callback from the Input layer when an event arrives from userspace to configure the LED */
+static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value)
+{
+	unsigned int command = (unsigned int)_value;
+	struct powermate_device *pm = dev->private;
+
+	if(type == EV_MSC && code == MSC_PULSELED){
+		/*  
+		    bits  0- 7: 8 bits: LED brightness
+		    bits  8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
+		    bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
+		    bit     19: 1 bit : pulse whilst asleep?
+		    bit     20: 1 bit : pulse constantly?
+		*/  
+		int static_brightness = command & 0xFF;   // bits 0-7
+		int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
+		int pulse_table = (command >> 17) & 0x3;  // bits 17-18
+		int pulse_asleep = (command >> 19) & 0x1; // bit 19
+		int pulse_awake  = (command >> 20) & 0x1; // bit 20
+  
+		powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
+	}
+
+	return 0;
+}
+
+/* Called whenever a USB device matching one in our supported devices table is connected */
+static void *powermate_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct powermate_device *pm;
+	int pipe, maxp;
+	char path[64];
+
+	interface = udev->config[0].interface[ifnum].altsetting + 0;
+	endpoint = interface->endpoint + 0;
+	if (!(endpoint->bEndpointAddress & 0x80)) return NULL;
+	if ((endpoint->bmAttributes & 3) != 3) return NULL;
+
+	usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+		0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+		0, interface->bInterfaceNumber, NULL, 0,
+		HZ * USB_CTRL_SET_TIMEOUT);
+
+	if (!(pm = kmalloc(sizeof(struct powermate_device), GFP_KERNEL)))
+		return NULL;
+
+	memset(pm, 0, sizeof(struct powermate_device));
+	pm->udev = udev;
+
+	init_MUTEX(&pm->lock);
+
+	/* get a handle to the interrupt data pipe */
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+
+	if(maxp != POWERMATE_PAYLOAD_SIZE)
+		printk("powermate: Expected payload of %d bytes, found %d bytes!\n", POWERMATE_PAYLOAD_SIZE, maxp);
+
+	FILL_INT_URB(&pm->irq, udev, pipe, pm->data, POWERMATE_PAYLOAD_SIZE, powermate_irq, pm, endpoint->bInterval);
+
+	/* register our interrupt URB with the USB system */
+	if(usb_submit_urb(&pm->irq, GFP_KERNEL)) {
+		kfree(pm);
+		return NULL; /* failure */
+	}
+
+	switch (udev->descriptor.idProduct) {
+	case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break;
+	case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break;
+	default: 
+	  pm->input.name = pm_name_soundknob;
+	  printk(KERN_WARNING "powermate: unknown product id %04x\n", udev->descriptor.idProduct);
+	}
+
+	pm->input.private = pm;
+	pm->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC);
+	pm->input.keybit[LONG(BTN_0)] = BIT(BTN_0);
+	pm->input.relbit[LONG(REL_DIAL)] = BIT(REL_DIAL);
+	pm->input.mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED);
+	pm->input.idbus = BUS_USB;
+	pm->input.idvendor = udev->descriptor.idVendor;
+	pm->input.idproduct = udev->descriptor.idProduct;
+	pm->input.idversion = udev->descriptor.bcdDevice;
+	pm->input.event = powermate_input_event;
+
+	input_register_device(&pm->input);
+
+	usb_make_path(udev, path, 64);
+	snprintf(pm->phys, 64, "%s/input0", path);
+	printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.phys);
+	
+	/* force an update of everything */
+	pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
+	powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
+  
+	return pm;
+}
+
+/* Called when a USB device we've accepted ownership of is removed */
+static void powermate_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct powermate_device *pm = ptr;
+	down(&pm->lock);
+	pm->requires_update = 0;
+	usb_unlink_urb(&pm->irq);  
+	input_unregister_device(&pm->input);
+  
+	kfree(pm);
+}
+
+static struct usb_device_id powermate_devices [] = {
+	{ USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) },
+	{ USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) },
+	{ USB_DEVICE(CONTOUR_VENDOR, CONTOUR_JOG) },
+	{ } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, powermate_devices);
+
+static struct usb_driver powermate_driver = {
+        name:           "powermate",
+        probe:          powermate_probe,
+        disconnect:     powermate_disconnect,
+        id_table:       powermate_devices,
+};
+
+int powermate_init(void)
+{
+	if (usb_register(&powermate_driver) < 0)
+		return -1;
+	return 0;
+}
+
+void powermate_cleanup(void)
+{
+	usb_deregister(&powermate_driver);
+}
+
+module_init(powermate_init);
+module_exit(powermate_cleanup);
+
+MODULE_AUTHOR( "William R Sowerbutts" );
+MODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" );
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/input/xpad.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,330 @@
+/*
+ * USB XBOX HID Gamecontroller - v0.0.3
+ *
+ * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de>
+ *
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License as
+ *      published by the Free Software Foundation; either version 2 of
+ *      the License, or (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * This driver is based on:
+ *  - information from      http://euc.jp/periphs/xbox-controller.ja.html
+ *  - the iForce driver     drivers/char/joystick/iforce.c
+ *  - the skeleton-driver   drivers/usb/usb-skeleton.c
+ *
+ * Thanks to:
+ *  - ITO Takayuki for providing xpad information on his website
+ *  - Vojtech Pavlik      - iforce driver / input subsystem
+ *  - Greg Kroah-Hartman  - usb-skeleton driver
+ *
+ * TODO:
+ *	- get the black button to work
+ *      - fine tune axes
+ *      - fix "analog" buttons
+ *	- get rumble working
+ *
+ * History:
+ *
+ * 2002-06-27 - 0.0.1 - first version, just said "XBOX HID controller"
+ *
+ * 2002-07-02 - 0.0.2 - basic working version
+ *      all axes and 9 of the 10 buttons work (german InterAct device)
+ *      the black button does not work
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/usb.h>
+
+#define DRIVER_VERSION "v0.0.3"
+#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
+#define DRIVER_DESC "X-Box pad driver"
+
+#define XPAD_PKT_LEN 32
+
+static struct xpad_device {
+	u16 idVendor;
+	u16 idProduct;
+	char *name;
+} xpad_device[] = {
+	{ 0x045e, 0x0202, "Microsoft X-Box pad (US)" },
+	{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)" },
+	{ 0x05fd, 0x107a, "InterAct X-Box pad (Germany)" },
+	{ 0x0000, 0x0000, "X-Box pad" }
+};
+
+static signed short xpad_btn[] = {
+	BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,       /* 6 "analog" buttons */
+	BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR,    /* start/back + stick press */
+	-1                                              /* terminating entry */
+};
+
+static signed short xpad_abs[] = {
+	ABS_X, ABS_Y,		/* left stick */
+	ABS_RX, ABS_RY,		/* right stick */
+	ABS_Z, ABS_RZ,		/* triggers left/right */
+	ABS_HAT0X, ABS_HAT0Y,	/* dpad */
+	-1                          /* terminating entry */
+};
+
+static struct {
+	__s32 x;
+	__s32 y;
+} xpad_hat_to_axis[] = { {0, 0}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1} };
+
+static struct usb_device_id xpad_table [] = {
+	{ USB_INTERFACE_INFO('X', 'B', 0) },	/* X-Box USB-IF not approved class */
+	{ }
+};
+
+MODULE_DEVICE_TABLE (usb, xpad_table);
+
+struct usb_xpad {
+	struct input_dev dev;			/* input device interface */
+	struct usb_device *udev;		/* usb device */
+	
+	struct urb *irq_in;			/* urb for interrupt in report */
+	unsigned char idata[XPAD_PKT_LEN];	/* input data */
+	
+	char phys[65];				/* physical device path */
+	int open_count;				/* how many times has this been opened */
+};
+
+/*
+ *      xpad_process_packet
+ *
+ *      Completes a request by converting the data into events for the input subsystem.
+ *      
+ *      The used report descriptor given below was taken from ITO Takayukis website:
+ *          http://euc.jp/periphs/xbox-controller.ja.html
+ *
+ * ----------------------------------------------------------------------------------------------------------------
+ * |  padding | byte-cnt | dpad sb12 | reserved |   bt A   |   bt B   |   bt X   |   bt Y   | bt black | bt white |
+ * | 01234567 | 01234567 | 0123 4567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 |
+ * |    0     |    1     |     2     |    3     |    4     |    5     |    6     |    7     |    8     |    9     |
+ * ----------------------------------------------------------------------------------------------------------------
+ *
+ * ---------------------------------------------------------------------------------------------------------------
+ * |  trig L  |  trig R  |     left stick X    |     left stick Y    |     right stick X   |     right stick Y   |
+ * | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 | 01234567 |
+ * |    10    |    11    |    12    |    13    |    14    |    15    |    16    |    17    |    18    |    19    |
+ * ---------------------------------------------------------------------------------------------------------------
+ */
+
+static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
+{
+	struct input_dev *dev = &xpad->dev;
+	
+	/* left stick */
+	input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
+	input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
+	
+	/* right stick */
+	input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16]));
+	input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18]));
+	
+	/* triggers left/right */
+	input_report_abs(dev, ABS_Z, data[10]);
+	input_report_abs(dev, ABS_RZ, data[11]);
+	
+	/* digital pad */
+	input_report_abs(dev, ABS_HAT0X, xpad_hat_to_axis[data[2] & 0x0f].x);
+	input_report_abs(dev, ABS_HAT0Y, xpad_hat_to_axis[data[2] & 0x0f].y);
+	
+	/* start/back buttons and stick press left/right */
+	input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4);
+	input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5);
+	input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6);
+	input_report_key(dev, BTN_THUMBR, data[2] >> 7);
+	
+	/* "analog" buttons A, B, X, Y */
+	input_report_key(dev, BTN_A, data[4]);
+	input_report_key(dev, BTN_B, data[5]);
+	input_report_key(dev, BTN_X, data[6]);
+	input_report_key(dev, BTN_Y, data[7]);
+	
+	/* "analog" buttons black, white */
+	input_report_key(dev, BTN_C, data[8]);
+	input_report_key(dev, BTN_Z, data[9]);
+}
+
+static void xpad_irq_in(struct urb *urb)
+{
+	struct usb_xpad *xpad = urb->context;
+	
+	if (urb->status)
+		return;
+	
+	xpad_process_packet(xpad, 0, xpad->idata);
+}
+
+static int xpad_open (struct input_dev *dev)
+{
+	struct usb_xpad *xpad = dev->private;
+	
+	if (xpad->open_count++)
+		return 0;
+	
+	xpad->irq_in->dev = xpad->udev;
+	if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
+		return -EIO;
+	
+	return 0;
+}
+
+static void xpad_close (struct input_dev *dev)
+{
+	struct usb_xpad *xpad = dev->private;
+	
+	if (!--xpad->open_count)
+		usb_unlink_urb(xpad->irq_in);
+}
+
+static void * xpad_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
+{
+	struct usb_xpad *xpad = NULL;
+	struct usb_endpoint_descriptor *ep_irq_in;
+	char path[64];
+	int i;
+	
+	for (i = 0; xpad_device[i].idVendor; i++) {
+		if ((udev->descriptor.idVendor == xpad_device[i].idVendor) &&
+		    (udev->descriptor.idProduct == xpad_device[i].idProduct))
+			break;
+	}
+	
+	if ((xpad = kmalloc (sizeof(struct usb_xpad), GFP_KERNEL)) == NULL) {
+		err("cannot allocate memory for new pad");
+		return NULL;
+	}
+	memset(xpad, 0, sizeof(struct usb_xpad));
+
+	xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
+        if (!xpad->irq_in) {
+		err("cannot allocate memory for new pad irq urb");
+                kfree(xpad);
+                return NULL;
+        }
+	
+	ep_irq_in = udev->actconfig->interface[ifnum].altsetting[0].endpoint + 0;
+	
+	FILL_INT_URB(xpad->irq_in, udev, usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
+	xpad->idata, XPAD_PKT_LEN, xpad_irq_in, xpad, ep_irq_in->bInterval);
+	
+	xpad->udev = udev;
+
+	xpad->dev.idbus = BUS_USB;
+	xpad->dev.idvendor = udev->descriptor.idVendor;
+	xpad->dev.idproduct = udev->descriptor.idProduct;
+	xpad->dev.idversion = udev->descriptor.bcdDevice;
+	xpad->dev.private = xpad;
+	xpad->dev.name = xpad_device[i].name;
+	xpad->dev.phys = xpad->phys;
+	xpad->dev.open = xpad_open;
+	xpad->dev.close = xpad_close;
+
+	usb_make_path(udev, path, 64);
+	snprintf(xpad->phys, 64,  "%s/input0", path);
+	
+	xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+	for (i = 0; xpad_btn[i] >= 0; i++)
+	set_bit(xpad_btn[i], xpad->dev.keybit);
+	
+	for (i = 0; xpad_abs[i] >= 0; i++) {
+
+		signed short t = xpad_abs[i];
+
+		set_bit(t, xpad->dev.absbit);
+		
+		switch (t) {
+			case ABS_X:
+			case ABS_Y:
+			case ABS_RX:
+			case ABS_RY:
+				xpad->dev.absmax[t] =  32767;
+				xpad->dev.absmin[t] = -32768;
+				xpad->dev.absflat[t] = 128;
+				xpad->dev.absfuzz[t] = 16;
+				break;
+			case ABS_Z:
+			case ABS_RZ:
+				xpad->dev.absmax[t] = 255;
+				xpad->dev.absmin[t] = 0;
+				break;
+			case ABS_HAT0X:
+			case ABS_HAT0Y:
+				xpad->dev.absmax[t] =  1;
+				xpad->dev.absmin[t] = -1;
+				break;
+		}
+	}
+	
+	input_register_device(&xpad->dev);
+	
+	printk(KERN_INFO "input: %s on %s", xpad->dev.name, path);
+	
+	return xpad;
+}
+
+static void xpad_disconnect(struct usb_device *udev, void *ptr)
+{
+	struct usb_xpad *xpad = ptr;
+	
+	usb_unlink_urb(xpad->irq_in);
+	input_unregister_device(&xpad->dev);
+	usb_free_urb(xpad->irq_in);
+	kfree(xpad);
+}
+
+static struct usb_driver xpad_driver = {
+	name:       "xpad",
+	probe:      xpad_probe,
+	disconnect: xpad_disconnect,
+	id_table:   xpad_table,
+};
+
+static int __init usb_xpad_init(void)
+{
+	usb_register(&xpad_driver);
+	info(DRIVER_DESC ":" DRIVER_VERSION);
+	return 0;
+}
+
+static void __exit usb_xpad_exit(void)
+{
+	usb_deregister(&xpad_driver);
+}
+
+module_init(usb_xpad_init);
+module_exit(usb_xpad_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
--- a/drivers/usb/media/se401.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/media/se401.c	Tue Jul 16 16:49:42 2002
@@ -593,7 +593,6 @@
 			se401->sbuf[i].data, SE401_PACKETSIZE,
 			se401_video_irq,
 			se401);
-		urb->transfer_flags |= USB_QUEUE_BULK;
 
 		se401->urb[i]=urb;
 
diff -Nru a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c
--- a/drivers/usb/media/stv680.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/usb/media/stv680.c	Tue Jul 16 16:49:41 2002
@@ -776,7 +776,6 @@
 				   stv680->sbuf[i].data, stv680->rawbufsize,
 				   stv680_video_irq, stv680);
 		urb->timeout = PENCAM_TIMEOUT * 2;
-		urb->transfer_flags |= USB_QUEUE_BULK;
 		stv680->urb[i] = urb;
 		err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
 		if (err)
diff -Nru a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c
--- a/drivers/usb/misc/emi26.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/misc/emi26.c	Tue Jul 16 16:49:42 2002
@@ -54,7 +54,7 @@
 	unsigned char *buffer =  kmalloc (length, GFP_KERNEL);
 
 	if (!buffer) {
-		printk(KERN_ERR "emi26: kmalloc(%d) failed.", length);
+		err("emi26: kmalloc(%d) failed.", length);
 		return -ENOMEM;
 	}
 	memcpy (buffer, data, length);
@@ -69,11 +69,11 @@
 static int emi26_set_reset (struct usb_device *dev, unsigned char reset_bit)
 {
 	int response;
-	printk(KERN_INFO "%s - %d", __FUNCTION__, reset_bit);
+	info("%s - %d", __FUNCTION__, reset_bit);
 	/* printk(KERN_DEBUG "%s - %d", __FUNCTION__, reset_bit); */
 	response = emi26_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0);
 	if (response < 0) {
-		printk(KERN_ERR "emi26: set_reset (%d) failed", reset_bit);
+		err("emi26: set_reset (%d) failed", reset_bit);
 	}
 	return response;
 }
@@ -89,7 +89,7 @@
 	/* Assert reset (stop the CPU in the EMI) */
 	err = emi26_set_reset(dev,1);
 	if (err < 0) {
-		printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err);
+		err( "%s - error loading firmware: error = %d", __FUNCTION__, err);
 		return err;
 	}
 
@@ -97,7 +97,7 @@
 	for (i=0; g_Loader[i].type == 0; i++) {
 		err = emi26_writememory(dev, g_Loader[i].address, g_Loader[i].data, g_Loader[i].length, ANCHOR_LOAD_INTERNAL);
 		if (err < 0) {
-			printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err);
+			err("%s - error loading firmware: error = %d", __FUNCTION__, err);
 			return err;
 		}
 	}
@@ -120,7 +120,7 @@
 		}
 		err = emi26_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
 		if (err < 0) {
-			printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err);
+			err("%s - error loading firmware: error = %d", __FUNCTION__, err);
 			return err;
 		}
 	} while (i > 0);
@@ -128,7 +128,7 @@
 	/* Assert reset (stop the CPU in the EMI) */
 	err = emi26_set_reset(dev,1);
 	if (err < 0) {
-		printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err);
+		err("%s - error loading firmware: error = %d", __FUNCTION__, err);
 		return err;
 	}
 
@@ -136,7 +136,7 @@
 	for (i=0; g_Loader[i].type == 0; i++) {
 		err = emi26_writememory(dev, g_Loader[i].address, g_Loader[i].data, g_Loader[i].length, ANCHOR_LOAD_INTERNAL);
 		if (err < 0) {
-			printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err);
+			err("%s - error loading firmware: error = %d", __FUNCTION__, err);
 			return err;
 		}
 	}
@@ -144,7 +144,7 @@
 	/* De-assert reset (let the CPU run) */
 	err = emi26_set_reset(dev,0);
 	if (err < 0) {
-		printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err);
+		err("%s - error loading firmware: error = %d", __FUNCTION__, err);
 		return err;
 	}
 
@@ -153,7 +153,7 @@
 		if (!INTERNAL_RAM(g_Firmware[i].address)) {
 			err = emi26_writememory(dev, g_Firmware[i].address, g_Firmware[i].data, g_Firmware[i].length, ANCHOR_LOAD_EXTERNAL);
 			if (err < 0) {
-				printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err);
+				err("%s - error loading firmware: error = %d", __FUNCTION__, err);
 				return err;
 			}
 		}
@@ -162,7 +162,7 @@
 	/* Assert reset (stop the CPU in the EMI) */
 	err = emi26_set_reset(dev,1);
 	if (err < 0) {
-		printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err);
+		err("%s - error loading firmware: error = %d", __FUNCTION__, err);
 		return err;
 	}
 
@@ -170,7 +170,7 @@
 		if (INTERNAL_RAM(g_Firmware[i].address)) {
 			err = emi26_writememory(dev, g_Firmware[i].address, g_Firmware[i].data, g_Firmware[i].length, ANCHOR_LOAD_INTERNAL);
 			if (err < 0) {
-				printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err);
+				err("%s - error loading firmware: error = %d", __FUNCTION__, err);
 				return err;
 			}
 		}
@@ -179,7 +179,7 @@
 	/* De-assert reset (let the CPU run) */
 	err = emi26_set_reset(dev,0);
 	if (err < 0) {
-		printk(KERN_ERR "%s - error loading firmware: error = %d", __FUNCTION__, err);
+		err("%s - error loading firmware: error = %d", __FUNCTION__, err);
 		return err;
 	}
 
@@ -197,7 +197,7 @@
 
 static void * emi26_probe(struct usb_device *dev, unsigned int if_num, const struct usb_device_id *id)
 {
-	printk(KERN_INFO "%s start", __FUNCTION__); 
+	info("%s start", __FUNCTION__); 
 	
 	if((dev->descriptor.idVendor == EMI26_VENDOR_ID) && (dev->descriptor.idProduct == EMI26_PRODUCT_ID)) {
 		emi26_load_firmware(dev);
diff -Nru a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c
--- a/drivers/usb/misc/tiglusb.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/usb/misc/tiglusb.c	Tue Jul 16 16:49:41 2002
@@ -60,7 +60,7 @@
 static int clear_device (struct usb_device *dev)
 {
 	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
-		printk ("tiglusb: clear_device failed\n");
+		err ("tiglusb: clear_device failed");
 		return -1;
 	}
 
@@ -74,13 +74,13 @@
 
 	pipe = usb_sndbulkpipe (dev, 1);
 	if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
-		printk ("tiglusb: clear_pipe (r), request failed\n");
+		err("tiglusb: clear_pipe (r), request failed");
 		return -1;
 	}
 
 	pipe = usb_sndbulkpipe (dev, 2);
 	if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
-		printk ("tiglusb: clear_pipe (w), request failed\n");
+		err ("tiglusb: clear_pipe (w), request failed");
 		return -1;
 	}
 
@@ -171,7 +171,7 @@
 	if (result == -ETIMEDOUT) {	/* NAK */
 		ret = result;
 		if (!bytes_read) {
-			printk ("quirk !\n");
+			warn ("quirk !");
 		}
 		warn ("tiglusb_read, NAK received.");
 		goto out;
@@ -233,7 +233,7 @@
 	} else if (result == -EPIPE) {	/* STALL -- shouldn't happen */
 		warn ("CLEAR_FEATURE request to remove STALL condition.");
 		if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
-			warn ("send_packet, request failed\n");
+			warn ("send_packet, request failed");
 		//clear_device(s->dev);
 		ret = result;
 		goto out;
@@ -273,12 +273,12 @@
 		timeout = arg;	// timeout value in tenth of seconds
 		break;
 	case IOCTL_TIUSB_RESET_DEVICE:
-		printk (KERN_DEBUG "IOCTL_TIGLUSB_RESET_DEVICE\n");
+		dbg ("IOCTL_TIGLUSB_RESET_DEVICE");
 		if (clear_device (s->dev))
 			ret = -EIO;
 		break;
 	case IOCTL_TIUSB_RESET_PIPES:
-		printk (KERN_DEBUG "IOCTL_TIGLUSB_RESET_PIPES\n");
+		dbg ("IOCTL_TIGLUSB_RESET_PIPES");
 		if (clear_pipes (s->dev))
 			ret = -EIO;
 		break;
@@ -326,8 +326,8 @@
 	ptiglusb_t s;
 	char name[8];
 
-	printk ("tiglusb: probing vendor id 0x%x, device id 0x%x ifnum:%d\n",
-		dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+	dbg ("tiglusb: probing vendor id 0x%x, device id 0x%x ifnum:%d",
+	     dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
 
 	/* 
 	 * We don't handle multiple configurations. As of version 0x0103 of 
@@ -341,7 +341,7 @@
 		return NULL;
 
 	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
-		printk ("tiglusb_probe: set_configuration failed\n");
+		err ("tiglusb_probe: set_configuration failed");
 		return NULL;
 	}
 
@@ -358,7 +358,7 @@
 	dbg ("bound to interface: %d", ifnum);
 
 	sprintf (name, "%d", s->minor);
-	printk ("tiglusb: registering to devfs : major = %d, minor = %d, node = %s\n", TIUSB_MAJOR,
+	info ("tiglusb: registering to devfs : major = %d, minor = %d, node = %s", TIUSB_MAJOR,
 		(TIUSB_MINOR + s->minor), name);
 	s->devfs =
 	    devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, TIUSB_MAJOR,
@@ -366,7 +366,7 @@
 			    NULL);
 
 	/* Display firmware version */
-	printk ("tiglusb: link cable version %i.%02x\n",
+	info ("tiglusb: link cable version %i.%02x",
 		dev->descriptor.bcdDevice >> 8, dev->descriptor.bcdDevice & 0xff);
 
 	return s;
@@ -377,7 +377,7 @@
 	ptiglusb_t s = (ptiglusb_t) drv_context;
 
 	if (!s || !s->dev)
-		printk ("bogus disconnect");
+		warn ("bogus disconnect");
 
 	s->remove_pending = 1;
 	wake_up (&s->wait);
@@ -396,7 +396,7 @@
 	/* unregister device */
 	devfs_unregister (s->devfs);
 	s->devfs = NULL;
-	printk ("tiglusb: device disconnected\n");
+	info ("tiglusb: device disconnected");
 }
 
 static struct usb_device_id tiglusb_ids[] = {
@@ -452,7 +452,7 @@
 
 	/* register device */
 	if (devfs_register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
-		printk ("tiglusb: unable to get major %d\n", TIUSB_MAJOR);
+		err ("tiglusb: unable to get major %d", TIUSB_MAJOR);
 		return -EIO;
 	}
 
diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
--- a/drivers/usb/net/usbnet.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/usb/net/usbnet.c	Tue Jul 16 16:49:41 2002
@@ -1317,9 +1317,6 @@
 		usb_rcvbulkpipe (dev->udev, dev->driver_info->in),
 		skb->data, size, rx_complete, skb);
 	urb->transfer_flags |= USB_ASYNC_UNLINK;
-#ifdef	REALLY_QUEUE
-	urb->transfer_flags |= USB_QUEUE_BULK;
-#endif
 #if 0
 	// Idle-but-posted reads with UHCI really chew up
 	// PCI bandwidth unless FSBR is disabled
@@ -1802,9 +1799,6 @@
 			usb_sndbulkpipe (dev->udev, info->out),
 			skb->data, skb->len, tx_complete, skb);
 	urb->transfer_flags |= USB_ASYNC_UNLINK;
-#ifdef	REALLY_QUEUE
-	urb->transfer_flags |= USB_QUEUE_BULK;
-#endif
 	// FIXME urb->timeout = ... jiffies ... ;
 
 	spin_lock_irqsave (&dev->txq.lock, flags);
diff -Nru a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
--- a/drivers/usb/serial/empeg.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/serial/empeg.c	Tue Jul 16 16:49:42 2002
@@ -171,8 +171,6 @@
 		empeg_read_bulk_callback,
 		port);
 
-	port->read_urb->transfer_flags |= USB_QUEUE_BULK;
-
 	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 
 	if (result)
@@ -270,8 +268,6 @@
 			empeg_write_bulk_callback,
 			port);
 
-		urb->transfer_flags |= USB_QUEUE_BULK;
-
 		/* send it down the pipe */
 		status = usb_submit_urb(urb, GFP_ATOMIC);
 		if (status) {
@@ -423,8 +419,6 @@
 		port->read_urb->transfer_buffer_length,
 		empeg_read_bulk_callback,
 		port);
-
-	port->read_urb->transfer_flags |= USB_QUEUE_BULK;
 
 	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 
diff -Nru a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
--- a/drivers/usb/serial/io_edgeport.c	Tue Jul 16 16:49:41 2002
+++ b/drivers/usb/serial/io_edgeport.c	Tue Jul 16 16:49:41 2002
@@ -1460,9 +1460,6 @@
 		       usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint),
 		       buffer, count+2, edge_bulk_out_data_callback, edge_port);
 
-	/* set the USB_BULK_QUEUE flag so that we can shove a bunch of urbs at once down the pipe */
-	urb->transfer_flags |= USB_QUEUE_BULK;
-
 	urb->dev = edge_serial->serial->dev;
 	status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (status) {
@@ -2487,9 +2484,6 @@
 	FILL_BULK_URB (urb, edge_serial->serial->dev, 
 		       usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint),
 		       buffer, length, edge_bulk_out_cmd_callback, edge_port);
-
-	/* set the USB_BULK_QUEUE flag so that we can shove a bunch of urbs at once down the pipe */
-	urb->transfer_flags |= USB_QUEUE_BULK;
 
 	edge_port->commandPending = TRUE;
 	status = usb_submit_urb(urb, GFP_ATOMIC);
diff -Nru a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
--- a/drivers/usb/serial/ir-usb.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/serial/ir-usb.c	Tue Jul 16 16:49:42 2002
@@ -311,7 +311,6 @@
 		port->read_urb->transfer_buffer_length,
 		ir_read_bulk_callback,
 		port);
-	port->read_urb->transfer_flags = USB_QUEUE_BULK;
 	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (result)
 		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
@@ -389,9 +388,7 @@
 		ir_write_bulk_callback,
 		port);
 
-	port->write_urb->transfer_flags
-		= USB_QUEUE_BULK
-		| USB_ZERO_PACKET;
+	port->write_urb->transfer_flags = USB_ZERO_PACKET;
 
 	result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
 	if (result)
@@ -501,8 +498,6 @@
 				ir_read_bulk_callback,
 				port);
 
-			port->read_urb->transfer_flags = USB_QUEUE_BULK;
-
 			result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 
 			if (result)
@@ -598,9 +593,7 @@
 			ir_write_bulk_callback,
 			port);
 
-		port->write_urb->transfer_flags
-			= USB_QUEUE_BULK
-			| USB_ZERO_PACKET;
+		port->write_urb->transfer_flags = USB_ZERO_PACKET;
 
 		result = usb_submit_urb (port->write_urb, GFP_KERNEL);
 		if (result)
diff -Nru a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
--- a/drivers/usb/serial/kl5kusb105.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/serial/kl5kusb105.c	Tue Jul 16 16:49:42 2002
@@ -391,7 +391,6 @@
 		      port->read_urb->transfer_buffer_length,
 		      klsi_105_read_bulk_callback,
 		      port);
-	port->read_urb->transfer_flags |= USB_QUEUE_BULK;
 
 	rc = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (rc) {
@@ -537,8 +536,6 @@
 			      URB_TRANSFER_BUFFER_SIZE,
 			      klsi_105_write_bulk_callback,
 			      port);
-		urb->transfer_flags |= USB_QUEUE_BULK;
-
 
 		/* send the data out the bulk port */
 		result = usb_submit_urb(urb, GFP_ATOMIC);
diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/serial/visor.c	Tue Jul 16 16:49:42 2002
@@ -390,7 +390,6 @@
 					    port->bulk_out_endpointAddress),
 			   buffer, count, 
 			   visor_write_bulk_callback, port);
-	urb->transfer_flags |= USB_QUEUE_BULK;
 
 	/* send it down the pipe */
 	status = usb_submit_urb(urb, GFP_ATOMIC);
diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
--- a/drivers/usb/storage/scsiglue.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/storage/scsiglue.c	Tue Jul 16 16:49:42 2002
@@ -114,11 +114,11 @@
 	/* Kill the control threads
 	 *
 	 * Enqueue the command, wake up the thread, and wait for 
-	 * notification that it's exited.
+	 * notification that it has exited.
 	 */
-	US_DEBUGP("-- sending US_ACT_EXIT command to thread\n");
-	us->action = US_ACT_EXIT;
-	
+	US_DEBUGP("-- sending exit command to thread\n");
+	BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE);
+	us->srb = NULL;
 	up(&(us->sema));
 	wait_for_completion(&(us->notify));
 
@@ -137,25 +137,19 @@
 	return DID_BAD_TARGET << 16;
 }
 
-/* run command */
+/* queue a command */
+/* This is always called with scsi_lock(srb->host) held */
 static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
 {
 	struct us_data *us = (struct us_data *)srb->host->hostdata[0];
-	unsigned long flags;
 
 	US_DEBUGP("queuecommand() called\n");
 	srb->host_scribble = (unsigned char *)us;
 
-	/* get exclusive access to the structures we want */
-	spin_lock_irqsave(&us->queue_exclusion, flags);
-
 	/* enqueue the command */
-	us->queue_srb = srb;
+	BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE || us->srb != NULL);
 	srb->scsi_done = done;
-	us->action = US_ACT_COMMAND;
-
-	/* release the lock on the structure */
-	spin_unlock_irqrestore(&us->queue_exclusion, flags);
+	us->srb = srb;
 
 	/* wake up the process task */
 	up(&(us->sema));
@@ -168,74 +162,82 @@
  ***********************************************************************/
 
 /* Command abort */
+/* This is always called with scsi_lock(srb->host) held */
 static int command_abort( Scsi_Cmnd *srb )
 {
 	struct us_data *us = (struct us_data *)srb->host->hostdata[0];
 
 	US_DEBUGP("command_abort() called\n");
 
-	if (atomic_read(&us->sm_state) == US_STATE_RUNNING) {
- 		scsi_unlock(srb->host);
-		usb_stor_abort_transport(us);
-
-		/* wait for us to be done */
-		wait_for_completion(&(us->notify));
- 		scsi_lock(srb->host);
-		return SUCCESS;
+	/* Is this command still active? */
+	if (us->srb != srb) {
+		US_DEBUGP ("-- nothing to abort\n");
+		return FAILED;
 	}
 
-	US_DEBUGP ("-- nothing to abort\n");
-	return FAILED;
+	usb_stor_abort_transport(us);
+	return SUCCESS;
 }
 
 /* This invokes the transport reset mechanism to reset the state of the
  * device */
+/* This is always called with scsi_lock(srb->host) held */
 static int device_reset( Scsi_Cmnd *srb )
 {
 	struct us_data *us = (struct us_data *)srb->host->hostdata[0];
 	int result;
 
 	US_DEBUGP("device_reset() called\n" );
+	BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE);
 
-	/* if the device was removed, then we're already reset */
-	if (!test_bit(DEV_ATTACHED, &us->bitflags))
-		return SUCCESS;
-
+	/* set the state and release the lock */
+	atomic_set(&us->sm_state, US_STATE_RESETTING);
 	scsi_unlock(srb->host);
+
 	/* lock the device pointers */
 	down(&(us->dev_semaphore));
-	us->srb = srb;
-	atomic_set(&us->sm_state, US_STATE_RESETTING);
-	result = us->transport_reset(us);
-	atomic_set(&us->sm_state, US_STATE_IDLE);
 
-	/* unlock the device pointers */
+	/* if the device was removed, then we're already reset */
+	if (!(us->flags & US_FL_DEV_ATTACHED))
+		result = SUCCESS;
+	else
+		result = us->transport_reset(us);
 	up(&(us->dev_semaphore));
+
+	/* lock access to the state and clear it */
 	scsi_lock(srb->host);
+	atomic_set(&us->sm_state, US_STATE_IDLE);
 	return result;
 }
 
 /* This resets the device port, and simulates the device
  * disconnect/reconnect for all drivers which have claimed
  * interfaces, including ourself. */
+/* This is always called with scsi_lock(srb->host) held */
 static int bus_reset( Scsi_Cmnd *srb )
 {
 	struct us_data *us = (struct us_data *)srb->host->hostdata[0];
 	int i;
 	int result;
-	struct usb_device *pusb_dev_save = us->pusb_dev;
+	struct usb_device *pusb_dev_save;
 
 	/* we use the usb_reset_device() function to handle this for us */
 	US_DEBUGP("bus_reset() called\n");
 
+	scsi_unlock(srb->host);
+
 	/* if the device has been removed, this worked */
-	if (!test_bit(DEV_ATTACHED, &us->bitflags)) {
+	down(&us->dev_semaphore);
+	if (!(us->flags & US_FL_DEV_ATTACHED)) {
 		US_DEBUGP("-- device removed already\n");
+		up(&us->dev_semaphore);
+		scsi_lock(srb->host);
 		return SUCCESS;
 	}
+	pusb_dev_save = us->pusb_dev;
+	up(&us->dev_semaphore);
 
 	/* attempt to reset the port */
-	scsi_unlock(srb->host);
 	result = usb_reset_device(pusb_dev_save);
 	US_DEBUGP("usb_reset_device returns %d\n", result);
 	if (result < 0) {
@@ -245,7 +247,7 @@
 
 	/* FIXME: This needs to lock out driver probing while it's working
 	 * or we can have race conditions */
-	/* Is that still true?  I don't see how...  AS */
+	/* This functionality really should be provided by the khubd thread */
 	for (i = 0; i < pusb_dev_save->actconfig->bNumInterfaces; i++) {
  		struct usb_interface *intf =
 			&pusb_dev_save->actconfig->interface[i];
@@ -331,8 +333,8 @@
 
 	/* show the GUID of the device */
 	SPRINTF("         GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
-	SPRINTF("     Attached: %s\n", (test_bit(DEV_ATTACHED, &us->bitflags)
-			? "Yes" : "No"));
+	SPRINTF("     Attached: %s\n", (us->flags & US_FL_DEV_ATTACHED ?
+			"Yes" : "No"));
 
 	/*
 	 * Calculate start of next buffer, and return value.
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/storage/transport.c	Tue Jul 16 16:49:42 2002
@@ -344,6 +344,12 @@
 			   len = srb->request_bufflen;
 	   }
 
+	/* According to the linux-scsi people, any command sent which
+	 * violates this invariant is a bug.  In the hopes of removing
+	 * all the complex logic above, let's find them and eliminate them.
+	 */
+	BUG_ON(len != srb->request_bufflen);
+
 	return len;
 }
 
@@ -354,24 +360,35 @@
 /*
  * This is subtle, so pay attention:
  * ---------------------------------
- * We're very concered about races with a command abort.  Hanging this code is
- * a sure fire way to hang the kernel.
+ * We're very concerned about races with a command abort.  Hanging this code
+ * is a sure fire way to hang the kernel.  (Note that this discussion applies
+ * only to transactions resulting from a scsi queued-command, since only
+ * these transactions are subject to a scsi abort.  Other transactions, such
+ * as those occurring during device-specific initialization, must be handled
+ * by a separate code path.)
  *
- * The abort function first sets the machine state, then tries to acquire the
- * lock on the current_urb to abort it.
+ * The abort function first sets the machine state, then acquires the lock
+ * on the current_urb before checking if it needs to be aborted.
  *
- * Once a function grabs the current_urb_sem, then it -MUST- test the state to
- * see if we just got aborted before the lock was grabbed.  If so, it's
- * essential to release the lock and return.
+ * When a function submits the current_urb, it must first grab the
+ * current_urb_sem to prevent the abort function from trying to cancel the
+ * URB while the submit call is underway.  After a function submits the
+ * current_urb, it -MUST- test the state to see if we got aborted just before
+ * the submission.  If so, it's essential to abort the URB if it's still in
+ * progress.  Either way, the function must then release the lock and wait
+ * for the URB to finish.
  *
- * The idea is that, once the current_urb_sem is held, the state can't really
- * change anymore without also engaging the usb_unlink_urb() call _after_ the
- * URB is actually submitted.
+ * (It's also permissible, but not necessary, to test the state -before-
+ * submitting the URB.  Doing so would prevent an unnecessary submission if
+ * the transaction had already been aborted, but this is very unlikely to
+ * happen, because the abort would have to have been requested during actual
+ * kernel processing rather than during an I/O delay.)
  *
- * So, we've guaranteed that (after the sm_state test), if we do submit the
- * URB it will get aborted when we release the current_urb_sem.  And we've
- * also guaranteed that if the abort code was called before we held the
- * current_urb_sem, we can safely get out before the URB is submitted.
+ * The idea is that (1) once the state is changed to ABORTING, either the
+ * aborting function or the submitting function is guaranteed to call
+ * usb_unlink_urb() for an active URB, and (2) current_urb_sem prevents
+ * usb_unlink_urb() from being called more than once or from being called
+ * during usb_submit_urb().
  */
 
 /* This is the completion handler which will wake us up when an URB
@@ -385,10 +402,10 @@
 }
 
 /* This is the common part of the URB message submission code
- * This function expects the current_urb_sem to be held upon entry.
  *
- * All URBs from the usb-storage driver _must_ pass through this function
- * (or something like it) for the abort mechanisms to work properly.
+ * All URBs from the usb-storage driver involved in handling a queued scsi
+ * command _must_ pass through this function (or something like it) for the
+ * abort mechanisms to work properly.
  */
 static int usb_stor_msg_common(struct us_data *us)
 {
@@ -404,17 +421,28 @@
 	us->current_urb->error_count = 0;
 	us->current_urb->transfer_flags = USB_ASYNC_UNLINK;
 
-	/* submit the URB */
+	/* lock and submit the URB */
+	down(&(us->current_urb_sem));
 	status = usb_submit_urb(us->current_urb, GFP_NOIO);
 	if (status) {
 		/* something went wrong */
+		up(&(us->current_urb_sem));
 		return status;
 	}
 
-	/* wait for the completion of the URB */
+	/* has the current command been aborted? */
+	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+
+		/* cancel the URB, if it hasn't been cancelled already */
+		if (us->current_urb->status == -EINPROGRESS) {
+			US_DEBUGP("-- cancelling URB\n");
+			usb_unlink_urb(us->current_urb);
+		}
+	}
 	up(&(us->current_urb_sem));
+
+	/* wait for the completion of the URB */
 	wait_for_completion(&urb_done);
-	down(&(us->current_urb_sem));
 
 	/* return the URB status */
 	return us->current_urb->status;
@@ -436,29 +464,15 @@
 	us->dr->wIndex = cpu_to_le16(index);
 	us->dr->wLength = cpu_to_le16(size);
 
-	/* lock the URB */
-	down(&(us->current_urb_sem));
-
-	/* has the current command been aborted? */
-	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-		up(&(us->current_urb_sem));
-		return 0;
-	}
-
-	/* fill the URB */
+	/* fill and submit the URB */
 	FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, 
 			 (unsigned char*) us->dr, data, size, 
 			 usb_stor_blocking_completion, NULL);
-
-	/* submit the URB */
 	status = usb_stor_msg_common(us);
 
 	/* return the actual length of the data transferred if no error*/
 	if (status >= 0)
 		status = us->current_urb->actual_length;
-
-	/* release the lock and return status */
-	up(&(us->current_urb_sem));
 	return status;
 }
 
@@ -470,27 +484,13 @@
 {
 	int status;
 
-	/* lock the URB */
-	down(&(us->current_urb_sem));
-
-	/* has the current command been aborted? */
-	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-		up(&(us->current_urb_sem));
-		return 0;
-	}
-
-	/* fill the URB */
+	/* fill and submit the URB */
 	FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len,
 		      usb_stor_blocking_completion, NULL);
-
-	/* submit the URB */
 	status = usb_stor_msg_common(us);
 
-	/* return the actual length of the data transferred */
+	/* store the actual length of the data transferred */
 	*act_len = us->current_urb->actual_length;
-
-	/* release the lock and return status */
-	up(&(us->current_urb_sem));
 	return status;
 }
 
@@ -845,31 +845,28 @@
 }
 
 /* Abort the currently running scsi command or device reset.
- */
+ * This must be called with scsi_lock(us->srb->host) held */
 void usb_stor_abort_transport(struct us_data *us)
 {
 	int state = atomic_read(&us->sm_state);
 
 	US_DEBUGP("usb_stor_abort_transport called\n");
 
-	/* If the current state is wrong or if there's
-	 *  no srb, then there's nothing to do */
-	BUG_ON((state != US_STATE_RUNNING && state != US_STATE_RESETTING));
-	BUG_ON(!(us->srb));
+	/* Normally the current state is RUNNING.  If the control thread
+	 * hasn't even started processing this command, the state will be
+	 * IDLE.  Anything else is a bug. */
+	BUG_ON((state != US_STATE_RUNNING && state != US_STATE_IDLE));
 
-	/* set state to abort */
+	/* set state to abort and release the lock */
 	atomic_set(&us->sm_state, US_STATE_ABORTING);
+	scsi_unlock(us->srb->host);
 
 	/* If the state machine is blocked waiting for an URB or an IRQ,
 	 * let's wake it up */
 
 	/* If we have an URB pending, cancel it.  Note that we guarantee with
-	 * the current_urb_sem that either (a) an URB has just been submitted,
-	 * or (b) the URB will never get submitted.  But, because of the use
-	 * of us->sm_state and current_urb_sem, we can't get an URB sumbitted
-	 * _after_ we set the state to US_STATE_ABORTING and this section of
-	 * code runs.  Thus we avoid deadlocks.
-	 */
+	 * the current_urb_sem that if a URB has just been submitted, it
+	 * won't be cancelled more than once. */
 	down(&(us->current_urb_sem));
 	if (us->current_urb->status == -EINPROGRESS) {
 		US_DEBUGP("-- cancelling URB\n");
@@ -878,10 +875,13 @@
 	up(&(us->current_urb_sem));
 
 	/* If we are waiting for an IRQ, simulate it */
-	if (test_bit(IP_WANTED, &us->bitflags)) {
+	if (test_bit(US_FLIDX_IP_WANTED, &us->flags)) {
 		US_DEBUGP("-- simulating missing IRQ\n");
 		usb_stor_CBI_irq(us->irq_urb);
 	}
+
+	/* Reacquire the lock */
+	scsi_lock(us->srb->host);
 }
 
 /*
@@ -903,7 +903,7 @@
 	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
 
 		/* was this a wanted interrupt? */
-		if (!test_and_clear_bit(IP_WANTED, &us->bitflags)) {
+		if (!test_and_clear_bit(US_FLIDX_IP_WANTED, &us->flags)) {
 			US_DEBUGP("ERROR: Unwanted interrupt received!\n");
 			return;
 		}
@@ -919,7 +919,7 @@
 		US_DEBUGP("-- device has been removed\n");
 
 		/* was this a wanted interrupt? */
-		if (!test_and_clear_bit(IP_WANTED, &us->bitflags))
+		if (!test_and_clear_bit(US_FLIDX_IP_WANTED, &us->flags))
 			return;
 
 		/* indicate a transport error -- this is the best we can do */
@@ -943,7 +943,7 @@
 	}
 
 	/* was this a wanted interrupt? */
-	if (!test_and_clear_bit(IP_WANTED, &us->bitflags)) {
+	if (!test_and_clear_bit(US_FLIDX_IP_WANTED, &us->flags)) {
 		US_DEBUGP("ERROR: Unwanted interrupt received!\n");
 		return;
 	}
@@ -965,7 +965,7 @@
 	init_MUTEX_LOCKED(&(us->ip_waitq));
 
 	/* Set up for status notification */
-	set_bit(IP_WANTED, &us->bitflags);
+	set_bit(US_FLIDX_IP_WANTED, &us->flags);
 
 	/* COMMAND STAGE */
 	/* let's send the command via the control pipe */
@@ -978,7 +978,7 @@
 	US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result);
 	if (result < 0) {
 		/* Reset flag for status notification */
-		clear_bit(IP_WANTED, &us->bitflags);
+		clear_bit(US_FLIDX_IP_WANTED, &us->flags);
 	}
 
 	/* did we abort this command? */
@@ -1016,11 +1016,11 @@
 
 		/* report any errors */
 		if (result == US_BULK_TRANSFER_ABORTED) {
-			clear_bit(IP_WANTED, &us->bitflags);
+			clear_bit(US_FLIDX_IP_WANTED, &us->flags);
 			return USB_STOR_TRANSPORT_ABORTED;
 		}
 		if (result == US_BULK_TRANSFER_FAILED) {
-			clear_bit(IP_WANTED, &us->bitflags);
+			clear_bit(US_FLIDX_IP_WANTED, &us->flags);
 			return USB_STOR_TRANSPORT_FAILED;
 		}
 	}
@@ -1397,11 +1397,9 @@
 	/* return a result code based on the result of the control message */
 	if (result < 0) {
 		US_DEBUGP("Soft reset failed: %d\n", result);
-		us->srb->result = DID_ERROR << 16;
 		result = FAILED;
 	} else {
 		US_DEBUGP("Soft reset done\n");
-		us->srb->result = GOOD << 1;
 		result = SUCCESS;
 	}
 	return result;
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c	Tue Jul 16 16:49:42 2002
+++ b/drivers/usb/storage/usb.c	Tue Jul 16 16:49:42 2002
@@ -301,7 +301,6 @@
 static int usb_stor_control_thread(void * __us)
 {
 	struct us_data *us = (struct us_data *)__us;
-	int action;
 
 	lock_kernel();
 
@@ -334,32 +333,30 @@
 	for(;;) {
 		struct Scsi_Host *host;
 		US_DEBUGP("*** thread sleeping.\n");
-		atomic_set(&us->sm_state, US_STATE_IDLE);
 		if(down_interruptible(&us->sema))
 			break;
 			
 		US_DEBUGP("*** thread awakened.\n");
-		atomic_set(&us->sm_state, US_STATE_RUNNING);
-
-		/* lock access to the queue element */
-		spin_lock_irq(&us->queue_exclusion);
 
-		/* take the command off the queue */
-		action = us->action;
-		us->action = 0;
-		us->srb = us->queue_srb;
+		/* if us->srb is NULL, we are being asked to exit */
+		if (us->srb == NULL) {
+			US_DEBUGP("-- exit command received\n");
+			break;
+		}
 		host = us->srb->host;
 
-		/* release the queue lock as fast as possible */
-		spin_unlock_irq(&us->queue_exclusion);
+		/* lock access to the state */
+		scsi_lock(host);
 
-		/* exit if we get a signal to exit */
-		if (action == US_ACT_EXIT) {
-			US_DEBUGP("-- US_ACT_EXIT command received\n");
-			break;
+		/* has the command been aborted *already* ? */
+		if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+			us->srb->result = DID_ABORT << 16;
+			goto SkipForAbort;
 		}
 
-		BUG_ON(action != US_ACT_COMMAND);
+		/* set the state and release the lock */
+		atomic_set(&us->sm_state, US_STATE_RUNNING);
+		scsi_unlock(host);
 
 		/* lock the device pointers */
 		down(&(us->dev_semaphore));
@@ -396,7 +393,7 @@
 		}
 
 		/* our device has gone - pretend not ready */
-		else if (!test_bit(DEV_ATTACHED, &us->bitflags)) {
+		else if (!(us->flags & US_FL_DEV_ATTACHED)) {
 			US_DEBUGP("Request is for removed device\n");
 			/* For REQUEST_SENSE, it's the data.  But
 			 * for anything else, it should look like
@@ -420,7 +417,7 @@
 				       sizeof(usb_stor_sense_notready));
 				us->srb->result = CHECK_CONDITION << 1;
 			}
-		}  /* test_bit(DEV_ATTACHED, &us->bitflags) */
+		}  /* !(us->flags & US_FL_DEV_ATTACHED) */
 
 		/* Handle those devices which need us to fake 
 		 * their inquiry data */
@@ -444,19 +441,29 @@
 		/* unlock the device pointers */
 		up(&(us->dev_semaphore));
 
+		/* lock access to the state */
+		scsi_lock(host);
+
 		/* indicate that the command is done */
 		if (us->srb->result != DID_ABORT << 16) {
 			US_DEBUGP("scsi cmd done, result=0x%x\n", 
 				   us->srb->result);
-			scsi_lock(host);
 			us->srb->scsi_done(us->srb);
-			us->srb = NULL;
-			scsi_unlock(host);
 		} else {
+			SkipForAbort:
 			US_DEBUGP("scsi command aborted\n");
-			us->srb = NULL;
-			complete(&(us->notify));
 		}
+
+		/* in case an abort request was received after the command
+		 * completed, we must use a separate test to see whether
+		 * we need to signal that the abort has finished */
+		if (atomic_read(&us->sm_state) == US_STATE_ABORTING)
+			complete(&(us->notify));
+
+		/* empty the queue, reset the state, and release the lock */
+		us->srb = NULL;
+		atomic_set(&us->sm_state, US_STATE_IDLE);
+		scsi_unlock(host);
 	} /* for (;;) */
 
 	/* notify the exit routine that we're actually exiting now */
@@ -466,7 +473,7 @@
 }	
 
 /* Set up the URB, the usb_ctrlrequest, and the IRQ pipe and handler.
- * ss->dev_semaphore should already be locked.
+ * ss->dev_semaphore must already be locked.
  * Note that this function assumes that all the data in the us_data
  * strucuture is current.  This includes the ep_int field, which gives us
  * the endpoint for the interrupt.
@@ -478,19 +485,19 @@
 	int maxp;
 	int result;
 
-	/* allocate the URB we're going to use */
-	US_DEBUGP("Allocating URB\n");
-	ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!ss->current_urb) {
-		US_DEBUGP("allocation failed\n");
-		return 1;
-	}
-
 	/* allocate the usb_ctrlrequest for control packets */
 	US_DEBUGP("Allocating usb_ctrlrequest\n");
 	ss->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
 	if (!ss->dr) {
 		US_DEBUGP("allocation failed\n");
+		return 1;
+	}
+
+	/* allocate the URB we're going to use */
+	US_DEBUGP("Allocating URB\n");
+	ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ss->current_urb) {
+		US_DEBUGP("allocation failed\n");
 		return 2;
 	}
 
@@ -554,12 +561,6 @@
 	}
 	up(&(ss->irq_urb_sem));
 
-	/* free the usb_ctrlrequest buffer */
-	if (ss->dr) {
-		kfree(ss->dr);
-		ss->dr = NULL;
-	}
-
 	/* free up the main URB for this device */
 	if (ss->current_urb) {
 		US_DEBUGP("-- releasing main URB\n");
@@ -569,8 +570,14 @@
 		ss->current_urb = NULL;
 	}
 
+	/* free the usb_ctrlrequest buffer */
+	if (ss->dr) {
+		kfree(ss->dr);
+		ss->dr = NULL;
+	}
+
 	/* mark the device as gone */
-	clear_bit(DEV_ATTACHED, &ss->bitflags);
+	ss->flags &= ~ US_FL_DEV_ATTACHED;
 	usb_put_dev(ss->pusb_dev);
 	ss->pusb_dev = NULL;
 }
@@ -726,7 +733,7 @@
 	 */
 	ss = us_list;
 	while ((ss != NULL) && 
-	           (test_bit(DEV_ATTACHED, &ss->bitflags) ||
+	           ((ss->flags & US_FL_DEV_ATTACHED) ||
 		    !GUID_EQUAL(guid, ss->guid)))
 		ss = ss->next;
 
@@ -741,7 +748,7 @@
 		/* establish the connection to the new device upon reconnect */
 		ss->ifnum = ifnum;
 		ss->pusb_dev = dev;
-		set_bit(DEV_ATTACHED, &ss->bitflags);
+		ss->flags |= US_FL_DEV_ATTACHED;
 
 		/* copy over the endpoint data */
 		ss->ep_in = ep_in->bEndpointAddress & 
@@ -777,15 +784,14 @@
 		/* Initialize the mutexes only when the struct is new */
 		init_completion(&(ss->notify));
 		init_MUTEX_LOCKED(&(ss->ip_waitq));
-		spin_lock_init(&ss->queue_exclusion);
 		init_MUTEX(&(ss->irq_urb_sem));
 		init_MUTEX(&(ss->current_urb_sem));
-		init_MUTEX(&(ss->dev_semaphore));
+		init_MUTEX_LOCKED(&(ss->dev_semaphore));
 
 		/* copy over the subclass and protocol data */
 		ss->subclass = subclass;
 		ss->protocol = protocol;
-		ss->flags = flags;
+		ss->flags = flags | US_FL_DEV_ATTACHED;
 		ss->unusual_dev = unusual_dev;
 
 		/* copy over the endpoint data */
@@ -1000,7 +1006,6 @@
 
 		/* start up our control thread */
 		atomic_set(&ss->sm_state, US_STATE_IDLE);
-		set_bit(DEV_ATTACHED, &ss->bitflags);
 		ss->pid = kernel_thread(usb_stor_control_thread, ss,
 					CLONE_VM);
 		if (ss->pid < 0) {
@@ -1012,6 +1017,9 @@
 		/* wait for the thread to start */
 		wait_for_completion(&(ss->notify));
 
+		/* unlock the device pointers */
+		up(&(ss->dev_semaphore));
+
 		/* now register	 - our detect function will be called */
 		ss->htmplt.module = THIS_MODULE;
 		result = scsi_register_host(&(ss->htmplt));
@@ -1020,9 +1028,12 @@
 				"Unable to register the scsi host\n");
 
 			/* tell the control thread to exit */
-			ss->action = US_ACT_EXIT;
+			ss->srb = NULL;
 			up(&ss->sema);
 			wait_for_completion(&ss->notify);
+
+			/* re-lock the device pointers */
+			down(&ss->dev_semaphore);
 			goto BadDevice;
 		}
 
@@ -1046,13 +1057,13 @@
 	return ss;
 
 	/* we come here if there are any problems */
+	/* ss->dev_semaphore must be locked */
 	BadDevice:
 	US_DEBUGP("storage_probe() failed\n");
 	usb_stor_deallocate_urbs(ss);
+	up(&ss->dev_semaphore);
 	if (new_device)
 		kfree(ss);
-	else
-		up(&ss->dev_semaphore);
 	return NULL;
 }
 
diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h	Tue Jul 16 16:49:43 2002
+++ b/drivers/usb/storage/usb.h	Tue Jul 16 16:49:43 2002
@@ -100,13 +100,12 @@
 						    Win/MacOS compatibility */
 #define US_FL_START_STOP      0x00000004 /* ignore START_STOP commands	    */
 #define US_FL_IGNORE_SER      0x00000010 /* Ignore the serial number given  */
-#define US_FL_SCM_MULT_TARG   0x00000020 /* supports multiple targets */
-#define US_FL_FIX_INQUIRY     0x00000040 /* INQUIRY response needs fixing */
+#define US_FL_SCM_MULT_TARG   0x00000020 /* supports multiple targets	    */
+#define US_FL_FIX_INQUIRY     0x00000040 /* INQUIRY response needs fixing   */
 
+#define US_FL_DEV_ATTACHED    0x00010000 /* is the device attached?	    */
+#define US_FLIDX_IP_WANTED   17  /* 0x00020000	is an IRQ expected?	    */
 
-/* kernel thread actions */
-#define US_ACT_COMMAND		1
-#define US_ACT_EXIT		5
 
 /* processing state machine states */
 #define US_STATE_IDLE		1
@@ -128,12 +127,11 @@
 	/* The device we're working with
 	 * It's important to note:
 	 *    (o) you must hold dev_semaphore to change pusb_dev
-	 *    (o) DEV_ATTACHED in bitflags should change whenever pusb_dev does
+	 *    (o) DEV_ATTACHED in flags should change whenever pusb_dev does
 	 */
 	struct semaphore	dev_semaphore;	 /* protect pusb_dev */
 	struct usb_device	*pusb_dev;	 /* this usb_device */
-
-	unsigned int		flags;		 /* from filter initially */
+	unsigned long		flags;		 /* from filter initially */
 
 	/* information about the device -- always good */
 	char			vendor[USB_STOR_STRING_LEN];
@@ -165,16 +163,11 @@
 	Scsi_Cmnd		*srb;		 /* current srb		*/
 
 	/* thread information */
-	Scsi_Cmnd		*queue_srb;	 /* the single queue slot */
-	int			action;		 /* what to do		  */
-	int			pid;		 /* control thread	  */
-	atomic_t		sm_state;
+	int			pid;		 /* control thread	 */
+	atomic_t		sm_state;	 /* what we are doing	 */
 
 	/* interrupt info for CBI devices -- only good if attached */
 	struct semaphore	ip_waitq;	 /* for CBI interrupts	 */
-	unsigned long		bitflags;	 /* single-bit flags:	 */
-#define IP_WANTED	1			 /* is an IRQ expected?	 */
-#define DEV_ATTACHED	2			 /* is the dev. attached?*/
 
 	/* interrupt communications data */
 	struct semaphore	irq_urb_sem;	 /* to protect irq_urb	 */
@@ -183,7 +176,7 @@
 	unsigned char		irqdata[2];	 /* data from USB IRQ	 */
 
 	/* control and bulk communications data */
-	struct semaphore	current_urb_sem; /* to protect irq_urb	 */
+	struct semaphore	current_urb_sem; /* protect current_urb  */
 	struct urb		*current_urb;	 /* non-int USB requests */
 	struct usb_ctrlrequest	*dr;		 /* control requests	 */
 
@@ -192,7 +185,6 @@
 
 	/* mutual exclusion structures */
 	struct completion	notify;		 /* thread begin/end	    */
-	spinlock_t		queue_exclusion; /* to protect data structs */
 	struct us_unusual_dev   *unusual_dev;	 /* If unusual device       */
 	void			*extra;		 /* Any extra data          */
 	extra_data_destructor	extra_destructor;/* extra data destructor   */
@@ -209,6 +201,8 @@
 extern void fill_inquiry_response(struct us_data *us,
 	unsigned char *data, unsigned int data_len);
 
+/* The scsi_lock() and scsi_unlock() macros protect the sm_state and the
+ * single queue element srb for write access */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3)
 #define scsi_unlock(host)	spin_unlock_irq(host->host_lock)
 #define scsi_lock(host)		spin_lock_irq(host->host_lock)
diff -Nru a/drivers/video/Config.in b/drivers/video/Config.in
--- a/drivers/video/Config.in	Tue Jul 16 16:49:42 2002
+++ b/drivers/video/Config.in	Tue Jul 16 16:49:42 2002
@@ -91,10 +91,10 @@
    if [ "$CONFIG_HP300" = "y" ]; then
       define_bool CONFIG_FB_HP300 y
    fi
-   if [ "$ARCH" = "alpha" ]; then
+   if [ "$CONFIG_ALPHA" = "y" ]; then
       tristate '  TGA framebuffer support' CONFIG_FB_TGA
    fi
-   if [ "$ARCH" = "i386" ]; then
+   if [ "$CONFIG_X86" = "y" ]; then
       bool '  VESA VGA graphics console' CONFIG_FB_VESA
       tristate '  VGA 16-color graphics console' CONFIG_FB_VGA16
       tristate '  Hercules mono graphics console (EXPERIMENTAL)' CONFIG_FB_HGA
@@ -158,16 +158,16 @@
 	 tristate '  Permedia3 support (EXPERIMENTAL)' CONFIG_FB_PM3
       fi
    fi
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       bool '  SBUS and UPA framebuffers' CONFIG_FB_SBUS
       if [ "$CONFIG_FB_SBUS" != "n" ]; then
-	 if [ "$ARCH" = "sparc64" ]; then
+	 if [ "$CONFIG_SPARC64" = "y" ]; then
 	    bool '    Creator/Creator3D support' CONFIG_FB_CREATOR
 	 fi
 	 bool '    CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
 	 bool '    BWtwo support' CONFIG_FB_BWTWO
 	 bool '    CGthree support' CONFIG_FB_CGTHREE
-	 if [ "$ARCH" = "sparc" ]; then
+	 if [ "$CONFIG_SPARC32" = "y" ]; then
 	    bool '    TCX (SS4/SS5 only) support' CONFIG_FB_TCX
 	    bool '    CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN
 	    bool '    P9100 (Sparcbook 3 only) support' CONFIG_FB_P9100
@@ -175,7 +175,7 @@
 	 bool '    Leo (ZX) support' CONFIG_FB_LEO
       fi
    fi
-   if [ "$ARCH" = "sparc" ]; then
+   if [ "$CONFIG_SPARC32" = "y" ]; then
       if [ "$CONFIG_PCI" != "n" ]; then
 	 bool '  PCI framebuffers' CONFIG_FB_PCI
 	 if [ "$CONFIG_FB_PCI" != "n" ]; then
@@ -183,7 +183,7 @@
 	 fi
       fi
    fi
-   if [ "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC64" = "y" ]; then
       if [ "$CONFIG_PCI" != "n" ]; then
 	 bool '  PCI framebuffers' CONFIG_FB_PCI
 	 if [ "$CONFIG_FB_PCI" != "n" ]; then
@@ -208,7 +208,7 @@
       bool '  TMPTX3912/PR31700 frame buffer support' CONFIG_FB_TX3912
    fi
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate '  Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
+      tristate '  Virtual Frame Buffer support (ONLY FOR TESTING!) (EXPERIMENTAL)' CONFIG_FB_VIRTUAL
    fi
 
    bool '  Advanced low level driver options' CONFIG_FBCON_ADVANCED
@@ -427,7 +427,7 @@
       fi
    fi
    bool '  Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       bool '  Sparc console 8x16 font' CONFIG_FONT_SUN8x16
       if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
 	 bool '  Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
diff -Nru a/fs/Config.in b/fs/Config.in
--- a/fs/Config.in	Tue Jul 16 16:49:43 2002
+++ b/fs/Config.in	Tue Jul 16 16:49:43 2002
@@ -6,7 +6,7 @@
 
 bool 'Quota support' CONFIG_QUOTA
 dep_tristate '  Old quota format support' CONFIG_QFMT_V1 $CONFIG_QUOTA
-dep_tristate '  VFS v0 quota format support' CONFIG_QFMT_V2 $CONFIG_QUOTA
+dep_tristate '  Quota format v2 support' CONFIG_QFMT_V2 $CONFIG_QUOTA
 if [ "$CONFIG_QUOTA" = "y" ]; then
    define_bool CONFIG_QUOTACTL y
 fi
diff -Nru a/fs/Makefile b/fs/Makefile
--- a/fs/Makefile	Tue Jul 16 16:49:41 2002
+++ b/fs/Makefile	Tue Jul 16 16:49:41 2002
@@ -15,7 +15,7 @@
 		namei.o fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
 		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
 		filesystems.o namespace.o seq_file.o xattr.o libfs.o \
-		fs-writeback.o mpage.o
+		fs-writeback.o mpage.o direct-io.o
 
 ifneq ($(CONFIG_NFSD),n)
 ifneq ($(CONFIG_NFSD),)
diff -Nru a/fs/affs/namei.c b/fs/affs/namei.c
--- a/fs/affs/namei.c	Tue Jul 16 16:49:42 2002
+++ b/fs/affs/namei.c	Tue Jul 16 16:49:42 2002
@@ -338,19 +338,10 @@
 int
 affs_rmdir(struct inode *dir, struct dentry *dentry)
 {
-	int res;
 	pr_debug("AFFS: rmdir(dir=%u, \"%.*s\")\n", (u32)dir->i_ino,
 		 (int)dentry->d_name.len, dentry->d_name.name);
 
-	lock_kernel();
-
-	/* WTF??? */
-	if (!dentry->d_inode)
-		return -ENOENT;
-
-	res = affs_remove_header(dentry);
-	unlock_kernel();
-	return res;
+	return affs_remove_header(dentry);
 }
 
 int
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Tue Jul 16 16:49:43 2002
+++ b/fs/block_dev.c	Tue Jul 16 16:49:43 2002
@@ -106,9 +106,12 @@
 	return 0;
 }
 
-static int blkdev_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsigned long blocknr, int blocksize)
+static int
+blkdev_direct_IO(int rw, struct inode *inode, char *buf,
+			loff_t offset, size_t count)
 {
-	return generic_direct_IO(rw, inode, iobuf, blocknr, blocksize, blkdev_get_block);
+	return generic_direct_IO(rw, inode, buf, offset,
+				count, blkdev_get_block);
 }
 
 static int blkdev_writepage(struct page * page)
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Tue Jul 16 16:49:41 2002
+++ b/fs/buffer.c	Tue Jul 16 16:49:41 2002
@@ -519,8 +519,7 @@
 		if (buffer_async_read(tmp)) {
 			if (buffer_locked(tmp))
 				goto still_busy;
-			if (!buffer_mapped(bh))
-				BUG();
+			BUG();
 		}
 		tmp = tmp->b_this_page;
 	} while (tmp != bh);
@@ -570,8 +569,7 @@
 		if (buffer_async_write(tmp)) {
 			if (buffer_locked(tmp))
 				goto still_busy;
-			if (!buffer_mapped(bh))
-				BUG();
+			BUG();
 		}
 		tmp = tmp->b_this_page;
 	}
@@ -2311,12 +2309,14 @@
 	return tmp.b_blocknr;
 }
 
+#if 0
 int generic_direct_IO(int rw, struct inode *inode,
 			struct kiobuf *iobuf, unsigned long blocknr,
 			int blocksize, get_block_t *get_block)
 {
-	int i, nr_blocks, retval;
+	int i, nr_blocks, retval = 0;
 	sector_t *blocks = iobuf->blocks;
+	struct block_device *bdev = NULL;
 
 	nr_blocks = iobuf->length / blocksize;
 	/* build the blocklist */
@@ -2346,15 +2346,17 @@
 				BUG();
 		}
 		blocks[i] = bh.b_blocknr;
+		bdev = bh.b_bdev;
 	}
 
 	/* This does not understand multi-device filesystems currently */
-	retval = brw_kiovec(rw, 1, &iobuf,
-			inode->i_sb->s_bdev, blocks, blocksize);
+	if (bdev)
+		retval = brw_kiovec(rw, 1, &iobuf, bdev, blocks, blocksize);
 
  out:
 	return retval;
 }
+#endif
 
 /*
  * Start I/O on a physical range of kernel memory, defined by a vector
diff -Nru a/fs/dcache.c b/fs/dcache.c
--- a/fs/dcache.c	Tue Jul 16 16:49:41 2002
+++ b/fs/dcache.c	Tue Jul 16 16:49:41 2002
@@ -137,6 +137,7 @@
 		goto kill_it;
 	list_add(&dentry->d_lru, &dentry_unused);
 	dentry_stat.nr_unused++;
+	dentry->d_vfs_flags |= DCACHE_REFERENCED;
 	spin_unlock(&dcache_lock);
 	return;
 
@@ -883,7 +884,6 @@
 			if (memcmp(dentry->d_name.name, str, len))
 				continue;
 		}
-		dentry->d_vfs_flags |= DCACHE_REFERENCED;
 		return dentry;
 	}
 	return NULL;
diff -Nru a/fs/direct-io.c b/fs/direct-io.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/direct-io.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,491 @@
+/*
+ * mm/direct-io.c
+ *
+ * Copyright (C) 2002, Linus Torvalds.
+ *
+ * O_DIRECT
+ *
+ * 04Jul2002	akpm@zip.com.au
+ *		Initial version
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/bio.h>
+#include <linux/wait.h>
+#include <linux/err.h>
+#include <linux/buffer_head.h>
+#include <linux/rwsem.h>
+#include <asm/atomic.h>
+
+/*
+ * The largest-sized BIO which this code will assemble, in bytes.  Set this
+ * to PAGE_SIZE if your drivers are broken.
+ */
+#define DIO_BIO_MAX_SIZE BIO_MAX_SIZE
+
+/*
+ * How many user pages to map in one call to get_user_pages().  This determines
+ * the size of a structure on the stack.
+ */
+#define DIO_PAGES	64
+
+struct dio {
+	/* BIO submission state */
+	struct bio *bio;		/* bio under assembly */
+	struct bio_vec *bvec;		/* current bvec in that bio */
+	struct inode *inode;
+	int rw;
+	sector_t block_in_file;		/* changes */
+	sector_t final_block_in_request;/* doesn't change */
+	unsigned first_block_in_page;	/* doesn't change */
+	int boundary;			/* prev block is at a boundary */
+	int reap_counter;		/* rate limit reaping */
+	get_block_t *get_block;
+	sector_t last_block_in_bio;
+
+	/* Page fetching state */
+	int curr_page;			/* changes */
+	int total_pages;		/* doesn't change */
+	unsigned long curr_user_address;/* changes */
+
+	/* Page queue */
+	struct page *pages[DIO_PAGES];
+	unsigned head;
+	unsigned tail;
+
+	/* BIO completion state */
+	atomic_t bio_count;
+	spinlock_t bio_list_lock;
+	struct bio *bio_list;		/* singly linked via bi_private */
+	wait_queue_head_t wait_q;
+};
+
+/*
+ * How many pages are in the queue?
+ */
+static inline unsigned dio_pages_present(struct dio *dio)
+{
+	return dio->head - dio->tail;
+}
+
+/*
+ * Go grab and pin some userspace pages.   Typically we'll get 64 at a time.
+ */
+static int dio_refill_pages(struct dio *dio)
+{
+	int ret;
+	int nr_pages;
+
+	nr_pages = min(dio->total_pages - dio->curr_page, DIO_PAGES);
+	ret = get_user_pages(
+		current,			/* Task for fault acounting */
+		current->mm,			/* whose pages? */
+		dio->curr_user_address,		/* Where from? */
+		nr_pages,			/* How many pages? */
+		dio->rw == READ,		/* Write to memory? */
+		0,				/* force (?) */
+		&dio->pages[0],
+		NULL);				/* vmas */
+
+	if (ret >= 0) {
+		dio->curr_user_address += ret * PAGE_SIZE;
+		dio->curr_page += ret;
+		dio->head = 0;
+		dio->tail = ret;
+		ret = 0;
+	}
+	return ret;	
+}
+
+/*
+ * Get another userspace page.  Returns an ERR_PTR on error.  Pages are
+ * buffered inside the dio so that we can call get_user_pages() against a
+ * decent number of pages, less frequently.  To provide nicer use of the
+ * L1 cache.
+ */
+static struct page *dio_get_page(struct dio *dio)
+{
+	if (dio_pages_present(dio) == 0) {
+		int ret;
+
+		ret = dio_refill_pages(dio);
+		if (ret) {
+			printk("%s: dio_refill_pages returns %d\n",
+				__FUNCTION__, ret);
+			return ERR_PTR(ret);
+		}
+		BUG_ON(dio_pages_present(dio) == 0);
+	}
+	return dio->pages[dio->head++];
+}
+
+/*
+ * The BIO completion handler simply queues the BIO up for the process-context
+ * handler.
+ *
+ * During I/O bi_private points at the dio.  After I/O, bi_private is used to
+ * implement a singly-linked list of completed BIOs, at dio->bio_list.
+ */
+static void dio_bio_end_io(struct bio *bio)
+{
+	struct dio *dio = bio->bi_private;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dio->bio_list_lock, flags);
+	bio->bi_private = dio->bio_list;
+	dio->bio_list = bio;
+	spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+	wake_up(&dio->wait_q);
+}
+
+static int
+dio_bio_alloc(struct dio *dio, struct block_device *bdev,
+		sector_t first_sector, int nr_vecs)
+{
+	struct bio *bio;
+
+	bio = bio_alloc(GFP_KERNEL, nr_vecs);
+	if (bio == NULL)
+		return -ENOMEM;
+
+	bio->bi_bdev = bdev;
+	bio->bi_vcnt = nr_vecs;
+	bio->bi_idx = 0;
+	bio->bi_size = 0;
+	bio->bi_sector = first_sector;
+	bio->bi_io_vec[0].bv_page = NULL;
+	bio->bi_end_io = dio_bio_end_io;
+
+	dio->bio = bio;
+	dio->bvec = NULL;		/* debug */
+	return 0;
+}
+
+static void dio_bio_submit(struct dio *dio)
+{
+	struct bio *bio = dio->bio;
+
+	bio->bi_vcnt = bio->bi_idx;
+	bio->bi_idx = 0;
+	bio->bi_private = dio;
+	atomic_inc(&dio->bio_count);
+	submit_bio(dio->rw, bio);
+
+	dio->bio = NULL;
+	dio->bvec = NULL;
+}
+
+/*
+ * Release any resources in case of a failure
+ */
+static void dio_cleanup(struct dio *dio)
+{
+	while (dio_pages_present(dio))
+		page_cache_release(dio_get_page(dio));
+}
+
+/*
+ * Wait for the next BIO to complete.  Remove it and return it.
+ */
+static struct bio *dio_await_one(struct dio *dio)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long flags;
+	struct bio *bio;
+
+	spin_lock_irqsave(&dio->bio_list_lock, flags);
+	while (dio->bio_list == NULL) {
+		add_wait_queue(&dio->wait_q, &wait);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		if (dio->bio_list == NULL) {
+			spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+			blk_run_queues();
+			schedule();
+			spin_lock_irqsave(&dio->bio_list_lock, flags);
+		}
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&dio->wait_q, &wait);
+	}
+	bio = dio->bio_list;
+	dio->bio_list = bio->bi_private;
+	spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+	return bio;
+}
+
+/*
+ * Process one completed BIO.  No locks are held.
+ */
+static int dio_bio_complete(struct dio *dio, struct bio *bio)
+{
+	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+	struct bio_vec *bvec = bio->bi_io_vec;
+	int page_no;
+	int ret = 0;
+
+	for (page_no = 0; page_no < bio->bi_vcnt; page_no++) {
+		struct page *page = bvec[page_no].bv_page;
+
+		if (!uptodate) {
+			if (ret == 0)
+				ret = -EIO;
+		}
+
+		if (dio->rw == READ)
+			set_page_dirty(page);
+		page_cache_release(page);
+	}
+	atomic_dec(&dio->bio_count);
+	bio_put(bio);
+	return ret;
+}
+
+/*
+ * Wait on and process all in-flight BIOs.
+ */
+static int dio_await_completion(struct dio *dio)
+{
+	int ret = 0;
+	while (atomic_read(&dio->bio_count)) {
+		struct bio *bio = dio_await_one(dio);
+		int ret2;
+
+		ret2 = dio_bio_complete(dio, bio);
+		if (ret == 0)
+			ret = ret2;
+	}
+	return ret;
+}
+
+/*
+ * A really large O_DIRECT read or write can generate a lot of BIOs.  So
+ * to keep the memory consumption sane we periodically reap any completed BIOs
+ * during the BIO generation phase.
+ *
+ * This also helps to limis the peak amount of pinned userspace memory.
+ */
+static int dio_bio_reap(struct dio *dio)
+{
+	int ret = 0;
+
+	if (dio->reap_counter++ >= 64) {
+		while (dio->bio_list) {
+			unsigned long flags;
+			struct bio *bio;
+			int ret2;
+
+			spin_lock_irqsave(&dio->bio_list_lock, flags);
+			bio = dio->bio_list;
+			dio->bio_list = bio->bi_private;
+			spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+			ret2 = dio_bio_complete(dio, bio);
+			if (ret == 0)
+				ret = ret2;
+		}
+		dio->reap_counter = 0;
+	}
+	return ret;
+}
+
+/*
+ * Walk the user pages, and the file, mapping blocks to disk and emitting BIOs.
+ */
+int do_direct_IO(struct dio *dio)
+{
+	struct inode * const inode = dio->inode;
+	const unsigned blkbits = inode->i_blkbits;
+	const unsigned blocksize = 1 << blkbits;
+	const unsigned blocks_per_page = PAGE_SIZE >> blkbits;
+	struct page *page;
+	unsigned block_in_page;
+	int ret;
+
+	/* The I/O can start at any block offset within the first page */
+	block_in_page = dio->first_block_in_page;
+
+	while (dio->block_in_file < dio->final_block_in_request) {
+		int new_page;	/* Need to insert this page into the BIO? */
+
+		page = dio_get_page(dio);
+		if (IS_ERR(page)) {
+			ret = PTR_ERR(page);
+			goto out;
+		}
+
+		new_page = 1;
+		for ( ; block_in_page < blocks_per_page; block_in_page++) {
+			struct buffer_head map_bh;
+			struct bio *bio;
+
+			map_bh.b_state = 0;
+			ret = (*dio->get_block)(inode, dio->block_in_file,
+						&map_bh, dio->rw == WRITE);
+			if (ret) {
+				printk("%s: get_block returns %d\n",
+					__FUNCTION__, ret);
+				goto fail_release;
+			}
+			/* blockdevs do not set buffer_new */
+			if (buffer_new(&map_bh))
+				unmap_underlying_metadata(map_bh.b_bdev,
+							map_bh.b_blocknr);
+			if (!buffer_mapped(&map_bh)) {
+				ret = -EINVAL;		/* A hole */
+				goto fail_release;
+			}
+			if (dio->bio) {
+				if (dio->bio->bi_idx == dio->bio->bi_vcnt ||
+						dio->boundary ||
+						dio->last_block_in_bio !=
+							map_bh.b_blocknr - 1) {
+					dio_bio_submit(dio);
+					dio->boundary = 0;
+				}
+			}
+			if (dio->bio == NULL) {
+				ret = dio_bio_reap(dio);
+				if (ret)
+					goto fail_release;
+				ret = dio_bio_alloc(dio, map_bh.b_bdev,
+					map_bh.b_blocknr << (blkbits - 9),
+					DIO_BIO_MAX_SIZE / PAGE_SIZE);
+				if (ret)
+					goto fail_release;
+				new_page = 1;
+				dio->boundary = 0;
+			}
+
+			bio = dio->bio;
+			if (new_page) {
+				dio->bvec = &bio->bi_io_vec[bio->bi_idx];
+				page_cache_get(page);
+				dio->bvec->bv_page = page;
+				dio->bvec->bv_len = 0;
+				dio->bvec->bv_offset = block_in_page*blocksize;
+				bio->bi_idx++;
+			}
+			new_page = 0;
+			dio->bvec->bv_len += blocksize;
+			bio->bi_size += blocksize;
+			dio->last_block_in_bio = map_bh.b_blocknr;
+			dio->boundary = buffer_boundary(&map_bh);
+
+			dio->block_in_file++;
+			if (dio->block_in_file >= dio->final_block_in_request)
+				break;
+		}
+		block_in_page = 0;
+		page_cache_release(page);
+	}
+	ret = 0;
+	goto out;
+fail_release:
+	page_cache_release(page);
+out:
+	return ret;
+}
+
+struct dio *g_dio;
+
+int
+generic_direct_IO(int rw, struct inode *inode, char *buf, loff_t offset,
+			size_t count, get_block_t get_block)
+{
+	const unsigned blocksize_mask = (1 << inode->i_blkbits) - 1;
+	const unsigned long user_addr = (unsigned long)buf;
+	int ret = 0;
+	int ret2;
+	struct dio dio;
+	size_t bytes;
+
+	/* Check the memory alignment.  Blocks cannot straddle pages */
+	if ((user_addr & blocksize_mask) || (count & blocksize_mask)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	g_dio = &dio;
+
+	/* BIO submission state */
+	dio.bio = NULL;
+	dio.bvec = NULL;
+	dio.inode = inode;
+	dio.rw = rw;
+	dio.block_in_file = offset >> inode->i_blkbits;
+	dio.final_block_in_request = (offset + count) >> inode->i_blkbits;
+
+	/* Index into the first page of the first block */
+	dio.first_block_in_page = (user_addr & (PAGE_SIZE - 1))
+						>> inode->i_blkbits;
+	dio.boundary = 0;
+	dio.reap_counter = 0;
+	dio.get_block = get_block;
+	dio.last_block_in_bio = -1;
+
+	/* Page fetching state */
+	dio.curr_page = 0;
+	bytes = count;
+	dio.total_pages = 0;
+	if (offset & PAGE_SIZE) {
+		dio.total_pages++;
+		bytes -= PAGE_SIZE - (offset & ~(PAGE_SIZE - 1));
+	}
+	dio.total_pages += (bytes + PAGE_SIZE - 1) / PAGE_SIZE;
+	dio.curr_user_address = user_addr;
+
+	/* Page queue */
+	dio.head = 0;
+	dio.tail = 0;
+
+	/* BIO completion state */
+	atomic_set(&dio.bio_count, 0);
+	spin_lock_init(&dio.bio_list_lock);
+	dio.bio_list = NULL;
+	init_waitqueue_head(&dio.wait_q);
+
+	down_read(&current->mm->mmap_sem);
+	ret = do_direct_IO(&dio);
+	up_read(&current->mm->mmap_sem);
+
+	if (dio.bio)
+		dio_bio_submit(&dio);
+	if (ret)
+		dio_cleanup(&dio);
+	ret2 = dio_await_completion(&dio);
+	if (ret == 0)
+		ret = ret2;
+	if (ret == 0)
+		ret = count - ((dio.final_block_in_request -
+				dio.block_in_file) << inode->i_blkbits);
+out:
+	return ret;
+}
+
+ssize_t
+generic_file_direct_IO(int rw, struct inode *inode, char *buf,
+			loff_t offset, size_t count)
+{
+	struct address_space *mapping = inode->i_mapping;
+	unsigned blocksize_mask;
+	ssize_t retval;
+
+	blocksize_mask = (1 << inode->i_blkbits) - 1;
+	if ((offset & blocksize_mask) || (count & blocksize_mask)) {
+		retval = -EINVAL;
+		goto out;
+	}
+
+	if (mapping->nrpages) {
+		retval = filemap_fdatawrite(mapping);
+		if (retval == 0)
+			retval = filemap_fdatawait(mapping);
+		if (retval)
+			goto out;
+	}
+	retval = mapping->a_ops->direct_IO(rw, inode, buf, offset, count);
+out:
+	return retval;
+}
diff -Nru a/fs/driverfs/inode.c b/fs/driverfs/inode.c
--- a/fs/driverfs/inode.c	Tue Jul 16 16:49:41 2002
+++ b/fs/driverfs/inode.c	Tue Jul 16 16:49:41 2002
@@ -119,6 +119,9 @@
 		case S_IFDIR:
 			inode->i_op = &driverfs_dir_inode_operations;
 			inode->i_fop = &simple_dir_operations;
+
+			/* directory inodes start off with i_nlink == 2 (for "." entry) */
+			inode->i_nlink++;
 			break;
 		case S_IFLNK:
 			inode->i_op = &page_symlink_inode_operations;
@@ -149,10 +152,8 @@
 	lock_kernel();
 	dentry->d_op = &driverfs_dentry_dir_ops;
  	res = driverfs_mknod(dir, dentry, mode | S_IFDIR, 0);
- 	if (!res) {
+ 	if (!res)
  		dir->i_nlink++;
- 		dentry->d_inode->i_nlink++;
- 	}
 	unlock_kernel();
 	return res;
 }
diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c
--- a/fs/ext2/inode.c	Tue Jul 16 16:49:41 2002
+++ b/fs/ext2/inode.c	Tue Jul 16 16:49:41 2002
@@ -607,11 +607,10 @@
 }
 
 static int
-ext2_direct_IO(int rw, struct inode *inode, struct kiobuf *iobuf,
-			unsigned long blocknr, int blocksize)
+ext2_direct_IO(int rw, struct inode *inode, char *buf,
+			loff_t offset, size_t count)
 {
-	return generic_direct_IO(rw, inode, iobuf, blocknr,
-				blocksize, ext2_get_block);
+	return generic_direct_IO(rw, inode, buf, offset, count, ext2_get_block);
 }
 
 static int
@@ -1106,7 +1105,7 @@
 	raw_inode->i_frag = ei->i_frag_no;
 	raw_inode->i_fsize = ei->i_frag_size;
 	raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);
-	if (S_ISDIR(inode->i_mode))
+	if (!S_ISREG(inode->i_mode))
 		raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl);
 	else {
 		raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
diff -Nru a/fs/hpfs/dir.c b/fs/hpfs/dir.c
--- a/fs/hpfs/dir.c	Tue Jul 16 16:49:42 2002
+++ b/fs/hpfs/dir.c	Tue Jul 16 16:49:42 2002
@@ -211,7 +211,10 @@
 
 	lock_kernel();
 	if ((err = hpfs_chk_name((char *)name, &len))) {
-		if (err == -ENAMETOOLONG) return ERR_PTR(-ENAMETOOLONG);
+		if (err == -ENAMETOOLONG) {
+			unlock_kernel();
+			return ERR_PTR(-ENAMETOOLONG);
+		}
 		goto end_add;
 	}
 
diff -Nru a/fs/jfs/jfs_debug.c b/fs/jfs/jfs_debug.c
--- a/fs/jfs/jfs_debug.c	Tue Jul 16 16:49:42 2002
+++ b/fs/jfs/jfs_debug.c	Tue Jul 16 16:49:42 2002
@@ -52,8 +52,14 @@
 		printk("%s\n", line);
 	}
 }
+#endif
+
+#ifdef PROC_FS_JFS /* see jfs_debug.h */
+
+static struct proc_dir_entry *base;
+#ifdef CONFIG_JFS_DEBUG
+extern read_proc_t jfs_txanchor_read;
 
-#ifdef CONFIG_PROC_FS
 static int loglevel_read(char *page, char **start, off_t off,
 			 int count, int *eof, void *data)
 {
@@ -89,28 +95,29 @@
 	jfsloglevel = c - '0';
 	return count;
 }
+#endif
 
 
-extern read_proc_t jfs_txanchor_read;
 #ifdef CONFIG_JFS_STATISTICS
 extern read_proc_t jfs_lmstats_read;
 extern read_proc_t jfs_xtstat_read;
 extern read_proc_t jfs_mpstat_read;
 #endif
-static struct proc_dir_entry *base;
 
 static struct {
 	const char	*name;
 	read_proc_t	*read_fn;
 	write_proc_t	*write_fn;
 } Entries[] = {
-	{ "TxAnchor",	jfs_txanchor_read, },
 #ifdef CONFIG_JFS_STATISTICS
 	{ "lmstats",	jfs_lmstats_read, },
 	{ "xtstat",	jfs_xtstat_read, },
 	{ "mpstat",	jfs_mpstat_read, },
 #endif
+#ifdef CONFIG_JFS_DEBUG
+	{ "TxAnchor",	jfs_txanchor_read, },
 	{ "loglevel",	loglevel_read, loglevel_write }
+#endif
 };
 #define NPROCENT	(sizeof(Entries)/sizeof(Entries[0]))
 
@@ -142,5 +149,4 @@
 	}
 }
 
-#endif /* CONFIG_PROC_FS */
-#endif /* CONFIG_JFS_DEBUG */
+#endif /* PROC_FS_JFS */
diff -Nru a/fs/jfs/jfs_debug.h b/fs/jfs/jfs_debug.h
--- a/fs/jfs/jfs_debug.h	Tue Jul 16 16:49:42 2002
+++ b/fs/jfs/jfs_debug.h	Tue Jul 16 16:49:42 2002
@@ -27,6 +27,14 @@
  */
 
 /*
+ * Create /proc/fs/jfs if procfs is enabled andeither
+ * CONFIG_JFS_DEBUG or CONFIG_JFS_STATISTICS is defined
+ */
+#if defined(CONFIG_PROC_FS) && (defined(CONFIG_JFS_DEBUG) || defined(CONFIG_JFS_STATISTICS))
+	#define PROC_FS_JFS
+#endif
+
+/*
  *	assert with traditional printf/panic
  */
 #ifdef CONFIG_KERNEL_ASSERTS
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Tue Jul 16 16:49:42 2002
+++ b/fs/jfs/jfs_logmgr.c	Tue Jul 16 16:49:42 2002
@@ -1109,7 +1109,7 @@
 
 	if ((rc = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_FS))) {
 		rc = -rc;
-		goto bdput;
+		goto free;
 	}
 
 	if ((rc = bd_claim(bdev, log))) {
@@ -1149,9 +1149,6 @@
       close:		/* close external log device */
 	blkdev_put(bdev, BDEV_FS);
 
-      bdput:
-	bdput(bdev);
-
       free:		/* free log descriptor */
 	kfree(log);
 
@@ -1398,7 +1395,6 @@
 
 	bd_release(bdev);
 	blkdev_put(bdev, BDEV_FS);
-	bdput(bdev);
 
       out:
 	jFYI(0, ("lmLogClose: exit(%d)\n", rc));
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Tue Jul 16 16:49:42 2002
+++ b/fs/jfs/jfs_txnmgr.c	Tue Jul 16 16:49:43 2002
@@ -2989,7 +2989,7 @@
 	return 0;
 }
 
-#if CONFIG_PROC_FS
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_DEBUG)
 int jfs_txanchor_read(char *buffer, char **start, off_t offset, int length,
 		      int *eof, void *data)
 {
diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c
--- a/fs/jfs/super.c	Tue Jul 16 16:49:42 2002
+++ b/fs/jfs/super.c	Tue Jul 16 16:49:42 2002
@@ -68,7 +68,7 @@
 
 extern struct dentry *jfs_get_parent(struct dentry *dentry);
 
-#if defined(CONFIG_JFS_DEBUG) && defined(CONFIG_PROC_FS)
+#ifdef PROC_FS_JFS /* see jfs_debug.h */
 extern void jfs_proc_init(void);
 extern void jfs_proc_clean(void);
 #endif
@@ -318,9 +318,14 @@
 	if (!sbi->nls_tab)
 		sbi->nls_tab = load_nls_default();
 
+	/* logical blocks are represented by 40 bits in pxd_t, etc. */
 	sb->s_maxbytes = ((u64) sb->s_blocksize) << 40;
 #if BITS_PER_LONG == 32
-	sb->s_maxbytes = min((u64)PAGE_CACHE_SIZE << 32, sb->s_maxbytes);
+	/*
+	 * Page cache is indexed by long.
+	 * I would use MAX_LFS_FILESIZE, but it's only half as big
+	 */
+	sb->s_maxbytes = min(((u64)PAGE_CACHE_SIZE << 32) - 1, sb->s_maxbytes);
 #endif
 
 	return 0;
@@ -448,7 +453,7 @@
 	}
 	wait_for_completion(&jfsIOwait);	/* Wait until IO thread starts */
 
-#if defined(CONFIG_JFS_DEBUG) && defined(CONFIG_PROC_FS)
+#ifdef PROC_FS_JFS
 	jfs_proc_init();
 #endif
 
@@ -485,7 +490,7 @@
 	wait_for_completion(&jfsIOwait);	/* Wait until Commit thread exits */
 	wake_up(&jfs_sync_thread_wait);
 	wait_for_completion(&jfsIOwait);	/* Wait until Sync thread exits */
-#if defined(CONFIG_JFS_DEBUG) && defined(CONFIG_PROC_FS)
+#ifdef PROC_FS_JFS
 	jfs_proc_clean();
 #endif
 	unregister_filesystem(&jfs_fs_type);
diff -Nru a/fs/lockd/xdr.c b/fs/lockd/xdr.c
--- a/fs/lockd/xdr.c	Tue Jul 16 16:49:41 2002
+++ b/fs/lockd/xdr.c	Tue Jul 16 16:49:41 2002
@@ -561,11 +561,10 @@
 #define nlmclt_decode_norep	NULL
 
 #define PROC(proc, argtype, restype)	\
-    { "nlm_" #proc,						\
-      (kxdrproc_t) nlmclt_encode_##argtype,			\
-      (kxdrproc_t) nlmclt_decode_##restype,			\
-      MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2,		\
-      0								\
+    { .p_procname  = "nlm_" #proc,					\
+      .p_encode    = (kxdrproc_t) nlmclt_encode_##argtype,		\
+      .p_decode    = (kxdrproc_t) nlmclt_decode_##restype,		\
+      .p_bufsiz    = MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2	\
     }
 
 static struct rpc_procinfo	nlm_procedures[] = {
diff -Nru a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
--- a/fs/lockd/xdr4.c	Tue Jul 16 16:49:41 2002
+++ b/fs/lockd/xdr4.c	Tue Jul 16 16:49:41 2002
@@ -566,12 +566,11 @@
  */
 #define nlm4clt_decode_norep	NULL
 
-#define PROC(proc, argtype, restype)				\
-    { "nlm4_" #proc,						\
-      (kxdrproc_t) nlm4clt_encode_##argtype,			\
-      (kxdrproc_t) nlm4clt_decode_##restype,			\
-      MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2,	\
-      0								\
+#define PROC(proc, argtype, restype)					\
+    { .p_procname  = "nlm4_" #proc,					\
+      .p_encode    = (kxdrproc_t) nlm4clt_encode_##argtype,		\
+      .p_decode    = (kxdrproc_t) nlm4clt_decode_##restype,		\
+      .p_bufsiz    = MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2	\
     }
 
 static struct rpc_procinfo	nlm4_procedures[] = {
diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Tue Jul 16 16:49:43 2002
+++ b/fs/nfs/inode.c	Tue Jul 16 16:49:43 2002
@@ -1093,14 +1093,17 @@
  	}
  
 	/* Update attrtimeo value */
-	if (!invalid && time_after(jiffies, NFS_ATTRTIMEO_UPDATE(inode)+NFS_ATTRTIMEO(inode))) {
+	if (invalid) {
+		NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+		NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
+		invalidate_inode_pages(inode);
+		memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+	} else if (time_after(jiffies, NFS_ATTRTIMEO_UPDATE(inode)+NFS_ATTRTIMEO(inode))) {
 		if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
 			NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
 		NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 	}
 
-	if (invalid)
-		nfs_zap_caches(inode);
 	return 0;
  out_nochange:
 	if (new_atime - inode->i_atime > 0)
diff -Nru a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
--- a/fs/nfs/nfs2xdr.c	Tue Jul 16 16:49:42 2002
+++ b/fs/nfs/nfs2xdr.c	Tue Jul 16 16:49:42 2002
@@ -671,33 +671,32 @@
 # define MAX(a, b)	(((a) > (b))? (a) : (b))
 #endif
 
-#define PROC(proc, argtype, restype)	\
-    { "nfs_" #proc,					\
-      (kxdrproc_t) nfs_xdr_##argtype,			\
-      (kxdrproc_t) nfs_xdr_##restype,			\
-      MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2,	\
-      0							\
+#define PROC(proc, argtype, restype, timer)				\
+    { .p_procname =  "nfs_" #proc,					\
+      .p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,			\
+      .p_decode   =  (kxdrproc_t) nfs_xdr_##restype,			\
+      .p_bufsiz   =  MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2,	\
+      .p_timer    =  timer						\
     }
-
 static struct rpc_procinfo	nfs_procedures[18] = {
-    PROC(null,		enc_void,	dec_void),
-    PROC(getattr,	fhandle,	attrstat),
-    PROC(setattr,	sattrargs,	attrstat),
-    PROC(root,		enc_void,	dec_void),
-    PROC(lookup,	diropargs,	diropres),
-    PROC(readlink,	readlinkargs,	readlinkres),
-    PROC(read,		readargs,	readres),
-    PROC(writecache,	enc_void,	dec_void),
-    PROC(write,		writeargs,	writeres),
-    PROC(create,	createargs,	diropres),
-    PROC(remove,	diropargs,	stat),
-    PROC(rename,	renameargs,	stat),
-    PROC(link,		linkargs,	stat),
-    PROC(symlink,	symlinkargs,	stat),
-    PROC(mkdir,		createargs,	diropres),
-    PROC(rmdir,		diropargs,	stat),
-    PROC(readdir,	readdirargs,	readdirres),
-    PROC(statfs,	fhandle,	statfsres),
+    PROC(null,		enc_void,	dec_void, 0),
+    PROC(getattr,	fhandle,	attrstat, 1),
+    PROC(setattr,	sattrargs,	attrstat, 0),
+    PROC(root,		enc_void,	dec_void, 0),
+    PROC(lookup,	diropargs,	diropres, 2),
+    PROC(readlink,	readlinkargs,	readlinkres, 3),
+    PROC(read,		readargs,	readres, 3),
+    PROC(writecache,	enc_void,	dec_void, 0),
+    PROC(write,		writeargs,	writeres, 4),
+    PROC(create,	createargs,	diropres, 0),
+    PROC(remove,	diropargs,	stat, 0),
+    PROC(rename,	renameargs,	stat, 0),
+    PROC(link,		linkargs,	stat, 0),
+    PROC(symlink,	symlinkargs,	stat, 0),
+    PROC(mkdir,		createargs,	diropres, 0),
+    PROC(rmdir,		diropargs,	stat, 0),
+    PROC(readdir,	readdirargs,	readdirres, 3),
+    PROC(statfs,	fhandle,	statfsres, 0),
 };
 
 struct rpc_version		nfs_version2 = {
diff -Nru a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
--- a/fs/nfs/nfs3xdr.c	Tue Jul 16 16:49:43 2002
+++ b/fs/nfs/nfs3xdr.c	Tue Jul 16 16:49:43 2002
@@ -988,37 +988,37 @@
 # define MAX(a, b)	(((a) > (b))? (a) : (b))
 #endif
 
-#define PROC(proc, argtype, restype)				\
-    { "nfs3_" #proc,						\
-      (kxdrproc_t) nfs3_xdr_##argtype,				\
-      (kxdrproc_t) nfs3_xdr_##restype,				\
-      MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2,	\
-      0							\
+#define PROC(proc, argtype, restype, timer)				\
+    { .p_procname  = "nfs3_" #proc,					\
+      .p_encode    = (kxdrproc_t) nfs3_xdr_##argtype,			\
+      .p_decode    = (kxdrproc_t) nfs3_xdr_##restype,			\
+      .p_bufsiz    = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2,	\
+      .p_timer     = timer						\
     }
 
 static struct rpc_procinfo	nfs3_procedures[22] = {
-  PROC(null,		enc_void,	dec_void),
-  PROC(getattr,		fhandle,	attrstat),
-  PROC(setattr, 	sattrargs,	wccstat),
-  PROC(lookup,		diropargs,	lookupres),
-  PROC(access,		accessargs,	accessres),
-  PROC(readlink,	readlinkargs,	readlinkres),
-  PROC(read,		readargs,	readres),
-  PROC(write,		writeargs,	writeres),
-  PROC(create,		createargs,	createres),
-  PROC(mkdir,		mkdirargs,	createres),
-  PROC(symlink,		symlinkargs,	createres),
-  PROC(mknod,		mknodargs,	createres),
-  PROC(remove,		diropargs,	wccstat),
-  PROC(rmdir,		diropargs,	wccstat),
-  PROC(rename,		renameargs,	renameres),
-  PROC(link,		linkargs,	linkres),
-  PROC(readdir,		readdirargs,	readdirres),
-  PROC(readdirplus,	readdirargs,	readdirres),
-  PROC(fsstat,		fhandle,	fsstatres),
-  PROC(fsinfo,  	fhandle,	fsinfores),
-  PROC(pathconf,	fhandle,	pathconfres),
-  PROC(commit,		commitargs,	commitres),
+  PROC(null,		enc_void,	dec_void, 0),
+  PROC(getattr,		fhandle,	attrstat, 1),
+  PROC(setattr, 	sattrargs,	wccstat, 0),
+  PROC(lookup,		diropargs,	lookupres, 2),
+  PROC(access,		accessargs,	accessres, 1),
+  PROC(readlink,	readlinkargs,	readlinkres, 3),
+  PROC(read,		readargs,	readres, 3),
+  PROC(write,		writeargs,	writeres, 4),
+  PROC(create,		createargs,	createres, 0),
+  PROC(mkdir,		mkdirargs,	createres, 0),
+  PROC(symlink,		symlinkargs,	createres, 0),
+  PROC(mknod,		mknodargs,	createres, 0),
+  PROC(remove,		diropargs,	wccstat, 0),
+  PROC(rmdir,		diropargs,	wccstat, 0),
+  PROC(rename,		renameargs,	renameres, 0),
+  PROC(link,		linkargs,	linkres, 0),
+  PROC(readdir,		readdirargs,	readdirres, 3),
+  PROC(readdirplus,	readdirargs,	readdirres, 3),
+  PROC(fsstat,		fhandle,	fsstatres, 0),
+  PROC(fsinfo,  	fhandle,	fsinfores, 0),
+  PROC(pathconf,	fhandle,	pathconfres, 0),
+  PROC(commit,		commitargs,	commitres, 5),
 };
 
 struct rpc_version		nfs_version3 = {
diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
--- a/fs/ntfs/ChangeLog	Tue Jul 16 16:49:42 2002
+++ b/fs/ntfs/ChangeLog	Tue Jul 16 16:49:42 2002
@@ -1,32 +1,103 @@
 ToDo:
 	- Find and fix bugs.
-	- W.r.t. s_maxbytes still need to be careful on reading/truncating as
-	  there are dragons lurking in the details, e.g. read_inode() currently
-	  does no checks for file size wrt s_maxbytes. So what happens when a
-	  user open()s a file with i_size > s_maxbytes? Should read_inode()
-	  truncate the visible i_size? Will the user just get -E2BIG (or
-	  whatever) on open()? Or will (s)he be able to open() but lseek() and
-	  read() will fail when s_maxbytes is reached? -> Investigate this.
-	- Implement/allow non-resident index bitmaps in dir.c::ntfs_readdir()
-	  and then also consider initialized_size w.r.t. the bitmaps, etc.
-	- vcn_to_lcn() should somehow return the correct pointer within the
-	  ->run_list so we can get at the lcns for the following vcns, this is
-	  strictly a speed optimization. Obviously need to keep the ->run_list
-	  locked or RACE. load_attribute_list() already performs such an
-	  optimization so use the same optimization where desired.
-	- Consider if ntfs_file_read_compressed_block() shouldn't be coping
-	  with initialized_size < data_size. I don't think it can happen but
-	  it requires more careful consideration.
-	- CLEANUP: At the moment we have two copies of almost identical
-	  functions in aops.c, can merge them once fake inode address space
-	  based attribute i/o is further developed.
-	- CLEANUP: Modularising code in aops.c a bit, e.g. a-la get_block(),
-	  will be cleaner and make code reuse easier.
-	- Modify ntfs_read_locked_inode() to return an error code and update
-	  callers, i.e. ntfs_iget(), to pass that error code up instead of just
-	  using -EIO.
 	- Enable NFS exporting of NTFS.
-	- Use fake inodes for address space i/o.
+
+2.0.21 - Check for, and refuse to work with too large files/directories/volumes.
+
+	- Limit volume size at mount time to 2TiB on architectures where
+	  unsigned long is 32-bits (fs/ntfs/super.c::parse_ntfs_boot_sector()).
+	  This is the most we can do without overflowing the 32-bit limit of
+	  the block device size imposed on us by sb_bread() and sb_getblk()
+	  for the time being.
+	- Limit file/directory size at open() time to 16TiB on architectures
+	  where unsigned long is 32-bits (fs/ntfs/file.c::ntfs_file_open() and
+	  fs/ntfs/dir.c::ntfs_dir_open()). This is the most we can do without
+	  overflowing the page cache page index.
+
+2.0.20 - Support non-resident directory index bitmaps, fix page leak in readdir.
+
+	- Move the directory index bitmap to use an attribute inode instead of
+	  having special fields for it inside the ntfs inode structure. This
+	  means that the index bitmaps now use the page cache for i/o, too,
+	  and also as a side effect we get support for non-resident index
+	  bitmaps for free.
+	- Simplify/cleanup error handling in fs/ntfs/dir.c::ntfs_readdir() and
+	  fix a page leak that manifested itself in some cases.
+	- Add fs/ntfs/inode.c::ntfs_put_inode(), which we need to release the
+	  index bitmap inode on the final iput().
+
+2.0.19 - Fix race condition, improvements, and optimizations in i/o interface.
+
+	- Apply block optimization added to fs/ntfs/aops.c::ntfs_read_block()
+	  to fs/ntfs/compress.c::ntfs_file_read_compressed_block() as well.
+	- Drop the "file" from ntfs_file_read_compressed_block().
+	- Rename fs/ntfs/aops.c::ntfs_enb_buffer_read_async() to
+	  ntfs_end_buffer_async_read() (more like the fs/buffer.c counterpart).
+	- Update ntfs_end_buffer_async_read() with the improved logic from
+	  its updated counterpart fs/buffer.c::end_buffer_async_read(). Apply
+	  further logic improvements to better determine when we set PageError.
+	- Update submission of buffers in fs/ntfs/aops.c::ntfs_read_block() to
+	  check for the buffers being uptodate first in line with the updated
+	  fs/buffer.c::block_read_full_page(). This plugs a small race
+	  condition.
+
+2.0.18 - Fix race condition in reading of compressed files.
+
+	- There was a narrow window between checking a buffer head for being
+	  uptodate and locking it in ntfs_file_read_compressed_block(). We now
+	  lock the buffer and then check whether it is uptodate or not.
+
+2.0.17 - Cleanups and optimizations - shrinking the ToDo list.
+
+	- Modify fs/ntfs/inode.c::ntfs_read_locked_inode() to return an error
+	  code and update callers, i.e. ntfs_iget(), to pass that error code
+	  up instead of just using -EIO.
+	- Modifications to super.c to ensure that both mount and remount
+	  cannot set any write related options when the driver is compiled
+	  read-only.
+	- Optimize block resolution in fs/ntfs/aops.c::ntfs_read_block() to
+	  cache the current run list element. This should improve performance
+	  when reading very large and/or very fragmented data.
+
+2.0.16 - Convert access to $MFT/$BITMAP to attribute inode API.
+
+	- Fix a stupid bug introduced in 2.0.15 where we were unmapping the
+	  wrong inode in fs/ntfs/inode.c::ntfs_attr_iget().
+	- Fix debugging check in fs/ntfs/aops.c::ntfs_read_block().
+	- Convert $MFT/$BITMAP access to attribute inode API and remove all
+	  remnants of the ugly mftbmp address space and operations hack. This
+	  means we finally have only one readpage function as well as only one
+	  async io completion handler. Yey! The mft bitmap is now just an
+	  attribute inode and is accessed from vol->mftbmp_ino just as if it
+	  were a normal file. Fake inodes rule. (-:
+
+2.0.15 - Fake inodes based attribute i/o via the pagecache, fixes and cleanups.
+
+	- Fix silly bug in fs/ntfs/super.c::parse_options() which was causing
+	  remounts to fail when the partition had an entry in /etc/fstab and
+	  the entry specified the nls= option.
+	- Apply same macro magic used in fs/ntfs/inode.h to fs/ntfs/volume.h to
+	  expand all the helper functions NVolFoo(), NVolSetFoo(), and
+	  NVolClearFoo().
+	- Move copyright statement from driver initialisation message to
+	  module description (fs/super.c). This makes the initialisation
+	  message fit on one line and fits in better with rest of kernel.
+	- Update fs/ntfs/attrib.c::map_run_list() to work on both real and
+	  attribute inodes, and both for files and directories.
+	- Implement fake attribute inodes allowing all attribute i/o to go via
+	  the page cache and to use all the normal vfs/mm functionality:
+	  - Add ntfs_attr_iget() and its helper ntfs_read_locked_attr_inode()
+	    to fs/ntfs/inode.c.
+	  - Add needed cleanup code to ntfs_clear_big_inode().
+	- Merge address space operations for files and directories (aops.c),
+	  now just have ntfs_aops:
+	  - Rename:
+		end_buffer_read_attr_async() ->	ntfs_end_buffer_read_async(),
+		ntfs_attr_read_block()	     ->	ntfs_read_block(),
+		ntfs_file_read_page()	     ->	ntfs_readpage().
+	  - Rewrite fs/ntfs/aops.c::ntfs_readpage() to work on both real and
+	    attribute inodes, and both for files and directories.
+	  - Remove obsolete fs/ntfs/aops.c::ntfs_mst_readpage().
 
 2.0.14 - Run list merging code cleanup, minor locking changes, typo fixes.
 
diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile
--- a/fs/ntfs/Makefile	Tue Jul 16 16:49:41 2002
+++ b/fs/ntfs/Makefile	Tue Jul 16 16:49:41 2002
@@ -5,11 +5,15 @@
 ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
 	     mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.14\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.21\"
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
+
+#ifeq ($(CONFIG_NTFS_RW),y)
+#EXTRA_CFLAGS += -DNTFS_RW
+#endif
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/fs/ntfs/aops.c b/fs/ntfs/aops.c
--- a/fs/ntfs/aops.c	Tue Jul 16 16:49:43 2002
+++ b/fs/ntfs/aops.c	Tue Jul 16 16:49:43 2002
@@ -30,7 +30,7 @@
 #include "ntfs.h"
 
 /**
- * end_buffer_read_attr_async - async io completion for reading attributes
+ * ntfs_end_buffer_async_read - async io completion for reading attributes
  * @bh:		buffer head on which io is completed
  * @uptodate:	whether @bh is now uptodate or not
  *
@@ -45,26 +45,23 @@
  * record size, and index_block_size_bits, to the log(base 2) of the ntfs
  * record size.
  */
-static void end_buffer_read_attr_async(struct buffer_head *bh, int uptodate)
+static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
 {
 	static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED;
 	unsigned long flags;
 	struct buffer_head *tmp;
 	struct page *page;
 	ntfs_inode *ni;
-
-	if (likely(uptodate))
-		set_buffer_uptodate(bh);
-	else
-		clear_buffer_uptodate(bh);
+	int page_uptodate = 1;
 
 	page = bh->b_page;
-
 	ni = NTFS_I(page->mapping->host);
 
 	if (likely(uptodate)) {
 		s64 file_ofs;
 
+		set_buffer_uptodate(bh);
+
 		file_ofs = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
 		/* Check for the current buffer head overflowing. */
 		if (file_ofs + bh->b_size > ni->initialized_size) {
@@ -78,22 +75,28 @@
 			flush_dcache_page(page);
 			kunmap_atomic(addr, KM_BIO_SRC_IRQ);
 		}
-	} else
+	} else {
+		clear_buffer_uptodate(bh);
+		ntfs_error(ni->vol->sb, "Buffer I/O error, logical block %Lu.",
+				(unsigned long long)bh->b_blocknr);
 		SetPageError(page);
+	}
 
 	spin_lock_irqsave(&page_uptodate_lock, flags);
 	clear_buffer_async_read(bh);
 	unlock_buffer(bh);
-
-	tmp = bh->b_this_page;
-	while (tmp != bh) {
-		if (buffer_locked(tmp)) {
-			if (buffer_async_read(tmp))
+	tmp = bh;
+	do {
+		if (!buffer_uptodate(tmp))
+			page_uptodate = 0;
+		if (buffer_async_read(tmp)) {
+			if (likely(buffer_locked(tmp)))
 				goto still_busy;
-		} else if (!buffer_uptodate(tmp))
-			SetPageError(page);
+			/* Async buffers must be locked. */
+			BUG();
+		}
 		tmp = tmp->b_this_page;
-	}
+	} while (tmp != bh);
 	spin_unlock_irqrestore(&page_uptodate_lock, flags);
 	/*
 	 * If none of the buffers had errors then we can set the page uptodate,
@@ -101,7 +104,7 @@
 	 * attribute is mst protected, i.e. if NInoMstProteced(ni) is true.
 	 */
 	if (!NInoMstProtected(ni)) {
-		if (likely(!PageError(page)))
+		if (likely(page_uptodate && !PageError(page)))
 			SetPageUptodate(page);
 		unlock_page(page);
 		return;
@@ -127,12 +130,15 @@
 		}
 		flush_dcache_page(page);
 		kunmap_atomic(addr, KM_BIO_SRC_IRQ);
-		if (likely(!nr_err && recs))
-			SetPageUptodate(page);
-		else {
-			ntfs_error(ni->vol->sb, "Setting page error, index "
-					"0x%lx.", page->index);
-			SetPageError(page);
+		if (likely(!PageError(page))) {
+			if (likely(!nr_err && recs)) {
+				if (likely(page_uptodate))
+					SetPageUptodate(page);
+			} else {
+				ntfs_error(ni->vol->sb, "Setting page error, "
+						"index 0x%lx.", page->index);
+				SetPageError(page);
+			}
 		}
 	}
 	unlock_page(page);
@@ -143,12 +149,12 @@
 }
 
 /**
- * ntfs_attr_read_block - fill a @page of an address space with data
+ * ntfs_read_block - fill a @page of an address space with data
  * @page:	page cache page to fill with data
  *
  * Fill the page @page of the address space belonging to the @page->host inode.
  * We read each buffer asynchronously and when all buffers are read in, our io
- * completion handler end_buffer_read_attr_async(), if required, automatically
+ * completion handler ntfs_end_buffer_read_async(), if required, automatically
  * applies the mst fixups to the page before finally marking it uptodate and
  * unlocking it.
  *
@@ -156,12 +162,13 @@
  *
  * Contains an adapted version of fs/buffer.c::block_read_full_page().
  */
-static int ntfs_attr_read_block(struct page *page)
+static int ntfs_read_block(struct page *page)
 {
 	VCN vcn;
 	LCN lcn;
 	ntfs_inode *ni;
 	ntfs_volume *vol;
+	run_list_element *rl;
 	struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
 	sector_t iblock, lblock, zblock;
 	unsigned int blocksize, blocks, vcn_ofs;
@@ -186,12 +193,13 @@
 	zblock = (ni->initialized_size + blocksize - 1) >> blocksize_bits;
 
 #ifdef DEBUG
-	if (unlikely(!ni->run_list.rl && !ni->mft_no))
+	if (unlikely(!ni->run_list.rl && !ni->mft_no && !NInoAttr(ni)))
 		panic("NTFS: $MFT/$DATA run list has been unmapped! This is a "
 				"very serious bug! Cannot continue...");
 #endif
 
 	/* Loop through all the buffers in the page. */
+	rl = NULL;
 	nr = i = 0;
 	do {
 		if (unlikely(buffer_uptodate(bh)))
@@ -210,11 +218,18 @@
 					vol->cluster_size_bits;
 			vcn_ofs = ((VCN)iblock << blocksize_bits) &
 					vol->cluster_size_mask;
-retry_remap:
-			/* Convert the vcn to the corresponding lcn. */
-			down_read(&ni->run_list.lock);
-			lcn = vcn_to_lcn(ni->run_list.rl, vcn);
-			up_read(&ni->run_list.lock);
+			if (!rl) {
+lock_retry_remap:
+				down_read(&ni->run_list.lock);
+				rl = ni->run_list.rl;
+			}
+			if (likely(rl != NULL)) {
+				/* Seek to element containing target vcn. */
+				while (rl->length && rl[1].vcn <= vcn)
+					rl++;
+				lcn = vcn_to_lcn(rl, vcn);
+			} else
+				lcn = (LCN)LCN_RL_NOT_MAPPED;
 			/* Successful remap. */
 			if (lcn >= 0) {
 				/* Setup buffer head to correct block. */
@@ -235,8 +250,14 @@
 			/* If first try and run list unmapped, map and retry. */
 			if (!is_retry && lcn == LCN_RL_NOT_MAPPED) {
 				is_retry = TRUE;
+				/*
+				 * Attempt to map run list, dropping lock for
+				 * the duration.
+				 */
+				up_read(&ni->run_list.lock);
 				if (!map_run_list(ni, vcn))
-					goto retry_remap;
+					goto lock_retry_remap;
+				rl = NULL;
 			}
 			/* Hard error, zero out region. */
 			SetPageError(page);
@@ -261,18 +282,29 @@
 		set_buffer_uptodate(bh);
 	} while (i++, iblock++, (bh = bh->b_this_page) != head);
 
+	/* Release the lock if we took it. */
+	if (rl)
+		up_read(&ni->run_list.lock);
+
 	/* Check we have at least one buffer ready for i/o. */
 	if (nr) {
+		struct buffer_head *tbh;
+
 		/* Lock the buffers. */
 		for (i = 0; i < nr; i++) {
-			struct buffer_head *tbh = arr[i];
+			tbh = arr[i];
 			lock_buffer(tbh);
-			tbh->b_end_io = end_buffer_read_attr_async;
+			tbh->b_end_io = ntfs_end_buffer_async_read;
 			set_buffer_async_read(tbh);
 		}
 		/* Finally, start i/o on the buffers. */
-		for (i = 0; i < nr; i++)
-			submit_bh(READ, arr[i]);
+		for (i = 0; i < nr; i++) {
+			tbh = arr[i];
+			if (likely(!buffer_uptodate(tbh)))
+				submit_bh(READ, tbh);
+			else
+				ntfs_end_buffer_async_read(tbh, 1);
+		}
 		return 0;
 	}
 	/* No i/o was scheduled on any of the buffers. */
@@ -285,27 +317,27 @@
 }
 
 /**
- * ntfs_file_readpage - fill a @page of a @file with data from the device
+ * ntfs_readpage - fill a @page of a @file with data from the device
  * @file:	open file to which the page @page belongs or NULL
  * @page:	page cache page to fill with data
  *
- * For non-resident attributes, ntfs_file_readpage() fills the @page of the open
+ * For non-resident attributes, ntfs_readpage() fills the @page of the open
  * file @file by calling the ntfs version of the generic block_read_full_page()
- * function provided by the kernel, ntfs_attr_read_block(), which in turn
- * creates and reads in the buffers associated with the page asynchronously.
+ * function, ntfs_read_block(), which in turn creates and reads in the buffers
+ * associated with the page asynchronously.
  *
- * For resident attributes, OTOH, ntfs_file_readpage() fills @page by copying
- * the data from the mft record (which at this stage is most likely in memory)
- * and fills the remainder with zeroes. Thus, in this case, I/O is synchronous,
- * as even if the mft record is not cached at this point in time, we need to
- * wait for it to be read in before we can do the copy.
+ * For resident attributes, OTOH, ntfs_readpage() fills @page by copying the
+ * data from the mft record (which at this stage is most likely in memory) and
+ * fills the remainder with zeroes. Thus, in this case, I/O is synchronous, as
+ * even if the mft record is not cached at this point in time, we need to wait
+ * for it to be read in before we can do the copy.
  *
- * Return 0 on success or -errno on error.
+ * Return 0 on success and -errno on error.
  */
-static int ntfs_file_readpage(struct file *file, struct page *page)
+int ntfs_readpage(struct file *file, struct page *page)
 {
 	s64 attr_pos;
-	ntfs_inode *ni;
+	ntfs_inode *ni, *base_ni;
 	char *addr;
 	attr_search_context *ctx;
 	MFT_RECORD *mrec;
@@ -317,40 +349,45 @@
 
 	ni = NTFS_I(page->mapping->host);
 
-	/* Is the unnamed $DATA attribute resident? */
 	if (NInoNonResident(ni)) {
-		/* Attribute is not resident. */
-
-		/* If the file is encrypted, we deny access, just like NT4. */
-		if (NInoEncrypted(ni)) {
-			err = -EACCES;
-			goto unl_err_out;
+		/*
+		 * Only unnamed $DATA attributes can be compressed or
+		 * encrypted.
+		 */
+		if (ni->type == AT_DATA && !ni->name_len) {
+			/* If file is encrypted, deny access, just like NT4. */
+			if (NInoEncrypted(ni)) {
+				err = -EACCES;
+				goto err_out;
+			}
+			/* Compressed data streams are handled in compress.c. */
+			if (NInoCompressed(ni))
+				return ntfs_read_compressed_block(page);
 		}
-		/* Compressed data stream. Handled in compress.c. */
-		if (NInoCompressed(ni))
-			return ntfs_file_read_compressed_block(page);
 		/* Normal data stream. */
-		return ntfs_attr_read_block(page);
+		return ntfs_read_block(page);
 	}
 	/* Attribute is resident, implying it is not compressed or encrypted. */
+	if (!NInoAttr(ni))
+		base_ni = ni;
+	else
+		base_ni = ni->_INE(base_ntfs_ino);
 
 	/* Map, pin and lock the mft record for reading. */
-	mrec = map_mft_record(READ, ni);
+	mrec = map_mft_record(READ, base_ni);
 	if (unlikely(IS_ERR(mrec))) {
 		err = PTR_ERR(mrec);
-		goto unl_err_out;
+		goto err_out;
 	}
-
-	ctx = get_attr_search_ctx(ni, mrec);
+	ctx = get_attr_search_ctx(base_ni, mrec);
 	if (unlikely(!ctx)) {
 		err = -ENOMEM;
-		goto unm_unl_err_out;
+		goto unm_err_out;
 	}
-
-	/* Find the data attribute in the mft record. */
-	if (unlikely(!lookup_attr(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx))) {
+	if (unlikely(!lookup_attr(ni->type, ni->name, ni->name_len,
+			IGNORE_CASE, 0, NULL, 0, ctx))) {
 		err = -ENOENT;
-		goto put_unm_unl_err_out;
+		goto put_unm_err_out;
 	}
 
 	/* Starting position of the page within the attribute value. */
@@ -377,253 +414,21 @@
 	kunmap(page);
 
 	SetPageUptodate(page);
-put_unm_unl_err_out:
+put_unm_err_out:
 	put_attr_search_ctx(ctx);
-unm_unl_err_out:
-	unmap_mft_record(READ, ni);
-unl_err_out:
+unm_err_out:
+	unmap_mft_record(READ, base_ni);
+err_out:
 	unlock_page(page);
 	return err;
 }
 
 /**
- * ntfs_mst_readpage - fill a @page of the mft or a directory with data
- * @file:	open file/directory to which the @page belongs or NULL
- * @page:	page cache page to fill with data
- *
- * Readpage method for the VFS address space operations of directory inodes
- * and the $MFT/$DATA attribute.
- *
- * We just call ntfs_attr_read_block() here, in fact we only need this wrapper
- * because of the difference in function parameters.
- */
-int ntfs_mst_readpage(struct file *file, struct page *page)
-{
-	if (unlikely(!PageLocked(page)))
-		PAGE_BUG(page);
-
-	return ntfs_attr_read_block(page);
-}
-
-/**
- * end_buffer_read_mftbmp_async -
- *
- * Async io completion handler for accessing mft bitmap. Adapted from
- * end_buffer_read_mst_async().
- */
-static void end_buffer_read_mftbmp_async(struct buffer_head *bh, int uptodate)
-{
-	static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED;
-	unsigned long flags;
-	struct buffer_head *tmp;
-	struct page *page;
-
-	if (likely(uptodate))
-		set_buffer_uptodate(bh);
-	else
-		clear_buffer_uptodate(bh);
-
-	page = bh->b_page;
-
-	if (likely(uptodate)) {
-		s64 file_ofs;
-
-		/* Host is the ntfs volume. Our mft bitmap access kludge... */
-		ntfs_volume *vol = (ntfs_volume*)page->mapping->host;
-
-		file_ofs = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
-		if (file_ofs + bh->b_size > vol->mftbmp_initialized_size) {
-			char *addr;
-			int ofs = 0;
-
-			if (file_ofs < vol->mftbmp_initialized_size)
-				ofs = vol->mftbmp_initialized_size - file_ofs;
-			addr = kmap_atomic(page, KM_BIO_SRC_IRQ);
-			memset(addr + bh_offset(bh) + ofs, 0, bh->b_size - ofs);
-			flush_dcache_page(page);
-			kunmap_atomic(addr, KM_BIO_SRC_IRQ);
-		}
-	} else
-		SetPageError(page);
-
-	spin_lock_irqsave(&page_uptodate_lock, flags);
-	clear_buffer_async_read(bh);
-	unlock_buffer(bh);
-
-	tmp = bh->b_this_page;
-	while (tmp != bh) {
-		if (buffer_locked(tmp)) {
-			if (buffer_async_read(tmp))
-				goto still_busy;
-		} else if (!buffer_uptodate(tmp))
-			SetPageError(page);
-		tmp = tmp->b_this_page;
-	}
-
-	spin_unlock_irqrestore(&page_uptodate_lock, flags);
-	if (likely(!PageError(page)))
-		SetPageUptodate(page);
-	unlock_page(page);
-	return;
-still_busy:
-	spin_unlock_irqrestore(&page_uptodate_lock, flags);
-	return;
-}
-
-/**
- * ntfs_mftbmp_readpage -
- *
- * Readpage for accessing mft bitmap. Adapted from ntfs_mst_readpage().
- */
-static int ntfs_mftbmp_readpage(ntfs_volume *vol, struct page *page)
-{
-	VCN vcn;
-	LCN lcn;
-	struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
-	sector_t iblock, lblock, zblock;
-	unsigned int blocksize, blocks, vcn_ofs;
-	int nr, i;
-	unsigned char blocksize_bits;
-
-	if (unlikely(!PageLocked(page)))
-		PAGE_BUG(page);
-
-	blocksize = vol->sb->s_blocksize;
-	blocksize_bits = vol->sb->s_blocksize_bits;
-
-	if (!page_has_buffers(page))
-		create_empty_buffers(page, blocksize, 0);
-	bh = head = page_buffers(page);
-	if (unlikely(!bh))
-		return -ENOMEM;
-
-	blocks = PAGE_CACHE_SIZE >> blocksize_bits;
-	iblock = page->index << (PAGE_CACHE_SHIFT - blocksize_bits);
-	lblock = (vol->mftbmp_allocated_size + blocksize - 1) >> blocksize_bits;
-	zblock = (vol->mftbmp_initialized_size + blocksize - 1) >>
-			blocksize_bits;
-
-	/* Loop through all the buffers in the page. */
-	nr = i = 0;
-	do {
-		if (unlikely(buffer_uptodate(bh)))
-			continue;
-		if (unlikely(buffer_mapped(bh))) {
-			arr[nr++] = bh;
-			continue;
-		}
-		bh->b_bdev = vol->sb->s_bdev;
-		/* Is the block within the allowed limits? */
-		if (iblock < lblock) {
-			/* Convert iblock into corresponding vcn and offset. */
-			vcn = (VCN)iblock << blocksize_bits >>
-					vol->cluster_size_bits;
-			vcn_ofs = ((VCN)iblock << blocksize_bits) &
-					vol->cluster_size_mask;
-			/* Convert the vcn to the corresponding lcn. */
-			down_read(&vol->mftbmp_rl.lock);
-			lcn = vcn_to_lcn(vol->mftbmp_rl.rl, vcn);
-			up_read(&vol->mftbmp_rl.lock);
-			/* Successful remap. */
-			if (lcn >= 0) {
-				/* Setup buffer head to correct block. */
-				bh->b_blocknr = ((lcn << vol->cluster_size_bits)
-						+ vcn_ofs) >> blocksize_bits;
-				set_buffer_mapped(bh);
-				/* Only read initialized data blocks. */
-				if (iblock < zblock) {
-					arr[nr++] = bh;
-					continue;
-				}
-				/* Fully non-initialized data block, zero it. */
-				goto handle_zblock;
-			}
-			if (lcn != LCN_HOLE) {
-				/* Hard error, zero out region. */
-				SetPageError(page);
-				ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%Lx) "
-						"failed with error code "
-						"0x%Lx.", (long long)vcn,
-						(long long)-lcn);
-				// FIXME: Depending on vol->on_errors, do
-				// something.
-			}
-		}
-		/*
-		 * Either iblock was outside lblock limits or vcn_to_lcn()
-		 * returned error. Just zero that portion of the page and set
-		 * the buffer uptodate.
-		 */
-		bh->b_blocknr = -1UL;
-		clear_buffer_mapped(bh);
-handle_zblock:
-		memset(kmap(page) + i * blocksize, 0, blocksize);
-		flush_dcache_page(page);
-		kunmap(page);
-		set_buffer_uptodate(bh);
-	} while (i++, iblock++, (bh = bh->b_this_page) != head);
-
-	/* Check we have at least one buffer ready for i/o. */
-	if (nr) {
-		/* Lock the buffers. */
-		for (i = 0; i < nr; i++) {
-			struct buffer_head *tbh = arr[i];
-			lock_buffer(tbh);
-			tbh->b_end_io = end_buffer_read_mftbmp_async;
-			set_buffer_async_read(tbh);
-		}
-		/* Finally, start i/o on the buffers. */
-		for (i = 0; i < nr; i++)
-			submit_bh(READ, arr[i]);
-		return 0;
-	}
-	/* No i/o was scheduled on any of the buffers. */
-	if (likely(!PageError(page)))
-		SetPageUptodate(page);
-	else /* Signal synchronous i/o error. */
-		nr = -EIO;
-	unlock_page(page);
-	return nr;
-}
-
-/**
- * ntfs_file_aops - address space operations for accessing normal file data
- */
-struct address_space_operations ntfs_file_aops = {
-	writepage:	NULL,			/* Write dirty page to disk. */
-	readpage:	ntfs_file_readpage,	/* Fill page with data. */
-	sync_page:	block_sync_page,	/* Currently, just unplugs the
-						   disk request queue. */
-	prepare_write:	NULL,			/* . */
-	commit_write:	NULL,			/* . */
-};
-
-typedef int readpage_t(struct file *, struct page *);
-
-/**
- * ntfs_mftbmp_aops - address space operations for accessing mftbmp
- */
-struct address_space_operations ntfs_mftbmp_aops = {
-	writepage:	NULL,			/* Write dirty page to disk. */
-	readpage:	(readpage_t*)ntfs_mftbmp_readpage, /* Fill page with
-							      data. */
-	sync_page:	block_sync_page,	/* Currently, just unplugs the
-						   disk request queue. */
-	prepare_write:	NULL,			/* . */
-	commit_write:	NULL,			/* . */
-};
-
-/**
- * ntfs_dir_aops -
- *
- * Address space operations for accessing normal directory data (i.e. index
- * allocation attribute). We can't just use the same operations as for files
- * because 1) the attribute is different and even more importantly 2) the index
- * records have to be multi sector transfer deprotected (i.e. fixed-up).
+ * ntfs_aops - general address space operations for inodes and attributes
  */
-struct address_space_operations ntfs_dir_aops = {
+struct address_space_operations ntfs_aops = {
 	writepage:	NULL,			/* Write dirty page to disk. */
-	readpage:	ntfs_mst_readpage,	/* Fill page with data. */
+	readpage:	ntfs_readpage,		/* Fill page with data. */
 	sync_page:	block_sync_page,	/* Currently, just unplugs the
 						   disk request queue. */
 	prepare_write:	NULL,			/* . */
diff -Nru a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
--- a/fs/ntfs/attrib.c	Tue Jul 16 16:49:42 2002
+++ b/fs/ntfs/attrib.c	Tue Jul 16 16:49:42 2002
@@ -935,78 +935,51 @@
  */
 int map_run_list(ntfs_inode *ni, VCN vcn)
 {
+	ntfs_inode *base_ni;
 	attr_search_context *ctx;
 	MFT_RECORD *mrec;
-	const uchar_t *name;
-	u32 name_len;
-	ATTR_TYPES at;
 	int err = 0;
 	
 	ntfs_debug("Mapping run list part containing vcn 0x%Lx.",
 			(long long)vcn);
 
-	/* Map, pin and lock the mft record for reading. */
-	mrec = map_mft_record(READ, ni);
+	if (!NInoAttr(ni))
+		base_ni = ni;
+	else
+		base_ni = ni->_INE(base_ntfs_ino);
+
+	mrec = map_mft_record(READ, base_ni);
 	if (IS_ERR(mrec))
 		return PTR_ERR(mrec);
-
-	ctx = get_attr_search_ctx(ni, mrec);
+	ctx = get_attr_search_ctx(base_ni, mrec);
 	if (!ctx) {
 		err = -ENOMEM;
-		goto unm_err_out;
-	}
-
-	/* The attribute type is determined from the inode type. */
-	if (S_ISDIR(VFS_I(ni)->i_mode)) {
-		at = AT_INDEX_ALLOCATION;
-		name = I30;
-		name_len = 4;
-	} else {
-		at = AT_DATA;
-		name = NULL;
-		name_len = 0;
+		goto err_out;
 	}
-
-	/* Find the attribute in the mft record. */
-	if (!lookup_attr(at, name, name_len, CASE_SENSITIVE, vcn, NULL, 0,
-			ctx)) {
+	if (!lookup_attr(ni->type, ni->name, ni->name_len, IGNORE_CASE, vcn,
+			NULL, 0, ctx)) {
 		put_attr_search_ctx(ctx);
 		err = -ENOENT;
-		goto unm_err_out;
+		goto err_out;
 	}
 
-	/* Lock the run list. */
 	down_write(&ni->run_list.lock);
-
-	/* Make sure someone else didn't do the work while we were spinning. */
+	/* Make sure someone else didn't do the work while we were sleeping. */
 	if (likely(vcn_to_lcn(ni->run_list.rl, vcn) <= LCN_RL_NOT_MAPPED)) {
 		run_list_element *rl;
 
-		/* Decode the run list. */
 		rl = decompress_mapping_pairs(ni->vol, ctx->attr,
 				ni->run_list.rl);
-
-		/* Flag any errors or set the run list if successful. */
 		if (unlikely(IS_ERR(rl)))
 			err = PTR_ERR(rl);
 		else
 			ni->run_list.rl = rl;
 	}
-
-	/* Unlock the run list. */
 	up_write(&ni->run_list.lock);
 	
 	put_attr_search_ctx(ctx);
-
-	/* Unlock, unpin and release the mft record. */
-	unmap_mft_record(READ, ni);
-
-	/* If an error occured, return it. */
-	ntfs_debug("Done.");
-	return err;
-
-unm_err_out:
-	unmap_mft_record(READ, ni);
+err_out:
+	unmap_mft_record(READ, base_ni);
 	return err;
 }
 
diff -Nru a/fs/ntfs/compress.c b/fs/ntfs/compress.c
--- a/fs/ntfs/compress.c	Tue Jul 16 16:49:42 2002
+++ b/fs/ntfs/compress.c	Tue Jul 16 16:49:42 2002
@@ -157,7 +157,7 @@
 
 	/* Default error code. */
 	int err = -EOVERFLOW;
-	
+
 	ntfs_debug("Entering, cb_size = 0x%x.", cb_size);
 do_next_sb:
 	ntfs_debug("Beginning sub-block at offset = 0x%x in the cb.",
@@ -193,7 +193,7 @@
 	/* Setup offsets for the current sub-block destination. */
 	do_sb_start = *dest_ofs;
 	do_sb_end = do_sb_start + NTFS_SB_SIZE;
-	
+
 	/* Check that we are still within allowed boundaries. */
 	if (*dest_index == dest_max_index && do_sb_end > dest_max_ofs)
 		goto return_overflow;
@@ -386,7 +386,7 @@
 }
 
 /**
- * ntfs_file_read_compressed_block - read a compressed block into the page cache
+ * ntfs_read_compressed_block - read a compressed block into the page cache
  * @page:	locked page in the compression block(s) we need to read
  *
  * When we are called the page has already been verified to be locked and the
@@ -418,14 +418,15 @@
  * initialized_size is less than data_size. This should be safe because of the
  * nature of the compression algorithm used. Just in case we check and output
  * an error message in read inode if the two sizes are not equal for a
- * compressed file.
+ * compressed file. (AIA)
  */
-int ntfs_file_read_compressed_block(struct page *page)
+int ntfs_read_compressed_block(struct page *page)
 {
 	struct address_space *mapping = page->mapping;
 	ntfs_inode *ni = NTFS_I(mapping->host);
 	ntfs_volume *vol = ni->vol;
 	struct super_block *sb = vol->sb;
+	run_list_element *rl;
 	unsigned long block_size = sb->s_blocksize;
 	unsigned char block_size_bits = sb->s_blocksize_bits;
 	u8 *cb, *cb_pos, *cb_end;
@@ -462,6 +463,11 @@
 
 	ntfs_debug("Entering, page->index = 0x%lx, cb_size = 0x%x, nr_pages = "
 			"%i.", index, cb_size, nr_pages);
+	/*
+	 * Bad things happen if we get here for anything that is not an
+	 * unnamed $DATA attribute.
+	 */
+	BUG_ON(ni->type != AT_DATA || ni->name_len);
 
 	pages = kmalloc(nr_pages * sizeof(struct page *), GFP_NOFS);
 
@@ -527,14 +533,23 @@
 	nr_bhs = 0;
 
 	/* Read all cb buffer heads one cluster at a time. */
+	rl = NULL;
 	for (vcn = start_vcn, start_vcn += cb_clusters; vcn < start_vcn;
 			vcn++) {
 		BOOL is_retry = FALSE;
-retry_remap:
-		/* Find lcn of vcn and convert it into blocks. */
-		down_read(&ni->run_list.lock);
-		lcn = vcn_to_lcn(ni->run_list.rl, vcn);
-		up_read(&ni->run_list.lock);
+
+		if (!rl) {
+lock_retry_remap:
+			down_read(&ni->run_list.lock);
+			rl = ni->run_list.rl;
+		}
+		if (likely(rl != NULL)) {
+			/* Seek to element containing target vcn. */
+			while (rl->length && rl[1].vcn <= vcn)
+				rl++;
+			lcn = vcn_to_lcn(rl, vcn);
+		} else
+			lcn = (LCN)LCN_RL_NOT_MAPPED;
 		ntfs_debug("Reading vcn = 0x%Lx, lcn = 0x%Lx.",
 				(long long)vcn, (long long)lcn);
 		if (lcn < 0) {
@@ -547,9 +562,13 @@
 			if (is_retry || lcn != LCN_RL_NOT_MAPPED)
 				goto rl_err;
 			is_retry = TRUE;
-			/* Map run list of current extent and retry. */
+			/*
+			 * Attempt to map run list, dropping lock for the
+			 * duration.
+			 */
+			up_read(&ni->run_list.lock);
 			if (!map_run_list(ni, vcn))
-				goto retry_remap;
+				goto lock_retry_remap;
 			goto map_rl_err;
 		}
 		block = lcn << vol->cluster_size_bits >> block_size_bits;
@@ -563,15 +582,21 @@
 		} while (++block < max_block);
 	}
 
+	/* Release the lock if we took it. */
+	if (rl)
+		up_read(&ni->run_list.lock);
+
 	/* Setup and initiate io on all buffer heads. */
 	for (i = 0; i < nr_bhs; i++) {
 		struct buffer_head *tbh = bhs[i];
 
-		if (buffer_uptodate(tbh))
+		if (unlikely(test_set_buffer_locked(tbh)))
 			continue;
-
-		lock_buffer(tbh);
-		get_bh(tbh);
+		if (unlikely(buffer_uptodate(tbh))) {
+			unlock_buffer(tbh);
+			continue;
+		}
+		atomic_inc(&tbh->b_count);
 		tbh->b_end_io = end_buffer_io_sync;
 		submit_bh(READ, tbh);
 	}
@@ -582,9 +607,8 @@
 
 		if (buffer_uptodate(tbh))
 			continue;
-
 		wait_on_buffer(tbh);
-		if (!buffer_uptodate(tbh))
+		if (unlikely(!buffer_uptodate(tbh)))
 			goto read_err;
 	}
 
@@ -822,11 +846,13 @@
 	goto err_out;
 
 rl_err:
+	up_read(&ni->run_list.lock);
 	ntfs_error(vol->sb, "vcn_to_lcn() failed. Cannot read compression "
 			"block.");
 	goto err_out;
 
 getblk_err:
+	up_read(&ni->run_list.lock);
 	ntfs_error(vol->sb, "getblk() failed. Cannot read compression block.");
 
 err_out:
diff -Nru a/fs/ntfs/dir.c b/fs/ntfs/dir.c
--- a/fs/ntfs/dir.c	Tue Jul 16 16:49:42 2002
+++ b/fs/ntfs/dir.c	Tue Jul 16 16:49:42 2002
@@ -2,7 +2,7 @@
  * dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project.
  *
  * Copyright (c) 2001,2002 Anton Altaparmakov.
- * Copyright (C) 2002 Richard Russon.
+ * Copyright (c) 2002 Richard Russon.
  *
  * This program/include file is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as published
@@ -1052,8 +1052,8 @@
  */
 static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
-	s64 ia_pos, ia_start, prev_ia_pos;
-	struct inode *vdir = filp->f_dentry->d_inode;
+	s64 ia_pos, ia_start, prev_ia_pos, bmp_pos;
+	struct inode *bmp_vi, *vdir = filp->f_dentry->d_inode;
 	struct super_block *sb = vdir->i_sb;
 	ntfs_inode *ndir = NTFS_I(vdir);
 	ntfs_volume *vol = NTFS_SB(sb);
@@ -1061,10 +1061,10 @@
 	INDEX_ROOT *ir;
 	INDEX_ENTRY *ie;
 	INDEX_ALLOCATION *ia;
-	u8 *name;
-	int rc, err, ir_pos, bmp_pos;
-	struct address_space *ia_mapping;
-	struct page *page;
+	u8 *name = NULL;
+	int rc, err, ir_pos, cur_bmp_pos;
+	struct address_space *ia_mapping, *bmp_mapping;
+	struct page *bmp_page = NULL, *ia_page = NULL;
 	u8 *kaddr, *bmp, *index_end;
 	attr_search_context *ctx;
 
@@ -1093,17 +1093,20 @@
 			goto done;
 		filp->f_pos++;
 	}
+
 	/* Get hold of the mft record for the directory. */
 	m = map_mft_record(READ, ndir);
-	if (IS_ERR(m)) {
+	if (unlikely(IS_ERR(m))) {
 		err = PTR_ERR(m);
+		m = NULL;
+		ctx = NULL;
 		goto err_out;
 	}
 
 	ctx = get_attr_search_ctx(ndir, m);
-	if (!ctx) {
+	if (unlikely(!ctx)) {
 		err = -ENOMEM;
-		goto unm_err_out;
+		goto err_out;
 	}
 
 	/*
@@ -1112,9 +1115,9 @@
 	 */
 	name = (u8*)kmalloc(NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1,
 			GFP_NOFS);
-	if (!name) {
+	if (unlikely(!name)) {
 		err = -ENOMEM;
-		goto put_unm_err_out;
+		goto err_out;
 	}
 	/* Are we jumping straight into the index allocation attribute? */
 	if (filp->f_pos >= vol->mft_record_size)
@@ -1122,12 +1125,11 @@
 	/* Get the offset into the index root attribute. */
 	ir_pos = (s64)filp->f_pos;
 	/* Find the index root attribute in the mft record. */
-	if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
-			ctx)) {
+	if (unlikely(!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0,
+			NULL, 0, ctx))) {
 		ntfs_error(sb, "Index root attribute missing in directory "
 				"inode 0x%lx.", vdir->i_ino);
-		err = -EIO;
-		goto kf_unm_err_out;
+		goto err_out;
 	}
 	/* Get to the index root value (it's been verified in read_inode). */
 	ir = (INDEX_ROOT*)((u8*)ctx->attr +
@@ -1144,11 +1146,11 @@
 	for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->_IEH(length)))) {
 		ntfs_debug("In index root, offset 0x%x.", (u8*)ie - (u8*)ir);
 		/* Bounds checks. */
-		if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
+		if (unlikely((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
 				sizeof(INDEX_ENTRY_HEADER) > index_end ||
 				(u8*)ie + le16_to_cpu(ie->_IEH(key_length)) >
-				index_end)
-			goto dir_err_out;
+				index_end))
+			goto err_out;
 		/* The last entry cannot contain a name. */
 		if (ie->_IEH(flags) & INDEX_ENTRY_END)
 			break;
@@ -1166,80 +1168,99 @@
 		goto EOD;
 	/* Advance f_pos to the beginning of the index allocation. */
 	filp->f_pos = vol->mft_record_size;
-	/* Reinitialize the search context. */
-	reinit_attr_search_ctx(ctx);
 skip_index_root:
-	if (NInoBmpNonResident(ndir)) {
-		/*
-		 * Read the page of the bitmap that contains the current index
-		 * block.
-		 */
-		// TODO: FIXME: Implement this!
-		ntfs_error(sb, "Index bitmap is non-resident, which is not "
-				"supported yet. Pretending that end of "
-				"directory has been reached.\n");
-		goto EOD;
-	} else {
-		/* Find the index bitmap attribute in the mft record. */
-		if (!lookup_attr(AT_BITMAP, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
-				ctx)) {
-			ntfs_error(sb, "Index bitmap attribute missing in "
-					"directory inode 0x%lx.", vdir->i_ino);
-			err = -EIO;
-			goto kf_unm_err_out;
-		}
-		bmp = (u8*)ctx->attr +
-				le16_to_cpu(ctx->attr->_ARA(value_offset));
-	}
+	kaddr = NULL;
+	prev_ia_pos = -1LL;
 	/* Get the offset into the index allocation attribute. */
 	ia_pos = (s64)filp->f_pos - vol->mft_record_size;
 	ia_mapping = vdir->i_mapping;
-	/* If the index block is not in use find the next one that is. */
+	bmp_vi = ndir->_IDM(bmp_ino);
+	if (unlikely(!bmp_vi)) {
+		ntfs_debug("Inode %lu, regetting index bitmap.", vdir->i_ino);
+		bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4);
+		if (unlikely(IS_ERR(bmp_vi))) {
+			ntfs_error(sb, "Failed to get bitmap attribute.");
+			err = PTR_ERR(bmp_vi);
+			goto err_out;
+		}
+		ndir->_IDM(bmp_ino) = bmp_vi;
+	}
+	bmp_mapping = bmp_vi->i_mapping;
+	/* Get the starting bitmap bit position and sanity check it. */
 	bmp_pos = ia_pos >> ndir->_IDM(index_block_size_bits);
-	page = NULL;
-	kaddr = NULL;
-	prev_ia_pos = -1LL;
-	if (bmp_pos >> 3 >= ndir->_IDM(bmp_size)) {
+	if (unlikely(bmp_pos >> 3 >= bmp_vi->i_size)) {
 		ntfs_error(sb, "Current index allocation position exceeds "
 				"index bitmap size.");
-		goto kf_unm_err_out;
+		goto err_out;
+	}
+	/* Get the starting bit position in the current bitmap page. */
+	cur_bmp_pos = bmp_pos & ((PAGE_CACHE_SIZE * 8) - 1);
+	bmp_pos &= ~((PAGE_CACHE_SIZE * 8) - 1);
+get_next_bmp_page:
+	ntfs_debug("Reading bitmap with page index 0x%Lx, bit ofs 0x%Lx",
+			(long long)bmp_pos >> (3 + PAGE_CACHE_SHIFT),
+			(long long)bmp_pos & ((PAGE_CACHE_SIZE * 8) - 1));
+	bmp_page = ntfs_map_page(bmp_mapping,
+			bmp_pos >> (3 + PAGE_CACHE_SHIFT));
+	if (unlikely(IS_ERR(bmp_page))) {
+		ntfs_error(sb, "Reading index bitmap failed.");
+		err = PTR_ERR(bmp_page);
+		bmp_page = NULL;
+		goto err_out;
 	}
-	while (!(bmp[bmp_pos >> 3] & (1 << (bmp_pos & 7)))) {
+	bmp = (u8*)page_address(bmp_page);
+	/* Find next index block in use. */
+	while (!(bmp[cur_bmp_pos >> 3] & (1 << (cur_bmp_pos & 7)))) {
 find_next_index_buffer:
-		bmp_pos++;
+		cur_bmp_pos++;
+		/*
+		 * If we have reached the end of the bitmap page, get the next
+		 * page, and put away the old one.
+		 */
+		if (unlikely((cur_bmp_pos >> 3) >= PAGE_CACHE_SIZE)) {
+			ntfs_unmap_page(bmp_page);
+			bmp_pos += PAGE_CACHE_SIZE * 8;
+			cur_bmp_pos = 0;
+			goto get_next_bmp_page;
+		}
 		/* If we have reached the end of the bitmap, we are done. */
-		if (bmp_pos >> 3 >= ndir->_IDM(bmp_size))
-			goto EOD;
-		ia_pos = (s64)bmp_pos << ndir->_IDM(index_block_size_bits);
+		if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= vdir->i_size))
+			goto unm_EOD;
+		ia_pos = (bmp_pos + cur_bmp_pos) <<
+				ndir->_IDM(index_block_size_bits);
 	}
-	ntfs_debug("Handling index buffer 0x%x.", bmp_pos);
+	ntfs_debug("Handling index buffer 0x%Lx.",
+			(long long)bmp_pos + cur_bmp_pos);
 	/* If the current index buffer is in the same page we reuse the page. */
 	if ((prev_ia_pos & PAGE_CACHE_MASK) != (ia_pos & PAGE_CACHE_MASK)) {
 		prev_ia_pos = ia_pos;
-		if (page)
-			ntfs_unmap_page(page);
+		if (likely(ia_page != NULL))
+			ntfs_unmap_page(ia_page);
 		/*
 		 * Map the page cache page containing the current ia_pos,
 		 * reading it from disk if necessary.
 		 */
-		page = ntfs_map_page(ia_mapping, ia_pos >> PAGE_CACHE_SHIFT);
-		if (IS_ERR(page))
-			goto map_page_err_out;
-		kaddr = (u8*)page_address(page);
+		ia_page = ntfs_map_page(ia_mapping, ia_pos >> PAGE_CACHE_SHIFT);
+		if (unlikely(IS_ERR(ia_page))) {
+			ntfs_error(sb, "Reading index allocation data failed.");
+			err = PTR_ERR(ia_page);
+			ia_page = NULL;
+			goto err_out;
+		}
+		kaddr = (u8*)page_address(ia_page);
 	}
 	/* Get the current index buffer. */
 	ia = (INDEX_ALLOCATION*)(kaddr + (ia_pos & ~PAGE_CACHE_MASK &
 			~(s64)(ndir->_IDM(index_block_size) - 1)));
 	/* Bounds checks. */
-	if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) {
+	if (unlikely((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE)) {
 		ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
 				"inode 0x%lx or driver bug.", vdir->i_ino);
-		err = -EIO;
-		goto unm_dir_err_out;
+		goto err_out;
 	}
-	if (sle64_to_cpu(ia->index_block_vcn) != (ia_pos &
+	if (unlikely(sle64_to_cpu(ia->index_block_vcn) != (ia_pos &
 			~(s64)(ndir->_IDM(index_block_size) - 1)) >>
-			ndir->_IDM(index_vcn_size_bits)) {
+			ndir->_IDM(index_vcn_size_bits))) {
 		ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
 				"different from expected VCN (0x%Lx). "
 				"Directory inode 0x%lx is corrupt or driver "
@@ -1247,11 +1268,10 @@
 				(long long)sle64_to_cpu(ia->index_block_vcn),
 				(long long)ia_pos >>
 				ndir->_IDM(index_vcn_size_bits), vdir->i_ino);
-		err = -EIO;
-		goto unm_dir_err_out;
+		goto err_out;
 	}
-	if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
-			ndir->_IDM(index_block_size)) {
+	if (unlikely(le32_to_cpu(ia->index.allocated_size) + 0x18 !=
+			ndir->_IDM(index_block_size))) {
 		ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
 				"0x%lx has a size (%u) differing from the "
 				"directory specified size (%u). Directory "
@@ -1260,28 +1280,25 @@
 				ndir->_IDM(index_vcn_size_bits), vdir->i_ino,
 				le32_to_cpu(ia->index.allocated_size) + 0x18,
 				ndir->_IDM(index_block_size));
-		err = -EIO;
-		goto unm_dir_err_out;
+		goto err_out;
 	}
 	index_end = (u8*)ia + ndir->_IDM(index_block_size);
-	if (index_end > kaddr + PAGE_CACHE_SIZE) {
+	if (unlikely(index_end > kaddr + PAGE_CACHE_SIZE)) {
 		ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
 				"0x%lx crosses page boundary. Impossible! "
 				"Cannot access! This is probably a bug in the "
 				"driver.", (long long)ia_pos >>
 				ndir->_IDM(index_vcn_size_bits), vdir->i_ino);
-		err = -EIO;
-		goto unm_dir_err_out;
+		goto err_out;
 	}
 	ia_start = ia_pos & ~(s64)(ndir->_IDM(index_block_size) - 1);
 	index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
-	if (index_end > (u8*)ia + ndir->_IDM(index_block_size)) {
+	if (unlikely(index_end > (u8*)ia + ndir->_IDM(index_block_size))) {
 		ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory "
 				"inode 0x%lx exceeds maximum size.",
 				(long long)ia_pos >>
 				ndir->_IDM(index_vcn_size_bits), vdir->i_ino);
-		err = -EIO;
-		goto unm_dir_err_out;
+		goto err_out;
 	}
 	/* The first index entry in this index buffer. */
 	ie = (INDEX_ENTRY*)((u8*)&ia->index +
@@ -1295,11 +1312,11 @@
 		ntfs_debug("In index allocation, offset 0x%Lx.",
 				(long long)ia_start + ((u8*)ie - (u8*)ia));
 		/* Bounds checks. */
-		if ((u8*)ie < (u8*)ia || (u8*)ie +
+		if (unlikely((u8*)ie < (u8*)ia || (u8*)ie +
 				sizeof(INDEX_ENTRY_HEADER) > index_end ||
 				(u8*)ie + le16_to_cpu(ie->_IEH(key_length)) >
-				index_end)
-			goto unm_dir_err_out;
+				index_end))
+			goto err_out;
 		/* The last entry cannot contain a name. */
 		if (ie->_IEH(flags) & INDEX_ENTRY_END)
 			break;
@@ -1310,11 +1327,16 @@
 		rc = ntfs_filldir(vol, filp, ndir, INDEX_TYPE_ALLOCATION, ia,
 				ie, name, dirent, filldir);
 		if (rc) {
-			ntfs_unmap_page(page);
+			ntfs_unmap_page(ia_page);
+			ntfs_unmap_page(bmp_page);
 			goto abort;
 		}
 	}
 	goto find_next_index_buffer;
+unm_EOD:
+	if (ia_page)
+		ntfs_unmap_page(ia_page);
+	ntfs_unmap_page(bmp_page);
 EOD:
 	/* We are finished, set f_pos to EOD. */
 	filp->f_pos = vdir->i_size + vol->mft_record_size;
@@ -1331,29 +1353,52 @@
 				rc, filp->f_pos);
 #endif
 	return 0;
-map_page_err_out:
-	ntfs_error(sb, "Reading index allocation data failed.");
-	err = PTR_ERR(page);
-kf_unm_err_out:
-	kfree(name);
-put_unm_err_out:
-	put_attr_search_ctx(ctx);
-unm_err_out:
-	unmap_mft_record(READ, ndir);
 err_out:
+	if (bmp_page)
+		ntfs_unmap_page(bmp_page);
+	if (ia_page)
+		ntfs_unmap_page(ia_page);
+	if (name)
+		kfree(name);
+	if (ctx)
+		put_attr_search_ctx(ctx);
+	if (m)
+		unmap_mft_record(READ, ndir);
+	if (!err)
+		err = -EIO;
 	ntfs_debug("Failed. Returning error code %i.", -err);
 	return err;
-unm_dir_err_out:
-	ntfs_unmap_page(page);
-dir_err_out:
-	ntfs_error(sb, "Corrupt directory. Aborting. You should run chkdsk.");
-	err = -EIO;
-	goto kf_unm_err_out;
+}
+
+/**
+ * ntfs_dir_open - called when an inode is about to be opened
+ * @vi:		inode to be opened
+ * @filp:	file structure describing the inode
+ *
+ * Limit directory size to the page cache limit on architectures where unsigned
+ * long is 32-bits. This is the most we can do for now without overflowing the
+ * page cache page index. Doing it this way means we don't run into problems
+ * because of existing too large directories. It would be better to allow the
+ * user to read the accessible part of the directory but I doubt very much
+ * anyone is going to hit this check on a 32-bit architecture, so there is no
+ * point in adding the extra complexity required to support this.
+ *
+ * On 64-bit architectures, the check is hopefully optimized away by the
+ * compiler.
+ */
+static int ntfs_dir_open(struct inode *vi, struct file *filp)
+{
+	if (sizeof(unsigned long) < 8) {
+		if (vi->i_size > MAX_LFS_FILESIZE)
+			return -EFBIG;
+	}
+	return 0;
 }
 
 struct file_operations ntfs_dir_ops = {
 	llseek:		generic_file_llseek,	/* Seek inside directory. */
 	read:		generic_read_dir,	/* Return -EISDIR. */
 	readdir:	ntfs_readdir,		/* Read directory contents. */
+	open:		ntfs_dir_open,		/* Open directory. */
 };
 
diff -Nru a/fs/ntfs/file.c b/fs/ntfs/file.c
--- a/fs/ntfs/file.c	Tue Jul 16 16:49:42 2002
+++ b/fs/ntfs/file.c	Tue Jul 16 16:49:42 2002
@@ -21,11 +21,38 @@
 
 #include "ntfs.h"
 
+/**
+ * ntfs_file_open - called when an inode is about to be opened
+ * @vi:		inode to be opened
+ * @filp:	file structure describing the inode
+ *
+ * Limit file size to the page cache limit on architectures where unsigned long
+ * is 32-bits. This is the most we can do for now without overflowing the page
+ * cache page index. Doing it this way means we don't run into problems because
+ * of existing too large files. It would be better to allow the user to read
+ * the beginning of the file but I doubt very much anyone is going to hit this
+ * check on a 32-bit architecture, so there is no point in adding the extra
+ * complexity required to support this.
+ *
+ * On 64-bit architectures, the check is hopefully optimized away by the
+ * compiler.
+ *
+ * After the check passes, just call generic_file_open() to do its work.
+ */
+static int ntfs_file_open(struct inode *vi, struct file *filp)
+{
+	if (sizeof(unsigned long) < 8) {
+		if (vi->i_size > MAX_LFS_FILESIZE)
+			return -EFBIG;
+	}
+	return generic_file_open(vi, filp);
+}
+
 struct file_operations ntfs_file_ops = {
-	llseek:			generic_file_llseek,	/* Seek inside file. */
-	read:			generic_file_read,	/* Read from file. */
-	mmap:			generic_file_mmap,	/* Mmap file. */
-	open:			generic_file_open,	/* Open file. */
+	llseek:		generic_file_llseek,	/* Seek inside file. */
+	read:		generic_file_read,	/* Read from file. */
+	mmap:		generic_file_mmap,	/* Mmap file. */
+	open:		ntfs_file_open,		/* Open file. */
 };
 
 struct inode_operations ntfs_file_inode_ops = {};
diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c
--- a/fs/ntfs/inode.c	Tue Jul 16 16:49:42 2002
+++ b/fs/ntfs/inode.c	Tue Jul 16 16:49:42 2002
@@ -35,7 +35,7 @@
  * @type:	attribute type (see layout.h)
  *
  * This structure exists only to provide a small structure for the
- * ntfs_iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism.
+ * ntfs_{attr_}iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism.
  *
  * NOTE: Elements are ordered by size to make the structure as compact as
  * possible on all architectures.
@@ -112,14 +112,21 @@
 	ntfs_inode *ni = NTFS_I(vi);
 
 	vi->i_ino = na->mft_no;
+
 	ni->type = na->type;
+	if (na->type == AT_INDEX_ALLOCATION)
+		NInoSetMstProtected(ni);
+
 	ni->name = na->name;
 	ni->name_len = na->name_len;
+
 	/* If initializing a normal inode, we are done. */
 	if (likely(na->type == AT_UNUSED))
 		return 0;
+
 	/* It is a fake inode. */
 	NInoSetAttr(ni);
+
 	/*
 	 * We have I30 global constant as an optimization as it is the name
 	 * in >99.9% of named attributes! The other <0.1% incur a GFP_ATOMIC
@@ -142,7 +149,8 @@
 
 typedef int (*test_t)(struct inode *, void *);
 typedef int (*set_t)(struct inode *, void *);
-static void ntfs_read_locked_inode(struct inode *vi);
+static int ntfs_read_locked_inode(struct inode *vi);
+static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi);
 
 /**
  * ntfs_iget - obtain a struct inode corresponding to a specific normal inode
@@ -164,6 +172,7 @@
 {
 	struct inode *vi;
 	ntfs_attr na;
+	int err;
 
 	na.mft_no = mft_no;
 	na.type = AT_UNUSED;
@@ -175,25 +184,77 @@
 	if (!vi)
 		return ERR_PTR(-ENOMEM);
 
+	err = 0;
+
+	/* If this is a freshly allocated inode, need to read it now. */
+	if (vi->i_state & I_NEW) {
+		err = ntfs_read_locked_inode(vi);
+		unlock_new_inode(vi);
+	}
+	/*
+	 * There is no point in keeping bad inodes around if the failure was
+	 * due to ENOMEM. We want to be able to retry again layer.
+	 */
+	if (err == -ENOMEM) {
+		iput(vi);
+		vi = ERR_PTR(err);
+	}
+	return vi;
+}
+
+/**
+ * ntfs_attr_iget - obtain a struct inode corresponding to an attribute
+ * @base_vi:	vfs base inode containing the attribute
+ * @type:	attribute type
+ * @name:	Unicode name of the attribute (NULL if unnamed)
+ * @name_len:	length of @name in Unicode characters (0 if unnamed)
+ *
+ * Obtain the (fake) struct inode corresponding to the attribute specified by
+ * @type, @name, and @name_len, which is present in the base mft record
+ * specified by the vfs inode @base_vi.
+ *
+ * If the attribute inode is in the cache, it is just returned with an
+ * increased reference count. Otherwise, a new struct inode is allocated and
+ * initialized, and finally ntfs_read_locked_attr_inode() is called to read the
+ * attribute and fill in the inode structure.
+ *
+ * Return the struct inode of the attribute inode on success. Check the return
+ * value with IS_ERR() and if true, the function failed and the error code is
+ * obtained from PTR_ERR().
+ */
+struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPES type,
+		uchar_t *name, u32 name_len)
+{
+	struct inode *vi;
+	ntfs_attr na;
+	int err;
+
+	na.mft_no = base_vi->i_ino;
+	na.type = type;
+	na.name = name;
+	na.name_len = name_len;
+
+	vi = iget5_locked(base_vi->i_sb, na.mft_no, (test_t)ntfs_test_inode,
+			(set_t)ntfs_init_locked_inode, &na);
+	if (!vi)
+		return ERR_PTR(-ENOMEM);
+
+	err = 0;
+
 	/* If this is a freshly allocated inode, need to read it now. */
 	if (vi->i_state & I_NEW) {
-		ntfs_read_locked_inode(vi);
+		err = ntfs_read_locked_attr_inode(base_vi, vi);
 		unlock_new_inode(vi);
 	}
-#if 0
-	// TODO: Enable this and do the follow up cleanup, i.e. remove all the
-	// bad inode checks. -- BUT: Do we actually want to do this? -- It may
-	// result in repeated attemps to read a bad inode which is not
-	// desirable. (AIA)
 	/*
-	 * There is no point in keeping bad inodes around. This also simplifies
-	 * things in that we never need to check for bad inodes elsewhere.
+	 * There is no point in keeping bad attribute inodes around. This also
+	 * simplifies things in that we never need to check for bad attribute
+	 * inodes elsewhere.
 	 */
-	if (is_bad_inode(vi)) {
+	if (err) {
 		iput(vi);
-		vi = ERR_PTR(-EIO);
+		vi = ERR_PTR(err);
 	}
-#endif
 	return vi;
 }
 
@@ -268,12 +329,9 @@
 	ni->attr_list_size = 0;
 	ni->attr_list = NULL;
 	init_run_list(&ni->attr_list_rl);
+	ni->_IDM(bmp_ino) = NULL;
 	ni->_IDM(index_block_size) = 0;
 	ni->_IDM(index_vcn_size) = 0;
-	ni->_IDM(bmp_size) = 0;
-	ni->_IDM(bmp_initialized_size) = 0;
-	ni->_IDM(bmp_allocated_size) = 0;
-	init_run_list(&ni->_IDM(bmp_rl));
 	ni->_IDM(index_block_size_bits) = 0;
 	ni->_IDM(index_vcn_size_bits) = 0;
 	init_MUTEX(&ni->extent_lock);
@@ -407,15 +465,18 @@
  *    is allowed to write to them. We should of course be honouring them but
  *    we need to do that using the IS_* macros defined in include/linux/fs.h.
  *    In any case ntfs_read_locked_inode() has nothing to do with i_flags.
+ *
+ * Return 0 on success and -errno on error. In the error case, the inode will
+ * have had make_bad_inode() executed on it.
  */
-static void ntfs_read_locked_inode(struct inode *vi)
+static int ntfs_read_locked_inode(struct inode *vi)
 {
 	ntfs_volume *vol = NTFS_SB(vi->i_sb);
 	ntfs_inode *ni;
 	MFT_RECORD *m;
 	STANDARD_INFORMATION *si;
 	attr_search_context *ctx;
-	int err;
+	int err = 0;
 
 	ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino);
 
@@ -428,46 +489,42 @@
 	 * that the file can be updated if necessary (compare with f_version).
 	 */
 	vi->i_version = ++event;
-	/* Set uid and gid from the mount options. */
+
 	vi->i_uid = vol->uid;
 	vi->i_gid = vol->gid;
-	/* Set to zero so we can use logical operations on it from here on. */
 	vi->i_mode = 0;
 
 	/*
 	 * Initialize the ntfs specific part of @vi special casing
-	 * FILE_MFT which we need to do at mount time. This also sets
-	 * ni->mft_no to vi->i_ino.
+	 * FILE_MFT which we need to do at mount time.
 	 */
 	if (vi->i_ino != FILE_MFT)
 		ntfs_init_big_inode(vi);
-
 	ni = NTFS_I(vi);
 
-	/* Map, pin and lock the mft record for reading. */
 	m = map_mft_record(READ, ni);
 	if (IS_ERR(m)) {
 		err = PTR_ERR(m);
 		goto err_out;
 	}
+	ctx = get_attr_search_ctx(ni, m);
+	if (!ctx) {
+		err = -ENOMEM;
+		goto unm_err_out;
+	}
 
-	/* Is the record in use? */
 	if (!(m->flags & MFT_RECORD_IN_USE)) {
 		ntfs_error(vi->i_sb, "Inode is not in use! You should "
 				"run chkdsk.");
 		goto unm_err_out;
 	}
-
-	/* Is this an extent mft record / inode? Treat same as if not in use. */
 	if (m->base_mft_record) {
-		ntfs_error(vi->i_sb, "Inode is an extent inode! iget() "
-				"not possible. You should run chkdsk.");
+		ntfs_error(vi->i_sb, "Inode is an extent inode! You should "
+				"run chkdsk.");
 		goto unm_err_out;
 	}
 
 	/* Transfer information from mft record into vfs and ntfs inodes. */
-
-	/* Cache the sequence number in the ntfs inode. */
 	ni->seq_no = le16_to_cpu(m->sequence_number);
 
 	/*
@@ -489,21 +546,12 @@
 	 */
 	if (m->flags & MFT_RECORD_IS_DIRECTORY) {
 		vi->i_mode |= S_IFDIR;
-		/*
-		 * Linux/Unix do not support directory hard links and things
-		 * break without this kludge.
-		 */
+		/* Things break without this kludge! */
 		if (vi->i_nlink > 1)
 			vi->i_nlink = 1;
 	} else
 		vi->i_mode |= S_IFREG;
 
-	ctx = get_attr_search_ctx(ni, m);
-	if (!ctx) {
-		err = -ENOMEM;
-		goto unm_err_out;
-	}
-
 	/*
 	 * Find the standard information attribute in the mft record. At this
 	 * stage we haven't setup the attribute list stuff yet, so this could
@@ -518,7 +566,7 @@
 		 */
 		ntfs_error(vi->i_sb, "$STANDARD_INFORMATION attribute is "
 				"missing.");
-		goto put_unm_err_out;
+		goto unm_err_out;
 	}
 	/* Get the standard information attribute value. */
 	si = (STANDARD_INFORMATION*)((char*)ctx->attr +
@@ -547,10 +595,7 @@
 	 */
 	vi->i_atime = ntfs2utc(si->last_access_time);
 
-	/*
-	 * Find the attribute list attribute and set the corresponding bit in
-	 * ntfs_ino->state.
-	 */
+	/* Find the attribute list attribute if present. */
 	reinit_attr_search_ctx(ctx);
 	if (lookup_attr(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx)) {
 		if (vi->i_ino == FILE_MFT)
@@ -564,7 +609,7 @@
 					"compressed/encrypted/sparse. Not "
 					"allowed. Corrupt inode. You should "
 					"run chkdsk.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		/* Now allocate memory for the attribute list. */
 		ni->attr_list_size = (u32)attribute_value_length(ctx->attr);
@@ -573,7 +618,7 @@
 			ntfs_error(vi->i_sb, "Not enough memory to allocate "
 					"buffer for attribute list.");
 			err = -ENOMEM;
-			goto ec_put_unm_err_out;
+			goto unm_err_out;
 		}
 		if (ctx->attr->non_resident) {
 			NInoSetAttrListNonResident(ni);
@@ -582,7 +627,7 @@
 						"zero lowest_vcn. Inode is "
 						"corrupt. You should run "
 						"chkdsk.");
-				goto put_unm_err_out;
+				goto unm_err_out;
 			}
 			/*
 			 * Setup the run list. No need for locking as we have
@@ -598,7 +643,7 @@
 						"error code %i. Corrupt "
 						"attribute list in inode.",
 						-err);
-				goto ec_put_unm_err_out;
+				goto unm_err_out;
 			}
 			/* Now load the attribute list. */
 			if ((err = load_attribute_list(vol, &ni->attr_list_rl,
@@ -607,7 +652,7 @@
 					ctx->attr->_ANR(initialized_size))))) {
 				ntfs_error(vi->i_sb, "Failed to load "
 						"attribute list attribute.");
-				goto ec_put_unm_err_out;
+				goto unm_err_out;
 			}
 		} else /* if (!ctx.attr->non_resident) */ {
 			if ((u8*)ctx->attr + le16_to_cpu(
@@ -617,7 +662,7 @@
 					(u8*)ctx->mrec + vol->mft_record_size) {
 				ntfs_error(vi->i_sb, "Corrupt attribute list "
 						"in inode.");
-				goto put_unm_err_out;
+				goto unm_err_out;
 			}
 			/* Now copy the attribute list. */
 			memcpy(ni->attr_list, (u8*)ctx->attr + le16_to_cpu(
@@ -632,6 +677,8 @@
 	 * in ntfs_ino->attr_list and it is ntfs_ino->attr_list_size bytes.
 	 */
 	if (S_ISDIR(vi->i_mode)) {
+		struct inode *bvi;
+		ntfs_inode *bni;
 		INDEX_ROOT *ir;
 		char *ir_end, *index_end;
 
@@ -643,13 +690,13 @@
 			// root attribute if recovery option is set.
 			ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
 					"missing.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		/* Set up the state. */
 		if (ctx->attr->non_resident) {
 			ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
 					"not resident. Not allowed.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		/*
 		 * Compressed/encrypted index root just means that the newly
@@ -664,7 +711,7 @@
 				ntfs_error(vi->i_sb, "Found encrypted and "
 						"compressed attribute. Not "
 						"allowed.");
-				goto put_unm_err_out;
+				goto unm_err_out;
 			}
 			NInoSetEncrypted(ni);
 		}
@@ -676,24 +723,23 @@
 		if (ir_end > (char*)ctx->mrec + vol->mft_record_size) {
 			ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
 					"corrupt.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		index_end = (char*)&ir->index +
 				le32_to_cpu(ir->index.index_length);
 		if (index_end > ir_end) {
 			ntfs_error(vi->i_sb, "Directory index is corrupt.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		if (ir->type != AT_FILE_NAME) {
-			ntfs_error(vi->i_sb, __FUNCTION__ "(): Indexed "
-					"attribute is not $FILE_NAME. Not "
-					"allowed.");
-			goto put_unm_err_out;
+			ntfs_error(vi->i_sb, "Indexed attribute is not "
+					"$FILE_NAME. Not allowed.");
+			goto unm_err_out;
 		}
 		if (ir->collation_rule != COLLATION_FILE_NAME) {
 			ntfs_error(vi->i_sb, "Index collation rule is not "
 					"COLLATION_FILE_NAME. Not allowed.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		ni->_IDM(index_block_size) = le32_to_cpu(ir->index_block_size);
 		if (ni->_IDM(index_block_size) &
@@ -701,7 +747,7 @@
 			ntfs_error(vi->i_sb, "Index block size (%u) is not a "
 					"power of two.",
 					ni->_IDM(index_block_size));
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		if (ni->_IDM(index_block_size) > PAGE_CACHE_SIZE) {
 			ntfs_error(vi->i_sb, "Index block size (%u) > "
@@ -710,7 +756,7 @@
 					ni->_IDM(index_block_size),
 					PAGE_CACHE_SIZE);
 			err = -EOPNOTSUPP;
-			goto ec_put_unm_err_out;
+			goto unm_err_out;
 		}
 		if (ni->_IDM(index_block_size) < NTFS_BLOCK_SIZE) {
 			ntfs_error(vi->i_sb, "Index block size (%u) < "
@@ -719,7 +765,7 @@
 					ni->_IDM(index_block_size),
 					NTFS_BLOCK_SIZE);
 			err = -EOPNOTSUPP;
-			goto ec_put_unm_err_out;
+			goto unm_err_out;
 		}
 		ni->_IDM(index_block_size_bits) =
 				ffs(ni->_IDM(index_block_size)) - 1;
@@ -740,7 +786,8 @@
 
 		if (!(ir->index.flags & LARGE_INDEX)) {
 			/* No index allocation. */
-			vi->i_size = ni->initialized_size = 0;
+			vi->i_size = ni->initialized_size =
+					ni->allocated_size = 0;
 			goto skip_large_dir_stuff;
 		} /* LARGE_INDEX: Index allocation present. Setup state. */
 		NInoSetIndexAllocPresent(ni);
@@ -751,97 +798,65 @@
 			ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
 					"is not present but $INDEX_ROOT "
 					"indicated it is.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		if (!ctx->attr->non_resident) {
 			ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
 					"is resident.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		if (ctx->attr->flags & ATTR_IS_ENCRYPTED) {
 			ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
 					"is encrypted.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		if (ctx->attr->flags & ATTR_IS_SPARSE) {
 			ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
 					"is sparse.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
 			ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
 					"is compressed.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		if (ctx->attr->_ANR(lowest_vcn)) {
 			ntfs_error(vi->i_sb, "First extent of "
 					"$INDEX_ALLOCATION attribute has non "
 					"zero lowest_vcn. Inode is corrupt. "
 					"You should run chkdsk.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		vi->i_size = sle64_to_cpu(ctx->attr->_ANR(data_size));
 		ni->initialized_size = sle64_to_cpu(
 				ctx->attr->_ANR(initialized_size));
 		ni->allocated_size = sle64_to_cpu(
 				ctx->attr->_ANR(allocated_size));
-		/* Find bitmap attribute. */
-		reinit_attr_search_ctx(ctx);
-		if (!lookup_attr(AT_BITMAP, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
-				ctx)) {
-			ntfs_error(vi->i_sb, "$BITMAP attribute is not "
-					"present but it must be.");
-			goto put_unm_err_out;
-		}
-		if (ctx->attr->flags & (ATTR_COMPRESSION_MASK |
-				ATTR_IS_ENCRYPTED | ATTR_IS_SPARSE)) {
+
+		/* Get the index bitmap attribute inode. */
+		bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4);
+		if (unlikely(IS_ERR(bvi))) {
+			ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");
+			err = PTR_ERR(bvi);
+			goto unm_err_out;
+		}
+		ni->_IDM(bmp_ino) = bvi;
+		bni = NTFS_I(bvi);
+		if (NInoCompressed(bni) || NInoEncrypted(bni) ||
+				NInoSparse(bni)) {
 			ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
 					"and/or encrypted and/or sparse.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
-		if (ctx->attr->non_resident) {
-			NInoSetBmpNonResident(ni);
-			if (ctx->attr->_ANR(lowest_vcn)) {
-				ntfs_error(vi->i_sb, "First extent of $BITMAP "
-						"attribute has non zero "
-						"lowest_vcn. Inode is corrupt. "
-						"You should run chkdsk.");
-				goto put_unm_err_out;
-			}
-			ni->_IDM(bmp_size) = sle64_to_cpu(
-					ctx->attr->_ANR(data_size));
-			ni->_IDM(bmp_initialized_size) = sle64_to_cpu(
-					ctx->attr->_ANR(initialized_size));
-			ni->_IDM(bmp_allocated_size) = sle64_to_cpu(
-					ctx->attr->_ANR(allocated_size));
-			/*
-			 * Setup the run list. No need for locking as we have
-			 * exclusive access to the inode at this time.
-			 */
-			ni->_IDM(bmp_rl).rl = decompress_mapping_pairs(vol,
-					ctx->attr, NULL);
-			if (IS_ERR(ni->_IDM(bmp_rl).rl)) {
-				err = PTR_ERR(ni->_IDM(bmp_rl).rl);
-				ni->_IDM(bmp_rl).rl = NULL;
-				ntfs_error(vi->i_sb, "Mapping pairs "
-						"decompression failed with "
-						"error code %i.", -err);
-				goto ec_put_unm_err_out;
-			}
-		} else
-			ni->_IDM(bmp_size) = ni->_IDM(bmp_initialized_size) =
-					ni->_IDM(bmp_allocated_size) =
-					le32_to_cpu(
-					ctx->attr->_ARA(value_length));
 		/* Consistency check bitmap size vs. index allocation size. */
-		if (ni->_IDM(bmp_size) << 3 < vi->i_size >>
-				ni->_IDM(index_block_size_bits)) {
-			ntfs_error(vi->i_sb, "$I30 bitmap too small (0x%Lx) "
+		if ((bvi->i_size << 3) < (vi->i_size >>
+				ni->_IDM(index_block_size_bits))) {
+			ntfs_error(vi->i_sb, "Index bitmap too small (0x%Lx) "
 					"for index allocation (0x%Lx).",
-					(long long)ni->_IDM(bmp_size) << 3,
-					vi->i_size);
-			goto put_unm_err_out;
+					bvi->i_size << 3, vi->i_size);
+			goto unm_err_out;
 		}
+
 skip_large_dir_stuff:
 		/* Everyone gets read and scan permissions. */
 		vi->i_mode |= S_IRUGO | S_IXUGO;
@@ -856,7 +871,7 @@
 		/* Setup the operations for this inode. */
 		vi->i_op = &ntfs_dir_inode_ops;
 		vi->i_fop = &ntfs_dir_ops;
-		vi->i_mapping->a_ops = &ntfs_dir_aops;
+		vi->i_mapping->a_ops = &ntfs_aops;
 	} else {
 		/* It is a file. */
 		reinit_attr_search_ctx(ctx);
@@ -891,7 +906,7 @@
 			// attribute if recovery option is set.
 			ntfs_error(vi->i_sb, "$DATA attribute is "
 					"missing.");
-			goto put_unm_err_out;
+			goto unm_err_out;
 		}
 		/* Setup the state. */
 		if (ctx->attr->non_resident) {
@@ -904,14 +919,14 @@
 						"compression is disabled due "
 						"to cluster size (%i) > 4kiB.",
 						vol->cluster_size);
-					goto put_unm_err_out;
+					goto unm_err_out;
 				}
 				if ((ctx->attr->flags & ATTR_COMPRESSION_MASK)
 						!= ATTR_IS_COMPRESSED) {
 					ntfs_error(vi->i_sb, "Found "
 						"unknown compression method or "
 						"corrupt file.");
-					goto put_unm_err_out;
+					goto unm_err_out;
 				}
 				ni->_ICF(compression_block_clusters) = 1U <<
 					ctx->attr->_ANR(compression_unit);
@@ -924,7 +939,7 @@
 						"should run chkdsk.",
 					     ctx->attr->_ANR(compression_unit));
 					err = -EOPNOTSUPP;
-					goto ec_put_unm_err_out;
+					goto unm_err_out;
 				}
 				ni->_ICF(compression_block_size) = 1U << (
 						ctx->attr->_ANR(
@@ -937,7 +952,7 @@
 				if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
 					ntfs_error(vi->i_sb, "Found encrypted "
 							"and compressed data.");
-					goto put_unm_err_out;
+					goto unm_err_out;
 				}
 				NInoSetEncrypted(ni);
 			}
@@ -948,7 +963,7 @@
 						"attribute has non zero "
 						"lowest_vcn. Inode is corrupt. "
 						"You should run chkdsk.");
-				goto put_unm_err_out;
+				goto unm_err_out;
 			}
 			/* Setup all the sizes. */
 			vi->i_size = sle64_to_cpu(ctx->attr->_ANR(data_size));
@@ -960,19 +975,15 @@
 				ni->_ICF(compressed_size) = sle64_to_cpu(
 					ctx->attr->_ANR(compressed_size));
 				if (vi->i_size != ni->initialized_size)
-					ntfs_warning(vi->i_sb, "Compressed "
-							"file with data_size "
-							"unequal to "
-							"initialized size "
-							"found. This will "
-							"probably cause "
-							"problems when trying "
-							"to access the file. "
-							"Please notify "
-							"linux-ntfs-dev@"
-							"lists.sf.net that you"
-							"saw this message."
-							"Thanks!");
+					ntfs_warning(vi->i_sb, "BUG: Found "
+						"compressed file with "
+						"data_size not equal to "
+						"initialized_size. This will "
+						"probably cause problems when "
+						"trying to access the file. "
+						"Please notify linux-ntfs-dev@"
+						"lists.sf.net that you saw "
+						"this message. Thanks!");
 			}
 		} else { /* Resident attribute. */
 			/*
@@ -995,7 +1006,7 @@
 		/* Setup the operations for this inode. */
 		vi->i_op = &ntfs_file_inode_ops;
 		vi->i_fop = &ntfs_file_ops;
-		vi->i_mapping->a_ops = &ntfs_file_aops;
+		vi->i_mapping->a_ops = &ntfs_aops;
 	}
 	/*
 	 * The number of 512-byte blocks used on disk (for stat). This is in so
@@ -1012,25 +1023,263 @@
 		vi->i_blocks = ni->allocated_size >> 9;
 	else
 		vi->i_blocks = ni->_ICF(compressed_size) >> 9;
-	/* Done. */
+
 	put_attr_search_ctx(ctx);
 	unmap_mft_record(READ, ni);
+
 	ntfs_debug("Done.");
-	return;
-ec_put_unm_err_out:
-	put_attr_search_ctx(ctx);
-	goto ec_unm_err_out;
-put_unm_err_out:
-	put_attr_search_ctx(ctx);
+	return 0;
+
 unm_err_out:
-	err = -EIO;
-ec_unm_err_out:
+	if (!err)
+		err = -EIO;
+	if (ctx)
+		put_attr_search_ctx(ctx);
 	unmap_mft_record(READ, ni);
 err_out:
 	ntfs_error(vi->i_sb, "Failed with error code %i. Marking inode 0x%lx "
 			"as bad.", -err, vi->i_ino);
 	make_bad_inode(vi);
-	return;
+	return err;
+}
+
+/**
+ * ntfs_read_locked_attr_inode - read an attribute inode from its base inode
+ * @base_vi:	base inode
+ * @vi:		attribute inode to read
+ *
+ * ntfs_read_locked_attr_inode() is called from the ntfs_attr_iget() to read
+ * the attribute inode described by @vi into memory from the base mft record
+ * described by @base_ni.
+ *
+ * ntfs_read_locked_attr_inode() maps, pins and locks the base inode for
+ * reading and looks up the attribute described by @vi before setting up the
+ * necessary fields in @vi as well as initializing the ntfs inode.
+ *
+ * Q: What locks are held when the function is called?
+ * A: i_state has I_LOCK set, hence the inode is locked, also
+ *    i_count is set to 1, so it is not going to go away
+ */
+static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
+{
+	ntfs_volume *vol = NTFS_SB(vi->i_sb);
+	ntfs_inode *ni, *base_ni;
+	MFT_RECORD *m;
+	attr_search_context *ctx;
+	int err = 0;
+
+	ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino);
+
+	ntfs_init_big_inode(vi);
+
+	ni	= NTFS_I(vi);
+	base_ni = NTFS_I(base_vi);
+
+	/* Just mirror the values from the base inode. */
+	vi->i_blksize	= base_vi->i_blksize;
+	vi->i_version	= base_vi->i_version;
+	vi->i_uid	= base_vi->i_uid;
+	vi->i_gid	= base_vi->i_gid;
+	vi->i_nlink	= base_vi->i_nlink;
+	vi->i_mtime	= base_vi->i_mtime;
+	vi->i_ctime	= base_vi->i_ctime;
+	vi->i_atime	= base_vi->i_atime;
+	ni->seq_no	= base_ni->seq_no;
+
+	/* Set inode type to zero but preserve permissions. */
+	vi->i_mode	= base_vi->i_mode & ~S_IFMT;
+
+	m = map_mft_record(READ, base_ni);
+	if (IS_ERR(m)) {
+		err = PTR_ERR(m);
+		goto err_out;
+	}
+	ctx = get_attr_search_ctx(base_ni, m);
+	if (!ctx) {
+		err = -ENOMEM;
+		goto unm_err_out;
+	}
+
+	/* Find the attribute. */
+	if (!lookup_attr(ni->type, ni->name, ni->name_len, IGNORE_CASE, 0,
+			NULL, 0, ctx))
+		goto unm_err_out;
+
+	if (!ctx->attr->non_resident) {
+		if (NInoMstProtected(ni) || ctx->attr->flags) {
+			ntfs_error(vi->i_sb, "Found mst protected attribute "
+					"or attribute with non-zero flags but "
+					"the attribute is resident (mft_no "
+					"0x%lx, type 0x%x, name_len %i). "
+					"Please report you saw this message "
+					"to linux-ntfs-dev@lists.sf.net",
+					vi->i_ino, ni->type, ni->name_len);
+			goto unm_err_out;
+		}
+		/*
+		 * Resident attribute. Make all sizes equal for simplicity in
+		 * read code paths.
+		 */
+		vi->i_size = ni->initialized_size = ni->allocated_size =
+			le32_to_cpu(ctx->attr->_ARA(value_length));
+	} else {
+		NInoSetNonResident(ni);
+		if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
+			if (NInoMstProtected(ni)) {
+				ntfs_error(vi->i_sb, "Found mst protected "
+						"attribute but the attribute "
+						"is compressed (mft_no 0x%lx, "
+						"type 0x%x, name_len %i). "
+						"Please report you saw this "
+						"message to linux-ntfs-dev@"
+						"lists.sf.net", vi->i_ino,
+						ni->type, ni->name_len);
+				goto unm_err_out;
+			}
+			NInoSetCompressed(ni);
+			if ((ni->type != AT_DATA) || (ni->type == AT_DATA &&
+					ni->name_len)) {
+				ntfs_error(vi->i_sb, "Found compressed non-"
+						"data or named data attribute "
+						"(mft_no 0x%lx, type 0x%x, "
+						"name_len %i). Please report "
+						"you saw this message to "
+						"linux-ntfs-dev@lists.sf.net",
+						vi->i_ino, ni->type,
+						ni->name_len);
+				goto unm_err_out;
+			}
+			if (vol->cluster_size > 4096) {
+				ntfs_error(vi->i_sb, "Found "
+					"compressed attribute but "
+					"compression is disabled due "
+					"to cluster size (%i) > 4kiB.",
+					vol->cluster_size);
+				goto unm_err_out;
+			}
+			if ((ctx->attr->flags & ATTR_COMPRESSION_MASK)
+					!= ATTR_IS_COMPRESSED) {
+				ntfs_error(vi->i_sb, "Found unknown "
+						"compression method or "
+						"corrupt file.");
+				goto unm_err_out;
+			}
+			ni->_ICF(compression_block_clusters) = 1U <<
+					ctx->attr->_ANR(compression_unit);
+			if (ctx->attr->_ANR(compression_unit) != 4) {
+				ntfs_error(vi->i_sb, "Found "
+					"nonstandard compression unit "
+					"(%u instead of 4). Cannot "
+					"handle this. This might "
+					"indicate corruption so you "
+					"should run chkdsk.",
+				     ctx->attr->_ANR(compression_unit));
+				err = -EOPNOTSUPP;
+				goto unm_err_out;
+			}
+			ni->_ICF(compression_block_size) = 1U << (
+					ctx->attr->_ANR(
+					compression_unit) +
+					vol->cluster_size_bits);
+			ni->_ICF(compression_block_size_bits) = ffs(
+				ni->_ICF(compression_block_size)) - 1;
+		}
+		if (ctx->attr->flags & ATTR_IS_ENCRYPTED) {
+			if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
+				ntfs_error(vi->i_sb, "Found encrypted "
+						"and compressed data.");
+				goto unm_err_out;
+			}
+			if (NInoMstProtected(ni)) {
+				ntfs_error(vi->i_sb, "Found mst protected "
+						"attribute but the attribute "
+						"is encrypted (mft_no 0x%lx, "
+						"type 0x%x, name_len %i). "
+						"Please report you saw this "
+						"message to linux-ntfs-dev@"
+						"lists.sf.net", vi->i_ino,
+						ni->type, ni->name_len);
+				goto unm_err_out;
+			}
+			NInoSetEncrypted(ni);
+		}
+		if (ctx->attr->flags & ATTR_IS_SPARSE) {
+			if (NInoMstProtected(ni)) {
+				ntfs_error(vi->i_sb, "Found mst protected "
+						"attribute but the attribute "
+						"is sparse (mft_no 0x%lx, "
+						"type 0x%x, name_len %i). "
+						"Please report you saw this "
+						"message to linux-ntfs-dev@"
+						"lists.sf.net", vi->i_ino,
+						ni->type, ni->name_len);
+				goto unm_err_out;
+			}
+			NInoSetSparse(ni);
+		}
+		if (ctx->attr->_ANR(lowest_vcn)) {
+			ntfs_error(vi->i_sb, "First extent of attribute has "
+					"non-zero lowest_vcn. Inode is "
+					"corrupt. You should run chkdsk.");
+			goto unm_err_out;
+		}
+		/* Setup all the sizes. */
+		vi->i_size = sle64_to_cpu(ctx->attr->_ANR(data_size));
+		ni->initialized_size = sle64_to_cpu(
+				ctx->attr->_ANR(initialized_size));
+		ni->allocated_size = sle64_to_cpu(
+				ctx->attr->_ANR(allocated_size));
+		if (NInoCompressed(ni)) {
+			ni->_ICF(compressed_size) = sle64_to_cpu(
+				ctx->attr->_ANR(compressed_size));
+			if (vi->i_size != ni->initialized_size)
+				ntfs_warning(vi->i_sb, "Compressed attribute "
+						"with data_size unequal to "
+						"initialized size found. This "
+						"will probably cause problems "
+						"when trying to access the "
+						"file. Please notify "
+						"linux-ntfs-dev@lists.sf.net "
+						"that you saw this message.");
+		}
+	}
+
+	/* Setup the operations for this attribute inode. */
+	vi->i_op = NULL;
+	vi->i_fop = NULL;
+	vi->i_mapping->a_ops = &ntfs_aops;
+
+	if (!NInoCompressed(ni))
+		vi->i_blocks = ni->allocated_size >> 9;
+	else
+		vi->i_blocks = ni->_ICF(compressed_size) >> 9;
+
+	/*
+	 * Make sure the base inode doesn't go away and attach it to the
+	 * attribute inode.
+	 */
+	igrab(base_vi);
+	ni->_INE(base_ntfs_ino) = base_ni;
+	ni->nr_extents = -1;
+
+	put_attr_search_ctx(ctx);
+	unmap_mft_record(READ, base_ni);
+
+	ntfs_debug("Done.");
+	return 0;
+
+unm_err_out:
+	if (!err)
+		err = -EIO;
+	if (ctx)
+		put_attr_search_ctx(ctx);
+	unmap_mft_record(READ, base_ni);
+err_out:
+	ntfs_error(vi->i_sb, "Failed with error code %i while reading "
+			"attribute inode (mft_no 0x%lx, type 0x%x, name_len "
+			"%i.", -err, vi->i_ino, ni->type, ni->name_len);
+	make_bad_inode(vi);
+	return err;
 }
 
 /**
@@ -1504,6 +1753,32 @@
 	return 0;
 }
 
+/**
+ * ntfs_put_inode - handler for when the inode reference count is decremented
+ * @vi:		vfs inode
+ *
+ * The VFS calls ntfs_put_inode() every time the inode reference count (i_count)
+ * is about to be decremented (but before the decrement itself.
+ *
+ * If the inode @vi is a directory with a single reference, we need to put the
+ * attribute inode for the directory index bitmap, if it is present, otherwise
+ * the directory inode would remain pinned for ever (or rather until umount()
+ * time.
+ */
+void ntfs_put_inode(struct inode *vi)
+{
+	if (S_ISDIR(vi->i_mode) && (atomic_read(&vi->i_count) == 2)) {
+		ntfs_inode *ni;
+
+		ni = NTFS_I(vi);
+		if (NInoIndexAllocPresent(ni) && ni->_IDM(bmp_ino)) {
+			iput(ni->_IDM(bmp_ino));
+			ni->_IDM(bmp_ino) = NULL;
+		}
+	}
+	return;
+}
+
 void __ntfs_clear_inode(ntfs_inode *ni)
 {
 	int err;
@@ -1585,11 +1860,13 @@
 
 	__ntfs_clear_inode(ni);
 
-	if (S_ISDIR(vi->i_mode)) {
-		down_write(&ni->_IDM(bmp_rl).lock);
-		if (ni->_IDM(bmp_rl).rl)
-			ntfs_free(ni->_IDM(bmp_rl).rl);
-		up_write(&ni->_IDM(bmp_rl).lock);
+	if (NInoAttr(ni)) {
+		/* Release the base inode if we are holding it. */
+		if (ni->nr_extents == -1) {
+			iput(VFS_I(ni->_INE(base_ntfs_ino)));
+			ni->nr_extents = 0;
+			ni->_INE(base_ntfs_ino) = NULL;
+		}
 	}
 	return;
 }
diff -Nru a/fs/ntfs/inode.h b/fs/ntfs/inode.h
--- a/fs/ntfs/inode.h	Tue Jul 16 16:49:43 2002
+++ b/fs/ntfs/inode.h	Tue Jul 16 16:49:43 2002
@@ -92,14 +92,11 @@
 	run_list attr_list_rl;	/* Run list for the attribute list value. */
 	union {
 		struct { /* It is a directory or $MFT. */
+			struct inode *bmp_ino;	/* Attribute inode for the
+						   directory index $BITMAP. */
 			u32 index_block_size;	/* Size of an index block. */
 			u32 index_vcn_size;	/* Size of a vcn in this
 						   directory index. */
-			s64 bmp_size;		/* Size of the $I30 bitmap. */
-			s64 bmp_initialized_size; /* Copy from $I30 bitmap. */
-			s64 bmp_allocated_size;	/* Copy from $I30 bitmap. */
-			run_list bmp_rl;	/* Run list for the $I30 bitmap
-						   if it is non-resident. */
 			u8 index_block_size_bits; /* Log2 of the above. */
 			u8 index_vcn_size_bits;	/* Log2 of the above. */
 		} SN(idm);
@@ -165,7 +162,6 @@
 	NI_Sparse,		/* 1: Unnamed data attr is sparse (f).
 				   1: Create sparse files by default (d).
 				   1: Attribute is sparse (a). */
-	NI_BmpNonResident,	/* 1: $I30 bitmap attr is non resident (d). */
 } ntfs_inode_state_bits;
 
 /*
@@ -203,7 +199,6 @@
 NINO_FNS(Compressed)
 NINO_FNS(Encrypted)
 NINO_FNS(Sparse)
-NINO_FNS(BmpNonResident)
 
 /*
  * The full structure containing a ntfs_inode and a vfs struct inode. Used for
@@ -232,6 +227,8 @@
 }
 
 extern struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no);
+extern struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPES type,
+		uchar_t *name, u32 name_len);
 
 extern struct inode *ntfs_alloc_big_inode(struct super_block *sb);
 extern void ntfs_destroy_big_inode(struct inode *inode);
@@ -244,6 +241,8 @@
 extern void ntfs_read_inode_mount(struct inode *vi);
 
 extern void ntfs_dirty_inode(struct inode *vi);
+
+extern void ntfs_put_inode(struct inode *vi);
 
 extern int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt);
 
diff -Nru a/fs/ntfs/mft.c b/fs/ntfs/mft.c
--- a/fs/ntfs/mft.c	Tue Jul 16 16:49:41 2002
+++ b/fs/ntfs/mft.c	Tue Jul 16 16:49:41 2002
@@ -95,8 +95,10 @@
 	return 0;
 }
 
-/* From fs/ntfs/aops.c */
-extern int ntfs_mst_readpage(struct file *, struct page *);
+/**
+ * From fs/ntfs/aops.c
+ */
+extern int ntfs_readpage(struct file *, struct page *);
 
 /**
  * ntfs_mft_aops - address space operations for access to $MFT
@@ -106,7 +108,7 @@
  */
 struct address_space_operations ntfs_mft_aops = {
 	writepage:	NULL,			/* Write dirty page to disk. */
-	readpage:	ntfs_mst_readpage,	/* Fill page with data. */
+	readpage:	ntfs_readpage,		/* Fill page with data. */
 	sync_page:	block_sync_page,	/* Currently, just unplugs the
 						   disk request queue. */
 	prepare_write:	NULL,			/* . */
@@ -214,11 +216,11 @@
  * necessary, increments the use count on the page so that it cannot disappear
  * under us and returns a reference to the page cache page).
  *
- * If read_cache_page() invokes ntfs_mst_readpage() to load the page from disk,
- * it sets PG_locked and clears PG_uptodate on the page. Once I/O has
- * completed and the post-read mst fixups on each mft record in the page have
- * been performed, the page gets PG_uptodate set and PG_locked cleared (this is
- * done in our asynchronous I/O completion handler end_buffer_read_mft_async()).
+ * If read_cache_page() invokes ntfs_readpage() to load the page from disk, it
+ * sets PG_locked and clears PG_uptodate on the page. Once I/O has completed
+ * and the post-read mst fixups on each mft record in the page have been
+ * performed, the page gets PG_uptodate set and PG_locked cleared (this is done
+ * in our asynchronous I/O completion handler end_buffer_read_mft_async()).
  * ntfs_map_page() waits for PG_locked to become clear and checks if
  * PG_uptodate is set and returns an error code if not. This provides
  * sufficient protection against races when reading/using the page.
diff -Nru a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
--- a/fs/ntfs/ntfs.h	Tue Jul 16 16:49:42 2002
+++ b/fs/ntfs/ntfs.h	Tue Jul 16 16:49:42 2002
@@ -62,18 +62,20 @@
 extern kmem_cache_t *ntfs_attr_ctx_cache;
 
 /* The various operations structs defined throughout the driver files. */
-extern struct super_operations ntfs_mount_sops;
 extern struct super_operations ntfs_sops;
-extern struct file_operations ntfs_file_ops;
+extern struct super_operations ntfs_mount_sops;
+
+extern struct address_space_operations ntfs_aops;
+extern struct address_space_operations ntfs_mft_aops;
+
+extern struct  file_operations ntfs_file_ops;
 extern struct inode_operations ntfs_file_inode_ops;
-extern struct address_space_operations ntfs_file_aops;
-extern struct file_operations ntfs_dir_ops;
+
+extern struct  file_operations ntfs_dir_ops;
 extern struct inode_operations ntfs_dir_inode_ops;
-extern struct address_space_operations ntfs_dir_aops;
-extern struct file_operations ntfs_empty_file_ops;
+
+extern struct  file_operations ntfs_empty_file_ops;
 extern struct inode_operations ntfs_empty_inode_ops;
-extern struct address_space_operations ntfs_mft_aops;
-extern struct address_space_operations ntfs_mftbmp_aops;
 
 /* Generic macro to convert pointers to values for comparison purposes. */
 #ifndef p2n
@@ -156,7 +158,7 @@
 /* Declarations of functions and global variables. */
 
 /* From fs/ntfs/compress.c */
-extern int ntfs_file_read_compressed_block(struct page *page);
+extern int ntfs_read_compressed_block(struct page *page);
 
 /* From fs/ntfs/super.c */
 #define default_upcase_len 0x10000
diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c
--- a/fs/ntfs/super.c	Tue Jul 16 16:49:41 2002
+++ b/fs/ntfs/super.c	Tue Jul 16 16:49:41 2002
@@ -2,7 +2,7 @@
  * super.c - NTFS kernel super block handling. Part of the Linux-NTFS project.
  *
  * Copyright (c) 2001,2002 Anton Altaparmakov.
- * Copyright (C) 2001,2002 Richard Russon.
+ * Copyright (c) 2001,2002 Richard Russon.
  *
  * This program/include file is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as published
@@ -135,6 +135,7 @@
 	}
 	if (!opt || !*opt)
 		goto no_mount_options;
+	ntfs_debug("Entering with mount options string: %s", opt);
 	while ((p = strsep(&opt, ","))) {
 		if ((v = strchr(p, '=')))
 			*v++ = '\0';
@@ -217,7 +218,7 @@
 		}
 	}
 	if (nls_map) {
-		if (vol->nls_map) {
+		if (vol->nls_map && vol->nls_map != nls_map) {
 			ntfs_error(vol->sb, "Cannot change NLS character set "
 					"on remount.");
 			return FALSE;
@@ -249,8 +250,8 @@
 			mft_zone_multiplier = 1;
 		}
 		vol->mft_zone_multiplier = mft_zone_multiplier;
-	} if (!vol->mft_zone_multiplier)
-		/* Not specified and it is the first mount, so set default. */
+	}
+	if (!vol->mft_zone_multiplier)
 		vol->mft_zone_multiplier = 1;
 	if (on_errors != -1)
 		vol->on_errors = on_errors;
@@ -304,7 +305,7 @@
 {
 	ntfs_volume *vol = NTFS_SB(sb);
 
-	ntfs_debug("Entering.");
+	ntfs_debug("Entering with remount options string: %s", opt);
 
 	// FIXME/TODO: If left like this we will have problems with rw->ro and
 	// ro->rw, as well as with sync->async and vice versa remounts.
@@ -322,6 +323,11 @@
 
 	if (!parse_options(vol, opt))
 		return -EINVAL;
+
+#ifndef NTFS_RW
+	*flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
+#endif
+
 	return 0;
 }
 
@@ -407,7 +413,7 @@
 }
 
 /**
- * read_boot_sector - read the NTFS boot sector of a device
+ * read_ntfs_boot_sector - read the NTFS boot sector of a device
  * @sb:		super block of device to read the boot sector from
  * @silent:	if true, suppress all output
  *
@@ -607,6 +613,20 @@
 	}
 	vol->nr_clusters = ll;
 	ntfs_debug("vol->nr_clusters = 0x%Lx", (long long)vol->nr_clusters);
+	/*
+	 * On an architecture where unsigned long is 32-bits, we restrict the
+	 * volume size to 2TiB (2^41). On a 64-bit architecture, the compiler
+	 * will hopefully optimize the whole check away.
+	 */
+	if (sizeof(unsigned long) < 8) {
+		if ((ll << vol->cluster_size_bits) >= (1ULL << 41)) {
+			ntfs_error(vol->sb, "Volume size (%LuTiB) is too large "
+					"for this architecture. Maximim "
+					"supported is 2TiB. Sorry.",
+					ll >> (40 - vol->cluster_size_bits));
+			return FALSE;
+		}
+	}
 	ll = sle64_to_cpu(b->mft_lcn);
 	if (ll >= vol->nr_clusters) {
 		ntfs_error(vol->sb, "MFT LCN is beyond end of volume. Weird.");
@@ -774,152 +794,28 @@
  */
 static BOOL load_system_files(ntfs_volume *vol)
 {
-	VCN next_vcn, last_vcn, highest_vcn;
 	struct super_block *sb = vol->sb;
 	struct inode *tmp_ino;
 	MFT_RECORD *m;
-	ATTR_RECORD *attr;
 	VOLUME_INFORMATION *vi;
 	attr_search_context *ctx;
-	run_list_element *rl;
 
 	ntfs_debug("Entering.");
-	/*
-	 * We have $MFT already (vol->mft_ino) but we need to setup access to
-	 * the $MFT/$BITMAP attribute.
-	 */
-	m = map_mft_record(READ, NTFS_I(vol->mft_ino));
-	if (IS_ERR(m)) {
-		ntfs_error(sb, "Failed to map $MFT.");
-		return FALSE;
-	}
-	if (!(ctx = get_attr_search_ctx(NTFS_I(vol->mft_ino), m))) {
-		ntfs_error(sb, "Failed to get attribute search context.");
-		goto unmap_err_out;
-	}
-	/* Load all attribute extents. */
-	attr = NULL;
-	rl = NULL;
-	next_vcn = last_vcn = highest_vcn = 0;
-	while (lookup_attr(AT_BITMAP, NULL, 0, 0, next_vcn, NULL, 0, ctx)) {
-		run_list_element *nrl;
-
-		/* Cache the current attribute extent. */
-		attr = ctx->attr;
-		/* $MFT/$BITMAP must be non-resident. */
-		if (!attr->non_resident) {
-			ntfs_error(sb, "$MFT/$BITMAP must be non-resident but "
-					"a resident extent was found. $MFT is "
-					"corrupt. Run chkdsk.");
-			goto put_err_out;
-		}
-		/* $MFT/$BITMAP must be uncompressed and unencrypted. */
-		if (attr->flags & ATTR_COMPRESSION_MASK ||
-				attr->flags & ATTR_IS_ENCRYPTED) {
-			ntfs_error(sb, "$MFT/$BITMAP must be uncompressed and "
-					"unencrypted but a compressed/"
-					"encrypted extent was found. $MFT is "
-					"corrupt. Run chkdsk.");
-			goto put_err_out;
-		}
-		/*
-		 * Decompress the mapping pairs array of this extent
-		 * and merge the result into the existing run list. Note we
-		 * don't need any locking at this stage as we are already
-		 * running exclusively as we are mount in progress task.
-		 */
-		nrl = decompress_mapping_pairs(vol, attr, rl);
-		if (IS_ERR(nrl)) {
-			ntfs_error(sb, "decompress_mapping_pairs() failed with "
-					"error code %ld. $MFT is corrupt.",
-					PTR_ERR(nrl));
-			goto put_err_out;
-		}
-		rl = nrl;
 
-		/* Are we in the first extent? */
-		if (!next_vcn) {
-			/* Get the last vcn in the $BITMAP attribute. */
-			last_vcn = sle64_to_cpu(attr->_ANR(allocated_size)) >>
-					vol->cluster_size_bits;
-			vol->mftbmp_size = sle64_to_cpu(attr->_ANR(data_size));
-			vol->mftbmp_initialized_size =
-					sle64_to_cpu(attr->_ANR(initialized_size));
-			vol->mftbmp_allocated_size =
-					sle64_to_cpu(attr->_ANR(allocated_size));
-			/* Consistency check. */
-			if (vol->mftbmp_size < (vol->nr_mft_records + 7) >> 3) {
-				ntfs_error(sb, "$MFT/$BITMAP is too short to "
-						"contain a complete mft "
-						"bitmap: impossible. $MFT is "
-						"corrupt. Run chkdsk.");
-				goto put_err_out;
-			}
-		}
-
-		/* Get the lowest vcn for the next extent. */
-		highest_vcn = sle64_to_cpu(attr->_ANR(highest_vcn));
-		next_vcn = highest_vcn + 1;
-
-		/* Only one extent or error, which we catch below. */
-		if (next_vcn <= 0)
-			break;
-
-		/* Avoid endless loops due to corruption. */
-		if (next_vcn < sle64_to_cpu(attr->_ANR(lowest_vcn))) {
-			ntfs_error(sb, "$MFT/$BITMAP has corrupt attribute "
-					"list attribute. Run chkdsk.");
-			goto put_err_out;
-		}
-
-	}
-	if (!attr) {
-		ntfs_error(sb, "Missing or invalid $BITMAP attribute in file "
-				"$MFT. $MFT is corrupt. Run chkdsk.");
-put_err_out:
-		put_attr_search_ctx(ctx);
-unmap_err_out:
-		unmap_mft_record(READ, NTFS_I(vol->mft_ino));
+	/* Get mft bitmap attribute inode. */
+	vol->mftbmp_ino = ntfs_attr_iget(vol->mft_ino, AT_BITMAP, NULL, 0);
+	if (IS_ERR(vol->mftbmp_ino)) {
+		ntfs_error(sb, "Failed to load $MFT/$BITMAP attribute.");
 		return FALSE;
 	}
 
-	/* We are finished with $MFT/$BITMAP. */
-	put_attr_search_ctx(ctx);
-	unmap_mft_record(READ, NTFS_I(vol->mft_ino));
-
-	/* Catch errors. */
-	if (highest_vcn && highest_vcn != last_vcn - 1) {
-		ntfs_error(sb, "Failed to load the complete run list for "
-				"$MFT/$BITMAP. Driver bug or corrupt $MFT. "
-				"Run chkdsk.");
-		ntfs_debug("highest_vcn = 0x%Lx, last_vcn - 1 = 0x%Lx",
-				(long long)highest_vcn,
-				(long long)last_vcn - 1);
-		return FALSE;;
-	}
-
-	/* Setup the run list and the address space in the volume structure. */
-	vol->mftbmp_rl.rl = rl;
-	vol->mftbmp_mapping.a_ops = &ntfs_mftbmp_aops;
-	
-	/*
-	 * Not inode data, set to volume. Our mft bitmap access kludge...
-	 * We can only pray this is not going to cause problems... If it does
-	 * cause problems we will need a fake inode for this.
-	 */
-	vol->mftbmp_mapping.host = (struct inode*)vol;
-
-	// FIXME: If mounting read-only, it would be ok to ignore errors when
-	// loading the mftbmp but we then need to make sure nobody remounts the
-	// volume read-write...
-
 	/* Get mft mirror inode. */
 	vol->mftmirr_ino = ntfs_iget(sb, FILE_MFTMirr);
 	if (IS_ERR(vol->mftmirr_ino) || is_bad_inode(vol->mftmirr_ino)) {
 		if (!IS_ERR(vol->mftmirr_ino))
 			iput(vol->mftmirr_ino);
 		ntfs_error(sb, "Failed to load $MFTMirr.");
-		return FALSE;
+		goto iput_mftbmp_err_out;
 	}
 	// FIXME: Compare mftmirr with mft and repair if appropriate and not
 	// a read-only mount.
@@ -954,7 +850,7 @@
 			iput(vol->vol_ino);
 volume_failed:
 		ntfs_error(sb, "Failed to load $Volume.");
-		goto iput_bmp_mirr_err_out;
+		goto iput_lcnbmp_err_out;
 	}
 	m = map_mft_record(READ, NTFS_I(vol->vol_ino));
 	if (IS_ERR(m)) {
@@ -978,8 +874,8 @@
 			le16_to_cpu(ctx->attr->_ARA(value_offset)));
 	/* Some bounds checks. */
 	if ((u8*)vi < (u8*)ctx->attr || (u8*)vi +
-			le32_to_cpu(ctx->attr->_ARA(value_length)) > (u8*)ctx->attr +
-			le32_to_cpu(ctx->attr->length))
+			le32_to_cpu(ctx->attr->_ARA(value_length)) >
+			(u8*)ctx->attr + le32_to_cpu(ctx->attr->length))
 		goto err_put_vol;
 	/* Setup volume flags and version. */
 	vol->vol_flags = vi->flags;
@@ -1000,7 +896,7 @@
 		ntfs_error(sb, "Failed to load $LogFile.");
 		// FIMXE: We only want to empty the thing so pointless bailing
 		// out. Can recover/ignore.
-		goto iput_vol_bmp_mirr_err_out;
+		goto iput_vol_err_out;
 	}
 	// FIXME: Empty the logfile, but only if not read-only.
 	// FIXME: What happens if someone remounts rw? We need to empty the file
@@ -1015,7 +911,7 @@
 		if (!IS_ERR(tmp_ino))
 			iput(tmp_ino);
 		ntfs_error(sb, "Failed to load $AttrDef.");
-		goto iput_vol_bmp_mirr_err_out;
+		goto iput_vol_err_out;
 	}
 	// FIXME: Parse the attribute definitions.
 	iput(tmp_ino);
@@ -1025,7 +921,7 @@
 		if (!IS_ERR(vol->root_ino))
 			iput(vol->root_ino);
 		ntfs_error(sb, "Failed to load root directory.");
-		goto iput_vol_bmp_mirr_err_out;
+		goto iput_vol_err_out;
 	}
 	/* If on NTFS versions before 3.0, we are done. */
 	if (vol->major_ver < 3)
@@ -1037,7 +933,7 @@
 		if (!IS_ERR(vol->secure_ino))
 			iput(vol->secure_ino);
 		ntfs_error(sb, "Failed to load $Secure.");
-		goto iput_root_vol_bmp_mirr_err_out;
+		goto iput_root_err_out;
 	}
 	// FIXME: Initialize security.
 	/* Get the extended system files' directory inode. */
@@ -1046,7 +942,7 @@
 		if (!IS_ERR(tmp_ino))
 			iput(tmp_ino);
 		ntfs_error(sb, "Failed to load $Extend.");
-		goto iput_sec_root_vol_bmp_mirr_err_out;
+		goto iput_sec_err_out;
 	}
 	// FIXME: Do something. E.g. want to delete the $UsnJrnl if exists.
 	// Note we might be doing this at the wrong level; we might want to
@@ -1055,16 +951,18 @@
 	// for the files in $Extend directory.
 	iput(tmp_ino);
 	return TRUE;
-iput_sec_root_vol_bmp_mirr_err_out:
+iput_sec_err_out:
 	iput(vol->secure_ino);
-iput_root_vol_bmp_mirr_err_out:
+iput_root_err_out:
 	iput(vol->root_ino);
-iput_vol_bmp_mirr_err_out:
+iput_vol_err_out:
 	iput(vol->vol_ino);
-iput_bmp_mirr_err_out:
+iput_lcnbmp_err_out:
 	iput(vol->lcnbmp_ino);
 iput_mirr_err_out:
 	iput(vol->mftmirr_ino);
+iput_mftbmp_err_out:
+	iput(vol->mftbmp_ino);
 	return FALSE;
 }
 
@@ -1082,8 +980,10 @@
 	ntfs_volume *vol = NTFS_SB(vfs_sb);
 
 	ntfs_debug("Entering.");
+
 	iput(vol->vol_ino);
 	vol->vol_ino = NULL;
+
 	/* NTFS 3.0+ specific clean up. */
 	if (vol->major_ver >= 3) {
 		if (vol->secure_ino) {
@@ -1091,29 +991,26 @@
 			vol->secure_ino = NULL;
 		}
 	}
+
 	iput(vol->root_ino);
 	vol->root_ino = NULL;
+
 	down_write(&vol->lcnbmp_lock);
 	iput(vol->lcnbmp_ino);
 	vol->lcnbmp_ino = NULL;
 	up_write(&vol->lcnbmp_lock);
+
 	iput(vol->mftmirr_ino);
 	vol->mftmirr_ino = NULL;
-	iput(vol->mft_ino);
-	vol->mft_ino = NULL;
+
 	down_write(&vol->mftbmp_lock);
-	/*
-	 * Clean up mft bitmap address space. Ignore the _inode_ bit in the
-	 * name of the function... FIXME: This destroys dirty pages!!! (AIA)
-	 */
-	truncate_inode_pages(&vol->mftbmp_mapping, 0);
-	vol->mftbmp_mapping.a_ops = NULL;
-	vol->mftbmp_mapping.host = NULL;
+	iput(vol->mftbmp_ino);
+	vol->mftbmp_ino = NULL;
 	up_write(&vol->mftbmp_lock);
-	down_write(&vol->mftbmp_rl.lock);
-	ntfs_free(vol->mftbmp_rl.rl);
-	vol->mftbmp_rl.rl = NULL;
-	up_write(&vol->mftbmp_rl.lock);
+
+	iput(vol->mft_ino);
+	vol->mft_ino = NULL;
+
 	vol->upcase_len = 0;
 	/*
 	 * Decrease the number of mounts and destroy the global default upcase
@@ -1241,60 +1138,41 @@
 static unsigned long __get_nr_free_mft_records(ntfs_volume *vol)
 {
 	struct address_space *mapping;
-	filler_t *readpage;
 	struct page *page;
 	unsigned long index, max_index, nr_free = 0;
 	unsigned int max_size, i;
 	u32 *b;
 
-	ntfs_debug("Entering.");
-	/* Serialize accesses to the inode bitmap. */
-	mapping = &vol->mftbmp_mapping;
-	readpage = (filler_t*)mapping->a_ops->readpage;
+	mapping = vol->mftbmp_ino->i_mapping;
 	/*
-	 * Convert the number of bits into bytes rounded up, then convert into
-	 * multiples of PAGE_CACHE_SIZE.
+	 * Convert the number of bits into bytes rounded up to a multiple of 8
+	 * bytes, then convert into multiples of PAGE_CACHE_SIZE.
 	 */
-	max_index = (vol->nr_mft_records + 7) >> (3 + PAGE_CACHE_SHIFT);
+	max_index = (((vol->nr_mft_records + 7) >> 3) + 7) >> PAGE_CACHE_SHIFT;
 	/* Use multiples of 4 bytes. */
 	max_size = PAGE_CACHE_SIZE >> 2;
 	ntfs_debug("Reading $MFT/$BITMAP, max_index = 0x%lx, max_size = "
 			"0x%x.", max_index, max_size);
 	for (index = 0UL; index < max_index;) {
 handle_partial_page:
-		/*
-		 * Read the page from page cache, getting it from backing store
-		 * if necessary, and increment the use count.
-		 */
-		page = read_cache_page(mapping, index++, (filler_t*)readpage,
-				vol);
-		/* Ignore pages which errored synchronously. */
+		page = ntfs_map_page(mapping, index++);
 		if (IS_ERR(page)) {
-			ntfs_debug("Sync read_cache_page() error. Skipping "
-					"page (index 0x%lx).", index - 1);
-			continue;
-		}
-		wait_on_page_locked(page);
-		if (!PageUptodate(page)) {
-			ntfs_debug("Async read_cache_page() error. Skipping "
-					"page (index 0x%lx).", index - 1);
-			/* Ignore pages which errored asynchronously. */
-			page_cache_release(page);
+			ntfs_debug("ntfs_map_page() error. Skipping page "
+					"(index 0x%lx).", index - 1);
 			continue;
 		}
-		b = (u32*)kmap(page);
+		b = (u32*)page_address(page);
 		/* For each 4 bytes, add up the number of zero bits. */
-	  	for (i = 0; i < max_size; i++)
+		for (i = 0; i < max_size; i++)
 			nr_free += 32 - hweight32(b[i]);
-		kunmap(page);
-		page_cache_release(page);
+		ntfs_unmap_page(page);
 	}
 	if (index == max_index) {
 		/*
 		 * Get the multiples of 4 bytes in use in the final partial
 		 * page.
 		 */
-		max_size = ((((vol->nr_mft_records + 7) >> 3) &
+		max_size = ((((((vol->nr_mft_records + 7) >> 3) + 7) & ~7) &
 				~PAGE_CACHE_MASK) + 3) >> 2;
 		/* If there is a partial page go back and do it. */
 		if (max_size) {
@@ -1308,7 +1186,6 @@
 	}
 	ntfs_debug("Finished reading $MFT/$BITMAP, last index = 0x%lx",
 			index - 1);
-	ntfs_debug("Exiting.");
 	return nr_free;
 }
 
@@ -1354,6 +1231,7 @@
 		size = 0LL;
 	/* Free blocks avail to non-superuser, same as above on NTFS. */
 	sfs->f_bavail = sfs->f_bfree = size;
+	/* Serialize accesses to the inode bitmap. */
 	down_read(&vol->mftbmp_lock);
 	/* Total file nodes in file system (at this moment in time). */
 	sfs->f_files  = vol->mft_ino->i_size >> vol->mft_record_size_bits;
@@ -1399,10 +1277,8 @@
 	dirty_inode:	ntfs_dirty_inode,	/* VFS: Called from
 						   __mark_inode_dirty(). */
 	//write_inode:	NULL,		/* VFS: Write dirty inode to disk. */
-	//put_inode:	NULL,		/* VFS: Called whenever the reference
-	//				   count (i_count) of the inode is
-	//				   going to be decreased but before the
-	//				   actual decrease. */
+	put_inode:	ntfs_put_inode,	/* VFS: Called just before the inode
+					   reference count is decreased. */
 	//delete_inode:	NULL,		/* VFS: Delete inode from disk. Called
 	//				   when i_count becomes 0 and i_nlink is
 	//				   also 0. */
@@ -1444,6 +1320,9 @@
 	int result;
 
 	ntfs_debug("Entering.");
+#ifndef NTFS_RW
+	sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
+#endif
 	/* Allocate a new ntfs_volume and place it in sb->u.generic_sbp. */
 	sb->u.generic_sbp = kmalloc(sizeof(ntfs_volume), GFP_NOFS);
 	vol = NTFS_SB(sb);
@@ -1458,6 +1337,8 @@
 	vol->sb = sb;
 	vol->upcase = NULL;
 	vol->mft_ino = NULL;
+	vol->mftbmp_ino = NULL;
+	init_rwsem(&vol->mftbmp_lock);
 	vol->mftmirr_ino = NULL;
 	vol->lcnbmp_ino = NULL;
 	init_rwsem(&vol->lcnbmp_lock);
@@ -1469,37 +1350,10 @@
 	vol->on_errors = 0;
 	vol->mft_zone_multiplier = 0;
 	vol->nls_map = NULL;
-	init_rwsem(&vol->mftbmp_lock);
-	init_run_list(&vol->mftbmp_rl);
-
-	/* Initialize the mftbmp address space mapping.  */
-	INIT_RADIX_TREE(&vol->mftbmp_mapping.page_tree, GFP_ATOMIC);
-	rwlock_init(&vol->mftbmp_mapping.page_lock);
-	INIT_LIST_HEAD(&vol->mftbmp_mapping.clean_pages);
-	INIT_LIST_HEAD(&vol->mftbmp_mapping.dirty_pages);
-	INIT_LIST_HEAD(&vol->mftbmp_mapping.locked_pages);
-	INIT_LIST_HEAD(&vol->mftbmp_mapping.io_pages);
-	vol->mftbmp_mapping.nrpages = 0;
-	vol->mftbmp_mapping.a_ops = NULL;
-	vol->mftbmp_mapping.host = NULL;
-	INIT_LIST_HEAD(&vol->mftbmp_mapping.i_mmap);
-	INIT_LIST_HEAD(&vol->mftbmp_mapping.i_mmap_shared);
-	spin_lock_init(&vol->mftbmp_mapping.i_shared_lock);
-	/*
-	 * private_lock and private_list are unused by ntfs.  But they
-	 * are available.
-	 */
-	spin_lock_init(&vol->mftbmp_mapping.private_lock);
-	INIT_LIST_HEAD(&vol->mftbmp_mapping.private_list);
-	vol->mftbmp_mapping.assoc_mapping = NULL;
-	vol->mftbmp_mapping.dirtied_when = 0;
-	vol->mftbmp_mapping.gfp_mask = GFP_HIGHUSER;
-	vol->mftbmp_mapping.backing_dev_info =
-			sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
 
 	/*
 	 * Default is group and other don't have any access to files or
-	 * directories while owner has full access. Further files by default
+	 * directories while owner has full access. Further, files by default
 	 * are not executable but directories are of course browseable.
 	 */
 	vol->fmask = 0177;
@@ -1508,9 +1362,6 @@
 	/* Important to get the mount options dealt with now. */
 	if (!parse_options(vol, (char*)opt))
 		goto err_out_now;
-	
-	/* We are just a read-only fs at the moment. */
-	sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
 
 	/*
 	 * TODO: Fail safety check. In the future we should really be able to
@@ -1666,11 +1517,8 @@
 	vol->lcnbmp_ino = NULL;
 	iput(vol->mftmirr_ino);
 	vol->mftmirr_ino = NULL;
-	truncate_inode_pages(&vol->mftbmp_mapping, 0);
-	vol->mftbmp_mapping.a_ops = NULL;
-	vol->mftbmp_mapping.host = NULL;
-	ntfs_free(vol->mftbmp_rl.rl);
-	vol->mftbmp_rl.rl = NULL;
+	iput(vol->mftbmp_ino);
+	vol->mftbmp_ino = NULL;
 	vol->upcase_len = 0;
 	if (vol->upcase != default_upcase)
 		ntfs_free(vol->upcase);
@@ -1707,7 +1555,8 @@
 	 * inode we have ever called ntfs_iget()/iput() on, otherwise we A)
 	 * leak resources and B) a subsequent mount fails automatically due to
 	 * ntfs_iget() never calling down into our ntfs_read_locked_inode()
-	 * method again...
+	 * method again... FIXME: Do we need to do this twice now because of
+	 * attribute inodes? I think not, so leave as is for now... (AIA)
 	 */
 	if (invalidate_inodes(sb)) {
 		ntfs_error(sb, "Busy inodes left. This is most likely a NTFS "
@@ -1788,7 +1637,7 @@
 
 	/* This may be ugly but it results in pretty output so who cares. (-8 */
 	printk(KERN_INFO "NTFS driver " NTFS_VERSION " [Flags: R/"
-#ifdef CONFIG_NTFS_RW
+#ifdef NTFS_RW
 			"W"
 #else
 			"O"
@@ -1799,7 +1648,7 @@
 #ifdef MODULE
 			" MODULE"
 #endif
-			"]. Copyright (c) 2001,2002 Anton Altaparmakov.\n");
+			"].\n");
 
 	ntfs_debug("Debug messages are enabled.");
 
@@ -1899,7 +1748,7 @@
 }
 
 MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>");
-MODULE_DESCRIPTION("NTFS 1.2/3.x driver");
+MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2002 Anton Altaparmakov");
 MODULE_LICENSE("GPL");
 #ifdef DEBUG
 MODULE_PARM(debug_msgs, "i");
diff -Nru a/fs/ntfs/volume.h b/fs/ntfs/volume.h
--- a/fs/ntfs/volume.h	Tue Jul 16 16:49:41 2002
+++ b/fs/ntfs/volume.h	Tue Jul 16 16:49:41 2002
@@ -27,31 +27,6 @@
 #include "types.h"
 
 /*
- * Defined bits for the flags field in the ntfs_volume structure.
- */
-typedef enum {
-	NV_ShowSystemFiles,	/* 1: Return system files in ntfs_readdir(). */
-	NV_CaseSensitive,	/* 1: Treat file names as case sensitive and
-				      create filenames in the POSIX namespace.
-				      Otherwise be case insensitive and create
-				      file names in WIN32 namespace. */
-} ntfs_volume_flags;
-
-#define NVolShowSystemFiles(n_vol)	test_bit(NV_ShowSystemFiles,	\
-							&(n_vol)->flags)
-#define NVolSetShowSystemFiles(n_vol)	set_bit(NV_ShowSystemFiles,	\
-							&(n_vol)->flags)
-#define NVolClearShowSystemFiles(n_vol)	clear_bit(NV_ShowSystemFiles,	\
-							&(n_vol)->flags)
-
-#define NVolCaseSensitive(n_vol)	test_bit(NV_CaseSensitive,	\
-							&(n_vol)->flags)
-#define NVolSetCaseSensitive(n_vol)	set_bit(NV_CaseSensitive,	\
-							&(n_vol)->flags)
-#define NVolClearCaseSensitive(n_vol)	clear_bit(NV_CaseSensitive,	\
-							&(n_vol)->flags)
-
-/*
  * The NTFS in memory super block structure.
  */
 typedef struct {
@@ -100,15 +75,13 @@
 	LCN mft_zone_start;		/* First cluster of the mft zone. */
 	LCN mft_zone_end;		/* First cluster beyond the mft zone. */
 	struct inode *mft_ino;		/* The VFS inode of $MFT. */
+
+	struct inode *mftbmp_ino;	/* Attribute inode for $MFT/$BITMAP. */
 	struct rw_semaphore mftbmp_lock; /* Lock for serializing accesses to the
 					    mft record bitmap ($MFT/$BITMAP). */
 	unsigned long nr_mft_records;	/* Number of mft records == number of
 					   bits in mft bitmap. */
-	struct address_space mftbmp_mapping; /* Page cache for $MFT/$BITMAP. */
-	run_list mftbmp_rl;		/* Run list for $MFT/$BITMAP. */
-	s64 mftbmp_size;		/* Data size of $MFT/$BITMAP. */
-	s64 mftbmp_initialized_size;	/* Initialized size of $MFT/$BITMAP. */
-	s64 mftbmp_allocated_size;	/* Allocated size of $MFT/$BITMAP. */
+
 	struct inode *mftmirr_ino;	/* The VFS inode of $MFTMirr. */
 	struct inode *lcnbmp_ino;	/* The VFS inode of $Bitmap. */
 	struct rw_semaphore lcnbmp_lock; /* Lock for serializing accesses to the
@@ -123,6 +96,39 @@
 					   only, otherwise NULL). */
 	struct nls_table *nls_map;
 } ntfs_volume;
+
+/*
+ * Defined bits for the flags field in the ntfs_volume structure.
+ */
+typedef enum {
+	NV_ShowSystemFiles,	/* 1: Return system files in ntfs_readdir(). */
+	NV_CaseSensitive,	/* 1: Treat file names as case sensitive and
+				      create filenames in the POSIX namespace.
+				      Otherwise be case insensitive and create
+				      file names in WIN32 namespace. */
+} ntfs_volume_flags;
+
+/*
+ * Macro tricks to expand the NVolFoo(), NVolSetFoo(), and NVolClearFoo()
+ * functions.
+ */
+#define NVOL_FNS(flag)					\
+static inline int NVol##flag(ntfs_volume *vol)		\
+{							\
+	return test_bit(NV_##flag, &(vol)->flags);	\
+}							\
+static inline void NVolSet##flag(ntfs_volume *vol)	\
+{							\
+	set_bit(NV_##flag, &(vol)->flags);		\
+}							\
+static inline void NVolClear##flag(ntfs_volume *vol)	\
+{							\
+	clear_bit(NV_##flag, &(vol)->flags);		\
+}
+
+/* Emit the ntfs volume bitops functions. */
+NVOL_FNS(ShowSystemFiles)
+NVOL_FNS(CaseSensitive)
 
 #endif /* _LINUX_NTFS_VOLUME_H */
 
diff -Nru a/fs/partitions/Config.in b/fs/partitions/Config.in
--- a/fs/partitions/Config.in	Tue Jul 16 16:49:42 2002
+++ b/fs/partitions/Config.in	Tue Jul 16 16:49:42 2002
@@ -34,7 +34,7 @@
    bool '  Sun partition tables support' CONFIG_SUN_PARTITION
    bool '  EFI GUID Partition support' CONFIG_EFI_PARTITION
 else
-   if [ "$ARCH" = "alpha" ]; then
+   if [ "$CONFIG_ALPHA" = "y" ]; then
       define_bool CONFIG_OSF_PARTITION y
    fi
    if [ "$CONFIG_AMIGA" != "y" -a "$CONFIG_ATARI" != "y" -a \
@@ -65,7 +65,7 @@
    if [ "$CONFIG_DECSTATION" = "y" ]; then
       define_bool CONFIG_ULTRIX_PARTITION y
    fi
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       define_bool CONFIG_SUN_PARTITION y
    fi
 fi
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Tue Jul 16 16:49:42 2002
+++ b/fs/partitions/check.c	Tue Jul 16 16:49:42 2002
@@ -226,7 +226,7 @@
 			char *page, size_t count, loff_t off)
 {
 	kdev_t kdev; 
-	kdev.value=(int)driverfs_dev->driver_data;
+	kdev.value=(int)(long)driverfs_dev->driver_data;
 	return off ? 0 : sprintf (page, "%x\n",kdev.value);
 }
 static struct driver_file_entry partition_device_kdev_file = {
@@ -285,7 +285,7 @@
 			current_driverfs_dev->parent = parent;
 			/* handle disc case */
 			current_driverfs_dev->driver_data =
-					(void *)__mkdev(hd->major, minor+part);
+					(void *)(long)__mkdev(hd->major, minor+part);
 			if (part == 0) {
 				if (parent)  {
 					sprintf(current_driverfs_dev->name,
diff -Nru a/fs/partitions/msdos.c b/fs/partitions/msdos.c
--- a/fs/partitions/msdos.c	Tue Jul 16 16:49:41 2002
+++ b/fs/partitions/msdos.c	Tue Jul 16 16:49:41 2002
@@ -453,8 +453,8 @@
 	/*
 	 * The i386 partition handling programs very often
 	 * make partitions end on cylinder boundaries.
-	 * There is no need to do so, and Linux fdisk doesnt always
-	 * do this, and Windows NT on Alpha doesnt do this either,
+	 * There is no need to do so, and Linux fdisk doesn't always
+	 * do this, and Windows NT on Alpha doesn't do this either,
 	 * but still, this helps to guess #heads.
 	 */
 	data = read_dev_sector(bdev, 0, &sect);
diff -Nru a/fs/pipe.c b/fs/pipe.c
--- a/fs/pipe.c	Tue Jul 16 16:49:41 2002
+++ b/fs/pipe.c	Tue Jul 16 16:49:41 2002
@@ -216,7 +216,7 @@
 		do {
 			/*
 			 * Synchronous wake-up: it knows that this process
-			 * is going to give up this CPU, so it doesnt have
+			 * is going to give up this CPU, so it doesn't have
 			 * to do idle reschedules.
 			 */
 			wake_up_interruptible_sync(PIPE_WAIT(*inode));
diff -Nru a/fs/quota_v2.c b/fs/quota_v2.c
--- a/fs/quota_v2.c	Tue Jul 16 16:49:42 2002
+++ b/fs/quota_v2.c	Tue Jul 16 16:49:42 2002
@@ -413,7 +413,7 @@
 
 	if (!dquot->dq_off)
 		if ((ret = dq_insert_tree(dquot)) < 0) {
-			printk(KERN_ERR "VFS: Error %d occured while creating quota.\n", ret);
+			printk(KERN_ERR "VFS: Error %Zd occured while creating quota.\n", ret);
 			return ret;
 		}
 	filp = sb_dqopt(dquot->dq_sb)->files[type];
diff -Nru a/fs/ramfs/inode.c b/fs/ramfs/inode.c
--- a/fs/ramfs/inode.c	Tue Jul 16 16:49:42 2002
+++ b/fs/ramfs/inode.c	Tue Jul 16 16:49:42 2002
@@ -102,6 +102,9 @@
 		case S_IFDIR:
 			inode->i_op = &ramfs_dir_inode_operations;
 			inode->i_fop = &simple_dir_operations;
+
+			/* directory inodes start off with i_nlink == 2 (for "." entry) */
+			inode->i_nlink++;
 			break;
 		case S_IFLNK:
 			inode->i_op = &page_symlink_inode_operations;
@@ -131,10 +134,8 @@
 static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
 {
 	int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
-	if (!retval) {
+	if (!retval)
 		dir->i_nlink++;
-		dentry->d_inode->i_nlink++;
-	}
 	return retval;
 }
 
diff -Nru a/fs/reiserfs/Makefile b/fs/reiserfs/Makefile
--- a/fs/reiserfs/Makefile	Tue Jul 16 16:49:42 2002
+++ b/fs/reiserfs/Makefile	Tue Jul 16 16:49:42 2002
@@ -6,7 +6,7 @@
 
 reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \
 		 super.o prints.o objectid.o lbalance.o ibalance.o stree.o \
-		 hashes.o buffer2.o tail_conversion.o journal.o resize.o \
+		 hashes.o tail_conversion.o journal.o resize.o \
 		 item_ops.o ioctl.o procfs.o
 
 # gcc -O2 (the kernel default)  is overaggressive on ppc32 when many inline
diff -Nru a/fs/reiserfs/buffer2.c b/fs/reiserfs/buffer2.c
--- a/fs/reiserfs/buffer2.c	Tue Jul 16 16:49:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,69 +0,0 @@
-/*
- *  Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README  
- */
-
-#include <linux/config.h>
-#include <linux/time.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/smp_lock.h>
-#include <linux/kernel_stat.h>
-#include <linux/buffer_head.h>
-
-/*
- *  wait_buffer_until_released
- *  reiserfs_bread
- */
-
-/* when we allocate a new block (get_new_buffer, get_empty_nodes) and
-   get buffer for it, it is possible that it is held by someone else
-   or even by this process. In this function we wait until all other
-   holders release buffer. To make sure, that current process does not
-   hold we did free all buffers in tree balance structure
-   (get_empty_nodes and get_nodes_for_preserving) or in path structure
-   only (get_new_buffer) just before calling this */
-void wait_buffer_until_released (const struct buffer_head * bh)
-{
-  int repeat_counter = 0;
-
-  /*
-   * FIXME! Temporary cludge until ReiserFS people tell what they
-   * actually are trying to protect against!
-   */
-  if (1)
-  	return;
-
-  while (atomic_read (&(bh->b_count)) > 1) {
-
-    if ( !(++repeat_counter % 30000000) ) {
-      reiserfs_warning ("vs-3050: wait_buffer_until_released: nobody releases buffer (%b). Still waiting (%d) %cJDIRTY %cJWAIT\n",
-			bh, repeat_counter, buffer_journaled(bh) ? ' ' : '!',
-			buffer_journal_dirty(bh) ? ' ' : '!');
-    }
-    blk_run_queues();
-    yield();
-  }
-  if (repeat_counter > 30000000) {
-    reiserfs_warning("vs-3051: done waiting, ignore vs-3050 messages for (%b)\n", bh) ;
-  }
-}
-
-/*
- * reiserfs_bread() reads a specified block and returns the buffer that contains
- * it. It returns NULL if the block was unreadable.
- */
-/* It first tries to find the block in cache, and if it cannot do so
-   then it creates a new buffer and schedules I/O to read the
-   block. */
-/* The function is NOT SCHEDULE-SAFE! */
-struct buffer_head  * reiserfs_bread (struct super_block *super, int n_block) 
-{
-    struct buffer_head  *result;
-    PROC_EXP( unsigned int ctx_switches = nr_context_switches() );
-
-    result = sb_bread(super, n_block);
-    PROC_INFO_INC( super, breads );
-    PROC_EXP( if( nr_context_switches() != ctx_switches )
-	      PROC_INFO_INC( super, bread_miss ) );
-    return result;
-}
-
diff -Nru a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c
--- a/fs/reiserfs/do_balan.c	Tue Jul 16 16:49:41 2002
+++ b/fs/reiserfs/do_balan.c	Tue Jul 16 16:49:41 2002
@@ -1078,13 +1078,9 @@
 	memcpy (insert_key + i,B_N_PKEY(S_new[i],0),KEY_SIZE);
 	insert_ptr[i] = S_new[i];
 
-	RFALSE( (atomic_read (&(S_new[i]->b_count)) != 1) &&
-		(atomic_read(&(S_new[i]->b_count)) != 2 ||
-		 !(buffer_journaled(S_new[i]) || 
-		   buffer_journal_dirty(S_new[i]))), 
+	RFALSE (!buffer_journaled (S_new [i]) || buffer_journal_dirty (S_new [i]) ||
+		buffer_dirty (S_new [i]),
 		"PAP-12247: S_new[%d] : (%b)\n", i, S_new[i]);
-
-
     }
 
     /* if the affected item was not wholly shifted then we perform all necessary operations on that part or whole of the
diff -Nru a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c
--- a/fs/reiserfs/fix_node.c	Tue Jul 16 16:49:42 2002
+++ b/fs/reiserfs/fix_node.c	Tue Jul 16 16:49:42 2002
@@ -807,32 +807,15 @@
 	    "PAP-8135: reiserfs_new_blocknrs failed when got new blocks");
 
     p_s_new_bh = sb_getblk(p_s_sb, *p_n_blocknr);
-    if (atomic_read (&(p_s_new_bh->b_count)) > 1) {
-/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
-/*
-      reiserfs_warning ("waiting for buffer %b, iput inode pid = %d, this pid %d, mode %c, %h\n",
-			p_s_new_bh, put_inode_pid, current->pid, p_s_tb->tb_vn->vn_mode, p_s_tb->tb_vn->vn_ins_ih);
-      print_tb (0, 0, 0, p_s_tb, "tb");
-*/
-/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
-      if (atomic_read(&(p_s_new_bh->b_count)) > 2 || 
-          !(buffer_journaled(p_s_new_bh) || buffer_journal_dirty(p_s_new_bh))) {
-	n_retval = REPEAT_SEARCH ;
-	free_buffers_in_tb (p_s_tb);
-	wait_buffer_until_released (p_s_new_bh);
-      }
-    }
-    RFALSE( (atomic_read (&(p_s_new_bh->b_count)) != 1 || 
-	     buffer_dirty (p_s_new_bh)) && 
-	    (atomic_read(&(p_s_new_bh->b_count)) > 2 || 
-	     !(buffer_journaled(p_s_new_bh) || 
-	       buffer_journal_dirty(p_s_new_bh))),
-	    "PAP-8140: not free or dirty buffer %b for the new block", 
+    RFALSE (buffer_dirty (p_s_new_bh) ||
+	    buffer_journaled (p_s_new_bh) ||
+	    buffer_journal_dirty (p_s_new_bh),
+	    "PAP-8140: journlaled or dirty buffer %b for the new block", 
 	    p_s_new_bh);
     
     /* Put empty buffers into the array. */
-    if (p_s_tb->FEB[p_s_tb->cur_blknum])
-      BUG();
+    RFALSE (p_s_tb->FEB[p_s_tb->cur_blknum],
+	    "PAP-8141: busy slot for new buffer");
 
     mark_buffer_journal_new(p_s_new_bh) ;
     p_s_tb->FEB[p_s_tb->cur_blknum++] = p_s_new_bh;
@@ -1926,7 +1909,7 @@
 
 	n_child_position = ( p_s_bh == p_s_tb->FL[n_h] ) ? p_s_tb->lkey[n_h] : B_NR_ITEMS (p_s_tb->FL[n_h]);
 	n_son_number = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position);
-	p_s_bh = reiserfs_bread(p_s_sb, n_son_number);
+	p_s_bh = sb_bread(p_s_sb, n_son_number);
 	if (!p_s_bh)
 	    return IO_ERROR;
 	if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) {
@@ -1959,7 +1942,7 @@
 
 	n_child_position = ( p_s_bh == p_s_tb->FR[n_h] ) ? p_s_tb->rkey[n_h] + 1 : 0;
 	n_son_number = B_N_CHILD_NUM(p_s_tb->FR[n_h], n_child_position);
-	p_s_bh = reiserfs_bread(p_s_sb, n_son_number);
+	p_s_bh = sb_bread(p_s_sb, n_son_number);
 	if (!p_s_bh)
 	    return IO_ERROR;
 	if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) {
diff -Nru a/fs/reiserfs/ibalance.c b/fs/reiserfs/ibalance.c
--- a/fs/reiserfs/ibalance.c	Tue Jul 16 16:49:42 2002
+++ b/fs/reiserfs/ibalance.c	Tue Jul 16 16:49:42 2002
@@ -1028,10 +1028,9 @@
 	/* new_insert_ptr = node_pointer to S_new */
 	new_insert_ptr = S_new;
 
-	RFALSE(( buffer_locked(S_new) || atomic_read (&(S_new->b_count)) != 1) &&
-	       (buffer_locked(S_new) || atomic_read(&(S_new->b_count)) > 2 ||
-		!(buffer_journaled(S_new) || buffer_journal_dirty(S_new))),
-	       "cm-00001: bad S_new (%b)", S_new);
+	RFALSE (!buffer_journaled(S_new) || buffer_journal_dirty(S_new) ||
+		buffer_dirty (S_new),
+		"cm-00001: bad S_new (%b)", S_new);
 
 	// S_new is released in unfix_nodes
     }
diff -Nru a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
--- a/fs/reiserfs/stree.c	Tue Jul 16 16:49:43 2002
+++ b/fs/reiserfs/stree.c	Tue Jul 16 16:49:43 2002
@@ -700,7 +700,7 @@
 	/* Read the next tree node, and set the last element in the path to
            have a pointer to it. */
 	if ( ! (p_s_bh = p_s_last_element->pe_buffer =
-		reiserfs_bread(p_s_sb, n_block_number)) ) {
+		sb_bread(p_s_sb, n_block_number)) ) {
 	    p_s_search_path->path_length --;
 	    pathrelse(p_s_search_path);
 	    return IO_ERROR;
diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c
--- a/fs/reiserfs/super.c	Tue Jul 16 16:49:42 2002
+++ b/fs/reiserfs/super.c	Tue Jul 16 16:49:42 2002
@@ -775,7 +775,7 @@
   memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * sb_bmap_nr(rs));
 
   for (i = 0; i < sb_bmap_nr(rs); i ++) {
-    SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp1 + i);
+    SB_AP_BITMAP (s)[i] = sb_bread (s, bmp1 + i);
     if (!SB_AP_BITMAP (s)[i])
       return 1;
   }
@@ -827,7 +827,7 @@
     sb_set_blocksize (s, sb_blocksize(rs));
     brelse (bh);
     
-    bh = reiserfs_bread (s, offset / s->s_blocksize);
+    bh = sb_bread (s, offset / s->s_blocksize);
     if (!bh) {
 	printk("sh-2007: read_super_block: "
                 "bread failed (dev %s, block %lu, size %lu)\n",
diff -Nru a/fs/smbfs/Makefile b/fs/smbfs/Makefile
--- a/fs/smbfs/Makefile	Tue Jul 16 16:49:42 2002
+++ b/fs/smbfs/Makefile	Tue Jul 16 16:49:42 2002
@@ -4,7 +4,8 @@
 
 obj-$(CONFIG_SMB_FS) += smbfs.o
 
-smbfs-objs := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o
+smbfs-objs := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o \
+		smbiod.o request.o
 
 # If you want debugging output, you may add these flags to the EXTRA_CFLAGS
 # SMBFS_PARANOIA should normally be enabled.
@@ -23,13 +24,15 @@
 #
 
 # getopt.c not included. It is intentionally separate
-SRC = proc.c dir.c cache.c sock.c inode.c file.c ioctl.c
+SRC = proc.c dir.c cache.c sock.c inode.c file.c ioctl.c smbiod.c request.c
 
 proto:
 	-rm -f proto.h
 	@echo >  proto2.h "/*"
 	@echo >> proto2.h " *  Autogenerated with cproto on: " `date`
 	@echo >> proto2.h " */"
+	@echo >> proto2.h ""
+	@echo >> proto2.h "struct smb_request;"
 	@echo >> proto2.h ""
 	cproto -E "gcc -E" -e -v -I $(TOPDIR)/include -DMAKING_PROTO -D__KERNEL__ $(SRC) >> proto2.h
 	mv proto2.h proto.h
diff -Nru a/fs/smbfs/file.c b/fs/smbfs/file.c
--- a/fs/smbfs/file.c	Tue Jul 16 16:49:43 2002
+++ b/fs/smbfs/file.c	Tue Jul 16 16:49:43 2002
@@ -42,9 +42,7 @@
 	 * Note: this function requires all pages to have been written already
 	 *       (should be ok with writepage_sync)
 	 */
-	smb_lock_server(server);
 	result = smb_proc_flush(server, SMB_I(dentry->d_inode)->fileid);
-	smb_unlock_server(server);
 	return result;
 }
 
@@ -129,7 +127,7 @@
 
 	offset = ((loff_t)page->index << PAGE_CACHE_SHIFT) + pageoffset;
 	VERBOSE("file ino=%ld, fileid=%d, count=%d@%Ld, wsize=%d\n",
-		inode->i_ino, inode->u.smbfs_i.fileid, count, offset, wsize);
+		inode->i_ino, SMB_I(inode)->fileid, count, offset, wsize);
 
 	do {
 		if (count < wsize)
diff -Nru a/fs/smbfs/inode.c b/fs/smbfs/inode.c
--- a/fs/smbfs/inode.c	Tue Jul 16 16:49:41 2002
+++ b/fs/smbfs/inode.c	Tue Jul 16 16:49:41 2002
@@ -434,17 +434,17 @@
 {
 	struct smb_sb_info *server = SMB_SB(sb);
 
-	if (server->sock_file) {
-		smb_dont_catch_keepalive(server);
-		fput(server->sock_file);
-	}
+	smbiod_unregister_server(server);
+
+	smb_lock_server(server);
+	server->state = CONN_INVALID;
+
+	smb_close_socket(server);
 
 	if (server->conn_pid)
-	       kill_proc(server->conn_pid, SIGTERM, 1);
+		kill_proc(server->conn_pid, SIGTERM, 1);
 
 	smb_kfree(server->ops);
-	if (server->packet)
-		smb_vfree(server->packet);
 
 	if (server->remote_nls) {
 		unload_nls(server->remote_nls);
@@ -455,6 +455,7 @@
 		server->local_nls = NULL;
 	}
 	sb->u.generic_sbp = NULL;
+	smb_unlock_server(server);
 	smb_kfree(server);
 }
 
@@ -491,32 +492,25 @@
 	server->mnt = NULL;
 	server->sock_file = NULL;
 	init_MUTEX(&server->sem);
-	init_waitqueue_head(&server->wait);
+	INIT_LIST_HEAD(&server->entry);
+	INIT_LIST_HEAD(&server->xmitq);
+	INIT_LIST_HEAD(&server->recvq);
+	server->conn_error = 0;
 	server->conn_pid = 0;
 	server->state = CONN_INVALID; /* no connection yet */
 	server->generation = 0;
-	server->packet_size = smb_round_length(SMB_INITIAL_PACKET_SIZE);
-	server->packet = smb_vmalloc(server->packet_size);
-	if (!server->packet)
-		goto out_no_mem;
 
 	/* Allocate the global temp buffer and some superblock helper structs */
+	/* FIXME: move these to the smb_sb_info struct */
 	VERBOSE("alloc chunk = %d\n", sizeof(struct smb_ops) +
-		sizeof(struct smb_mount_data_kernel) +
-		2*SMB_MAXPATHLEN + 20);
+		sizeof(struct smb_mount_data_kernel));
 	mem = smb_kmalloc(sizeof(struct smb_ops) +
-			  sizeof(struct smb_mount_data_kernel) +
-			  2*SMB_MAXPATHLEN + 20, GFP_KERNEL);
+			  sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
 	if (!mem)
-		goto out_no_temp;
+		goto out_no_mem;
 
 	server->ops = mem;
 	server->mnt = mem + sizeof(struct smb_ops);
-	server->name_buf = mem + sizeof(struct smb_ops) +
-		sizeof(struct smb_mount_data_kernel);
-	server->temp_buf = mem + sizeof(struct smb_ops) +
-		sizeof(struct smb_mount_data_kernel) +
-		SMB_MAXPATHLEN + 1;
 
 	/* Setup NLS stuff */
 	server->remote_nls = NULL;
@@ -573,14 +567,14 @@
 		goto out_no_root;
 	smb_new_dentry(sb->s_root);
 
+	smbiod_register_server(server);
+
 	return 0;
 
 out_no_root:
 	iput(root_inode);
 out_bad_option:
 	smb_kfree(mem);
-out_no_temp:
-	smb_vfree(server->packet);
 out_no_mem:
 	if (!server->mnt)
 		printk(KERN_ERR "smb_fill_super: allocation failure\n");
@@ -764,14 +758,19 @@
 
 	err = init_inodecache();
 	if (err)
-		goto out1;
+		goto out_inode;
+	err = smb_init_request_cache();
+	if (err)
+		goto out_request;
 	err = register_filesystem(&smb_fs_type);
 	if (err)
 		goto out;
 	return 0;
 out:
+	smb_destroy_request_cache();
+out_request:
 	destroy_inodecache();
-out1:
+out_inode:
 	return err;
 }
 
@@ -779,6 +778,7 @@
 {
 	DEBUG1("unregistering ...\n");
 	unregister_filesystem(&smb_fs_type);
+	smb_destroy_request_cache();
 	destroy_inodecache();
 #ifdef DEBUG_SMB_MALLOC
 	printk(KERN_DEBUG "smb_malloced: %d\n", smb_malloced);
diff -Nru a/fs/smbfs/ioctl.c b/fs/smbfs/ioctl.c
--- a/fs/smbfs/ioctl.c	Tue Jul 16 16:49:41 2002
+++ b/fs/smbfs/ioctl.c	Tue Jul 16 16:49:41 2002
@@ -41,7 +41,13 @@
 	case SMB_IOC_NEWCONN:
 		/* arg is smb_conn_opt, or NULL if no connection was made */
 		if (!arg) {
-			result = smb_wakeup(server);
+			result = 0;
+			smb_lock_server(server);
+			server->state = CONN_RETRIED;
+			printk(KERN_ERR "Connection attempt failed!  [%d]\n",
+			       server->conn_error);
+			smbiod_flush(server);
+			smb_unlock_server(server);
 			break;
 		}
 
diff -Nru a/fs/smbfs/proc.c b/fs/smbfs/proc.c
--- a/fs/smbfs/proc.c	Tue Jul 16 16:49:41 2002
+++ b/fs/smbfs/proc.c	Tue Jul 16 16:49:41 2002
@@ -23,11 +23,14 @@
 #include <linux/smbno.h>
 #include <linux/smb_mount.h>
 
+#include <net/sock.h>
+
 #include <asm/string.h>
 #include <asm/div64.h>
 
 #include "smb_debug.h"
 #include "proto.h"
+#include "request.h"
 
 
 /* Features. Undefine if they cause problems, this should perhaps be a
@@ -40,8 +43,6 @@
 #define SMB_VWV(packet)  ((packet) + SMB_HEADER_LEN)
 #define SMB_CMD(packet)  (*(packet+8))
 #define SMB_WCT(packet)  (*(packet+SMB_HEADER_LEN - 1))
-#define SMB_BCC(packet)  smb_bcc(packet)
-#define SMB_BUF(packet)  ((packet) + SMB_HEADER_LEN + SMB_WCT(packet) * 2 + 2)
 
 #define SMB_DIRINFO_SIZE 43
 #define SMB_STATUS_SIZE  21
@@ -396,12 +397,13 @@
 }
 
 /* encode_path for non-trans2 request SMBs */
-static int smb_simple_encode_path(struct smb_sb_info *server, char **p,
-			  struct dentry * entry, struct qstr * name)
+static int smb_simple_encode_path(struct smb_request *req, char **p,
+				  struct dentry * entry, struct qstr * name)
 {
+	struct smb_sb_info *server = req->rq_server;
 	char *s = *p;
 	int res;
-	int maxlen = ((char *)server->packet + server->packet_size) - s;
+	int maxlen = ((char *)req->rq_buffer + req->rq_bufsize) - s;
 	int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE);
 
 	if (!maxlen)
@@ -413,8 +415,8 @@
 	 * packet. If they are not they must be padded with 0.
 	 */
 	if (unicode) {
-		int align = s - (char *)server->packet;
-		if (align & 1) {
+		int align = s - (char *)req->rq_buffer;
+		if (!(align & 1)) {
 			*s++ = '\0';
 			maxlen--;
 		}
@@ -560,7 +562,7 @@
 		&& packet[6] == 'M'
 		&& packet[7] == 'B'
 		&& (smb_len(packet) + 4 == SMB_HEADER_LEN
-		    + SMB_WCT(packet) * 2 + SMB_BCC(packet)));
+		    + SMB_WCT(packet) * 2 + smb_bcc(packet)));
 }
 
 /* smb_verify: We check if we got the answer we expected, and if we
@@ -573,7 +575,7 @@
 		goto bad_command;
 	if (SMB_WCT(packet) < wct)
 		goto bad_wct;
-	if (bcc != -1 && SMB_BCC(packet) < bcc)
+	if (bcc != -1 && smb_bcc(packet) < bcc)
 		goto bad_bcc;
 	return 0;
 
@@ -587,7 +589,7 @@
 	goto fail;
 bad_bcc:
 	printk(KERN_ERR "smb_verify: command=%x, bcc=%d, SMB_BCC=%d??\n",
-	       command, bcc, SMB_BCC(packet));
+	       command, bcc, smb_bcc(packet));
 fail:
 	return -EIO;
 }
@@ -615,8 +617,7 @@
 	int overhead = SMB_HEADER_LEN + 12 * sizeof(__u16) + 2 + 1 + 2;
 	int size = smb_get_xmitsize(server, overhead);
 
-	VERBOSE("packet=%d, xmit=%d, size=%d\n",
-		server->packet_size, server->opt.max_xmit, size);
+	VERBOSE("xmit=%d, size=%d\n", server->opt.max_xmit, size);
 
 	return size;
 }
@@ -631,8 +632,7 @@
 	int overhead = SMB_HEADER_LEN + 14 * sizeof(__u16) + 2 + 1 + 2;
 	int size = smb_get_xmitsize(server, overhead);
 
-	VERBOSE("packet=%d, xmit=%d, size=%d\n",
-		server->packet_size, server->opt.max_xmit, size);
+	VERBOSE("xmit=%d, size=%d\n", server->opt.max_xmit, size);
 
 	return size;
 }
@@ -641,14 +641,14 @@
  * Convert SMB error codes to -E... errno values.
  */
 int
-smb_errno(struct smb_sb_info *server)
+smb_errno(struct smb_request *req)
 {
-	int errcls = server->rcls;
-	int error  = server->err;
+	int errcls = req->rq_rcls;
+	int error  = req->rq_err;
 	char *class = "Unknown";
 
 	VERBOSE("errcls %d  code %d  from command 0x%x\n",
-		errcls, error, SMB_CMD(server->packet));
+		errcls, error, SMB_CMD(req->rq_header));
 
 	if (errcls == ERRDOS) {
 		switch (error) {
@@ -714,6 +714,7 @@
 		case ERRbadpw:
 			return -EINVAL;
 		case ERRbadtype:
+		case ERRtimeout:
 			return -EIO;
 		case ERRaccess:
 			return -EACCES;
@@ -759,138 +760,35 @@
 
 err_unknown:
 	printk(KERN_ERR "smb_errno: class %s, code %d from command 0x%x\n",
-	       class, error, SMB_CMD(server->packet));
+	       class, error, SMB_CMD(req->rq_header));
 	return -EIO;
 }
 
-/*
- * smb_retry: This function should be called when smb_request_ok has
- * indicated an error. If the error was indicated because the
- * connection was killed, we try to reconnect. If smb_retry returns 0,
- * the error was indicated for another reason, so a retry would not be
- * of any use.
- * N.B. The server must be locked for this call.
- */
-static int
-smb_retry(struct smb_sb_info *server)
-{
-	pid_t pid = server->conn_pid;
-	int error, result = 0;
-
-	if (server->state == CONN_VALID || server->state == CONN_RETRYING)
-		goto out;
-
-	smb_close_socket(server);
-
-	if (pid == 0) {
-		printk(KERN_ERR "smb_retry: no connection process\n");
-		server->state = CONN_RETRIED;
-		goto out;
-	}
-
-	/*
-	 * Change state so that only one retry per server will be started.
-	 */
-	server->state = CONN_RETRYING;
-
-	/*
-	 * Note: use the "priv" flag, as a user process may need to reconnect.
-	 */
-	error = kill_proc(pid, SIGUSR1, 1);
-	if (error) {
-		/* FIXME: this is fatal */
-		printk(KERN_ERR "smb_retry: signal failed, error=%d\n", error);
-		goto out;
-	}
-	VERBOSE("signalled pid %d, waiting for new connection\n", pid);
-
-	/*
-	 * Wait for the new connection.
-	 */
-#ifdef SMB_RETRY_INTR
-	smb_unlock_server(server);
-	interruptible_sleep_on_timeout(&server->wait,  30*HZ);
-	smb_lock_server(server);
-	if (signal_pending(current))
-		printk(KERN_INFO "smb_retry: caught signal\n");
-#else
-	/*
-	 * We don't want to be interrupted. For example, what if 'current'
-	 * already has received a signal? sleep_on would terminate immediately
-	 * and smbmount would not be able to re-establish connection.
-	 *
-	 * smbmount should be able to reconnect later, but it can't because
-	 * it will get an -EIO on attempts to open the mountpoint!
-	 *
-	 * FIXME: go back to the interruptable version now that smbmount
-	 * can avoid -EIO on the mountpoint when reconnecting?
-	 */
-	smb_unlock_server(server);
-	sleep_on_timeout(&server->wait, 30*HZ);
-	smb_lock_server(server);
-#endif
-
-	/*
-	 * Check for a valid connection.
-	 */
-	if (server->state == CONN_VALID) {
-		/* This should be changed to VERBOSE, except many smbfs
-		   problems is with the userspace daemon not reconnecting. */
-		PARANOIA("successful, new pid=%d, generation=%d\n",
-			 server->conn_pid, server->generation);
-		result = 1;
-	} else if (server->state == CONN_RETRYING) {
-		/* allow further attempts later */
-		server->state = CONN_RETRIED;
-	}
-
-out:
-	return result;
-}
-
 /* smb_request_ok: We expect the server to be locked. Then we do the
    request and check the answer completely. When smb_request_ok
    returns 0, you can be quite sure that everything went well. When
    the answer is <=0, the returned number is a valid unix errno. */
 
 static int
-smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc)
+smb_request_ok(struct smb_request *req, int command, int wct, int bcc)
 {
-	int result = -EIO;
-
-	s->rcls = 0;
-	s->err = 0;
+	int result;
 
-	/* Make sure we have a connection */
-	if (s->state != CONN_VALID) {
-		if (!smb_retry(s))
-			goto out;
-	}
+	req->rq_resp_wct = wct;
+	req->rq_resp_bcc = bcc;
 
-	if (smb_request(s) < 0) {
+	result = smb_add_request(req);
+	if (result != 0) {
 		DEBUG1("smb_request failed\n");
 		goto out;
 	}
-	if (smb_valid_packet(s->packet) != 0) {
+
+	if (smb_valid_packet(req->rq_header) != 0) {
 		PARANOIA("invalid packet!\n");
 		goto out;
 	}
 
-	/*
-	 * Check for server errors.
-	 */
-	if (s->rcls != 0) {
-		result = smb_errno(s);
-		if (!result)
-			printk(KERN_DEBUG "smb_request_ok: rcls=%d, err=%d mapped to 0\n",
-				s->rcls, s->err);
-		/*
-		 * Exit now even if the error was squashed ...
-		 * packet verify will fail anyway.
-		 */
-		goto out;
-	}
-	result = smb_verify(s->packet, command, wct, bcc);
+	result = smb_verify(req->rq_header, command, wct, bcc);
 
 out:
 	return result;
@@ -904,6 +802,7 @@
 smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
 {
 	struct file *filp;
+	struct sock *sk;
 	int error;
 
 	VERBOSE("fd=%d, pid=%d\n", opt->fd, current->pid);
@@ -931,12 +830,32 @@
 
 	server->sock_file = filp;
 	server->conn_pid = current->pid;
-	smb_catch_keepalive(server);
 	server->opt = *opt;
 	server->generation += 1;
 	server->state = CONN_VALID;
 	error = 0;
 
+	if (server->conn_error) {
+		/*
+		 * conn_error is the returncode we originally decided to
+		 * drop the old connection on. This message should be positive
+		 * and not make people ask questions on why smbfs is printing
+		 * error messages ...
+		 */
+		printk(KERN_INFO "SMB connection re-established (%d)\n",
+		       server->conn_error);
+		server->conn_error = 0;
+	}
+
+	/*
+	 * Store the server in sock user_data (Only used by sunrpc)
+	 */
+	sk = SOCKET_I(filp->f_dentry->d_inode)->sk;
+	sk->user_data = server;
+
+	/* chain into the data_ready callback */
+	server->data_ready = xchg(&sk->data_ready, smb_data_ready);
+
 	/* check if we have an old smbmount that uses seconds for the 
 	   serverzone */
 	if (server->opt.serverzone > 12*60 || server->opt.serverzone < -12*60)
@@ -999,28 +918,14 @@
 		server->opt.protocol, server->opt.max_xmit, server->conn_pid,
 		server->opt.capabilities);
 
-	/* Make sure we can fit a message of the negotiated size in our
-	   packet buffer. */
-	if (server->opt.max_xmit > server->packet_size) {
-		int len = smb_round_length(server->opt.max_xmit);
-		char *buf = smb_vmalloc(len);
-		if (buf) {
-			if (server->packet)
-				smb_vfree(server->packet);
-			server->packet = buf;
-			server->packet_size = len;
-		} else {
-			/* else continue with the too small buffer? */
-			PARANOIA("Failed to allocate new packet buffer: "
-				 "max_xmit=%d, packet_size=%d\n",
-				 server->opt.max_xmit, server->packet_size);
-			server->opt.max_xmit = server->packet_size;
-		}
+	/* FIXME: this really should be done by smbmount. */
+	if (server->opt.max_xmit > SMB_MAX_PACKET_SIZE) {
+		server->opt.max_xmit = SMB_MAX_PACKET_SIZE;
 	}
 
 out:
 	smb_unlock_server(server);
-	smb_wakeup(server);
+	smbiod_wake_up();
 	return error;
 
 out_putf:
@@ -1028,31 +933,15 @@
 	goto out;
 }
 
-int
-smb_wakeup(struct smb_sb_info *server)
-{
-#ifdef SMB_RETRY_INTR
-	wake_up_interruptible(&server->wait);
-#else
-	wake_up(&server->wait);
-#endif
-	return 0;
-}
-
 /* smb_setup_header: We completely set up the packet. You only have to
    insert the command-specific fields */
 
 __u8 *
-smb_setup_header(struct smb_sb_info * server, __u8 command, __u16 wct, __u16 bcc)
+smb_setup_header(struct smb_request *req, __u8 command, __u16 wct, __u16 bcc)
 {
 	__u32 xmit_len = SMB_HEADER_LEN + wct * sizeof(__u16) + bcc + 2;
-	__u8 *p = server->packet;
-	__u8 *buf = server->packet;
-
-	if (xmit_len > server->packet_size)
-		printk(KERN_DEBUG "smb_setup_header: "
-		       "Aieee, xmit len > packet! len=%d, size=%d\n",
-		       xmit_len, server->packet_size);
+	__u8 *p = req->rq_header;
+	struct smb_sb_info *server = req->rq_server;
 
 	p = smb_encode_smb_length(p, xmit_len - 4);
 
@@ -1066,67 +955,81 @@
 	p += 19;
 	p += 8;
 
-	WSET(buf, smb_tid, server->opt.tid);
-	WSET(buf, smb_pid, 1);
-	WSET(buf, smb_uid, server->opt.server_uid);
-	WSET(buf, smb_mid, 1);
+	/* FIXME: the request will fail if the 'tid' is changed. This
+	   should perhaps be set just before transmitting ... */
+	WSET(req->rq_header, smb_tid, server->opt.tid);
+	WSET(req->rq_header, smb_pid, 1);
+	WSET(req->rq_header, smb_uid, server->opt.server_uid);
 
 	if (server->opt.protocol > SMB_PROTOCOL_CORE) {
 		int flags = SMB_FLAGS_CASELESS_PATHNAMES;
 		int flags2 = SMB_FLAGS2_LONG_PATH_COMPONENTS |
 			SMB_FLAGS2_EXTENDED_ATTRIBUTES;	/* EA? not really ... */
 
-		*(buf+smb_flg) = flags;
+		*(req->rq_header + smb_flg) = flags;
 		if (server->mnt->flags & SMB_MOUNT_UNICODE)
 			flags2 |= SMB_FLAGS2_UNICODE_STRINGS;
-		WSET(buf, smb_flg2, flags2);
+		WSET(req->rq_header, smb_flg2, flags2);
 	}
 	*p++ = wct;		/* wct */
 	p += 2 * wct;
 	WSET(p, 0, bcc);
-	return p + 2;
+
+	/* Include the header in the data to send */
+	req->rq_iovlen = 1;
+	req->rq_iov[0].iov_base = req->rq_header;
+	req->rq_iov[0].iov_len  = xmit_len - bcc;
+
+	return req->rq_buffer;
 }
 
 static void
-smb_setup_bcc(struct smb_sb_info *server, __u8 * p)
+smb_setup_bcc(struct smb_request *req, __u8 *p)
 {
-	__u8 *packet = server->packet;
-	__u8 *pbcc = packet + SMB_HEADER_LEN + 2 * SMB_WCT(packet);
-	__u16 bcc = p - (pbcc + 2);
+	u16 bcc = p - req->rq_buffer;
+	u8 *pbcc = req->rq_header + SMB_HEADER_LEN + 2*SMB_WCT(req->rq_header);
 
 	WSET(pbcc, 0, bcc);
-	smb_encode_smb_length(packet,
-			      SMB_HEADER_LEN + 2 * SMB_WCT(packet) - 2 + bcc);
+
+	smb_encode_smb_length(req->rq_header, SMB_HEADER_LEN + 
+			      2*SMB_WCT(req->rq_header) - 2 + bcc);
+
+	/* Include the "bytes" in the data to send */
+	req->rq_iovlen = 2;
+	req->rq_iov[1].iov_base = req->rq_buffer;
+	req->rq_iov[1].iov_len  = bcc;
 }
 
-/*
- * Called with the server locked
- */
 static int
 smb_proc_seek(struct smb_sb_info *server, __u16 fileid,
 	      __u16 mode, off_t offset)
 {
 	int result;
+	struct smb_request *req;
 
-	smb_setup_header(server, SMBlseek, 4, 0);
-	WSET(server->packet, smb_vwv0, fileid);
-	WSET(server->packet, smb_vwv1, mode);
-	DSET(server->packet, smb_vwv2, offset);
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, 0)))
+		goto out;
 
-	result = smb_request_ok(server, SMBlseek, 2, 0);
+	smb_setup_header(req, SMBlseek, 4, 0);
+	WSET(req->rq_header, smb_vwv0, fileid);
+	WSET(req->rq_header, smb_vwv1, mode);
+	DSET(req->rq_header, smb_vwv2, offset);
+	req->rq_flags |= SMB_REQ_NORETRY;
+
+	result = smb_request_ok(req, SMBlseek, 2, 0);
 	if (result < 0) {
 		result = 0;
-		goto out;
+		goto out_free;
 	}
 
-	result = DVAL(server->packet, smb_vwv0);
+	result = DVAL(req->rq_header, smb_vwv0);
+out_free:
+	smb_rput(req);
 out:
 	return result;
 }
 
-/*
- * We're called with the server locked, and we leave it that way.
- */
 static int
 smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
 {
@@ -1135,6 +1038,7 @@
 	int mode, read_write = 0x42, read_only = 0x40;
 	int res;
 	char *p;
+	struct smb_request *req;
 
 	/*
 	 * Attempt to open r/w, unless there are no write privileges.
@@ -1153,20 +1057,21 @@
 		mode = read_only;
 #endif
 
+	res = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
+		goto out;
+
       retry:
-	p = smb_setup_header(server, SMBopen, 2, 0);
-	WSET(server->packet, smb_vwv0, mode);
-	WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
-	res = smb_simple_encode_path(server, &p, dentry, NULL);
+	p = smb_setup_header(req, SMBopen, 2, 0);
+	WSET(req->rq_header, smb_vwv0, mode);
+	WSET(req->rq_header, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
+	res = smb_simple_encode_path(req, &p, dentry, NULL);
 	if (res < 0)
-		goto out;
-	smb_setup_bcc(server, p);
+		goto out_free;
+	smb_setup_bcc(req, p);
 
-	res = smb_request_ok(server, SMBopen, 7, 0);
+	res = smb_request_ok(req, SMBopen, 7, 0);
 	if (res != 0) {
-		if (smb_retry(server))
-			goto retry;
-
 		if (mode == read_write &&
 		    (res == -EACCES || res == -ETXTBSY || res == -EROFS))
 		{
@@ -1175,17 +1080,19 @@
 			mode = read_only;
 			goto retry;
 		}
-		goto out;
+		goto out_free;
 	}
 	/* We should now have data in vwv[0..6]. */
 
-	ei->fileid = WVAL(server->packet, smb_vwv0);
-	ei->attr   = WVAL(server->packet, smb_vwv1);
+	ei->fileid = WVAL(req->rq_header, smb_vwv0);
+	ei->attr   = WVAL(req->rq_header, smb_vwv1);
 	/* smb_vwv2 has mtime */
 	/* smb_vwv4 has size  */
-	ei->access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK);
+	ei->access = (WVAL(req->rq_header, smb_vwv6) & SMB_ACCMASK);
 	ei->open = server->generation;
 
+out_free:
+	smb_rput(req);
 out:
 	return res;
 }
@@ -1210,11 +1117,9 @@
 
 	if (!smb_is_open(inode)) {
 		struct smb_sb_info *server = server_from_inode(inode);
-		smb_lock_server(server);
 		result = 0;
 		if (!smb_is_open(inode))
 			result = smb_proc_open(server, dentry, wish);
-		smb_unlock_server(server);
 		if (result) {
 			PARANOIA("%s/%s open failed, result=%d\n",
 				 DENTRY_PATH(dentry), result);
@@ -1240,20 +1145,27 @@
 	return result;
 }
 
-/* We're called with the server locked */
-
 static int 
 smb_proc_close(struct smb_sb_info *server, __u16 fileid, __u32 mtime)
 {
-	smb_setup_header(server, SMBclose, 3, 0);
-	WSET(server->packet, smb_vwv0, fileid);
-	DSET(server->packet, smb_vwv1, utc2local(server, mtime));
-	return smb_request_ok(server, SMBclose, 0, 0);
+	struct smb_request *req;
+	int result = -ENOMEM;
+
+	if (! (req = smb_alloc_request(server, 0)))
+		goto out;
+
+	smb_setup_header(req, SMBclose, 3, 0);
+	WSET(req->rq_header, smb_vwv0, fileid);
+	DSET(req->rq_header, smb_vwv1, utc2local(server, mtime));
+	req->rq_flags |= SMB_REQ_NORETRY;
+	result = smb_request_ok(req, SMBclose, 0, 0);
+
+	smb_rput(req);
+out:
+	return result;
 }
 
 /*
- * Called with the server locked.
- *
  * Win NT 4.0 has an apparent bug in that it fails to update the
  * modify time when writing to a file. As a workaround, we update
  * both modify and access time locally, and post the times to the
@@ -1312,9 +1224,7 @@
 
 	if (smb_is_open(ino)) {
 		struct smb_sb_info *server = server_from_inode(ino);
-		smb_lock_server(server);
 		result = smb_proc_close_inode(server, ino);
-		smb_unlock_server(server);
 	}
 	return result;
 }
@@ -1329,15 +1239,26 @@
 	struct smb_sb_info *server = server_from_dentry(dentry);
 	int result;
 
-	smb_lock_server(server);
 	result = smb_proc_close(server, fileid, CURRENT_TIME);
-	smb_unlock_server(server);
 	return result;
 }
 
 /* In smb_proc_read and smb_proc_write we do not retry, because the
    file-id would not be valid after a reconnection. */
 
+static void
+smb_proc_read_data(struct smb_request *req)
+{
+	req->rq_iov[0].iov_base = req->rq_buffer;
+	req->rq_iov[0].iov_len  = 3;
+
+	req->rq_iov[1].iov_base = req->rq_page;
+	req->rq_iov[1].iov_len  = req->rq_rsize;
+	req->rq_iovlen = 2;
+
+	req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd;
+}
+
 static int
 smb_proc_read(struct inode *inode, loff_t offset, int count, char *data)
 {
@@ -1345,33 +1266,32 @@
 	__u16 returned_count, data_len;
 	unsigned char *buf;
 	int result;
+	struct smb_request *req;
+	u8 rbuf[4];
 
-	smb_lock_server(server);
-	smb_setup_header(server, SMBread, 5, 0);
-	buf = server->packet;
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, 0)))
+		goto out;
+
+	smb_setup_header(req, SMBread, 5, 0);
+	buf = req->rq_header;
 	WSET(buf, smb_vwv0, SMB_I(inode)->fileid);
 	WSET(buf, smb_vwv1, count);
 	DSET(buf, smb_vwv2, offset);
 	WSET(buf, smb_vwv4, 0);
 
-	result = smb_request_ok(server, SMBread, 5, -1);
-	if (result < 0)
-		goto out;
-	returned_count = WVAL(server->packet, smb_vwv0);
-
-	buf = SMB_BUF(server->packet);
-	data_len = WVAL(buf, 1);
+	req->rq_page = data;
+	req->rq_rsize = count;
+	req->rq_callback = smb_proc_read_data;
+	req->rq_buffer = rbuf;
+	req->rq_flags |= SMB_REQ_NORETRY | SMB_REQ_STATIC;
 
-	/* we can NOT simply trust the data_len given by the server ... */
-	if (data_len > server->packet_size - (buf+3 - server->packet)) {
-		printk(KERN_ERR "smb_proc_read: invalid data length!! "
-		       "%d > %d - (%p - %p)\n",
-		       data_len, server->packet_size, buf+3, server->packet);
-		result = -EIO;
-		goto out;
-	}
+	result = smb_request_ok(req, SMBread, 5, -1);
+	if (result < 0)
+		goto out_free;
+	returned_count = WVAL(req->rq_header, smb_vwv0);
 
-	memcpy(data, buf+3, data_len);
+	data_len = WVAL(rbuf, 1);
 
 	if (returned_count != data_len) {
 		printk(KERN_NOTICE "smb_proc_read: returned != data_len\n");
@@ -1380,10 +1300,11 @@
 	}
 	result = data_len;
 
+out_free:
+	smb_rput(req);
 out:
 	VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",
 		inode->i_ino, SMB_I(inode)->fileid, count, result);
-	smb_unlock_server(server);
 	return result;
 }
 
@@ -1392,29 +1313,38 @@
 {
 	struct smb_sb_info *server = server_from_inode(inode);
 	int result;
-	__u8 *p;
-	__u16 fileid = SMB_I(inode)->fileid;
+	u16 fileid = SMB_I(inode)->fileid;
+	u8 buf[4];
+	struct smb_request *req;
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, 0)))
+		goto out;
+
+	VERBOSE("ino=%ld, fileid=%d, count=%d@%Ld\n",
+		inode->i_ino, fileid, count, offset);
+
+	smb_setup_header(req, SMBwrite, 5, count + 3);
+	WSET(req->rq_header, smb_vwv0, fileid);
+	WSET(req->rq_header, smb_vwv1, count);
+	DSET(req->rq_header, smb_vwv2, offset);
+	WSET(req->rq_header, smb_vwv4, 0);
+
+	buf[0] = 1;
+	WSET(buf, 1, count);	/* yes, again ... */
+	req->rq_iov[1].iov_base = buf;
+	req->rq_iov[1].iov_len = 3;
+	req->rq_iov[2].iov_base = (char *) data;
+	req->rq_iov[2].iov_len = count;
+	req->rq_iovlen = 3;
+	req->rq_flags |= SMB_REQ_NORETRY;
 
-	VERBOSE("ino=%ld, fileid=%d, count=%d@%Ld, packet_size=%d\n",
-		inode->i_ino, SMB_I(inode)->fileid, count, offset,
-		server->packet_size);
-
-	smb_lock_server(server);
-	p = smb_setup_header(server, SMBwrite, 5, count + 3);
-	WSET(server->packet, smb_vwv0, fileid);
-	WSET(server->packet, smb_vwv1, count);
-	DSET(server->packet, smb_vwv2, offset);
-	WSET(server->packet, smb_vwv4, 0);
-
-	*p++ = 1;
-	WSET(p, 0, count);
-	memcpy(p+2, data, count);
-
-	result = smb_request_ok(server, SMBwrite, 1, 0);
+	result = smb_request_ok(req, SMBwrite, 1, 0);
 	if (result >= 0)
-		result = WVAL(server->packet, smb_vwv0);
+		result = WVAL(req->rq_header, smb_vwv0);
 
-	smb_unlock_server(server);
+	smb_rput(req);
+out:
 	return result;
 }
 
@@ -1422,17 +1352,51 @@
  * In smb_proc_readX and smb_proc_writeX we do not retry, because the
  * file-id would not be valid after a reconnection.
  */
+
+#define SMB_READX_MAX_PAD      64
+static void
+smb_proc_readX_data(struct smb_request *req)
+{
+	/* header length, excluding the netbios length (-4) */
+	int hdrlen = SMB_HEADER_LEN + req->rq_resp_wct*2 - 2;
+	int data_off = WVAL(req->rq_header, smb_vwv6);
+
+	/*
+	 * Some genius made the padding to the data bytes arbitrary.
+	 * So we must first calculate the amount of padding used by the server.
+	 */
+	data_off -= hdrlen;
+	if (data_off > SMB_READX_MAX_PAD) {
+		PARANOIA("offset is larger than max pad!\n");
+		PARANOIA("%d > %d\n", data_off, SMB_READX_MAX_PAD);
+		req->rq_rlen = req->rq_bufsize + 1;
+		return;
+	}
+	req->rq_iov[0].iov_base = req->rq_buffer;
+	req->rq_iov[0].iov_len  = data_off;
+
+	req->rq_iov[1].iov_base = req->rq_page;
+	req->rq_iov[1].iov_len  = req->rq_rsize;
+	req->rq_iovlen = 2;
+
+	req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd;
+}
+
 static int
 smb_proc_readX(struct inode *inode, loff_t offset, int count, char *data)
 {
 	struct smb_sb_info *server = server_from_inode(inode);
-	u16 data_len, data_off;
 	unsigned char *buf;
 	int result;
+	struct smb_request *req;
+	static char pad[SMB_READX_MAX_PAD];
 
-	smb_lock_server(server);
-	smb_setup_header(server, SMBreadX, 12, 0);
-	buf = server->packet;
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, 0)))
+		goto out;
+
+	smb_setup_header(req, SMBreadX, 12, 0);
+	buf = req->rq_header;
 	WSET(buf, smb_vwv0, 0x00ff);
 	WSET(buf, smb_vwv1, 0);
 	WSET(buf, smb_vwv2, SMB_I(inode)->fileid);
@@ -1444,27 +1408,21 @@
 	DSET(buf, smb_vwv10, (u32)(offset >> 32));      /* high 32 bits */
 	WSET(buf, smb_vwv11, 0);
 
-	result = smb_request_ok(server, SMBreadX, 12, -1);
-	if (result < 0)
-		goto out;
-	data_len = WVAL(server->packet, smb_vwv5);
-	data_off = WVAL(server->packet, smb_vwv6);
-	buf = smb_base(server->packet) + data_off;
-
-	/* we can NOT simply trust the info given by the server ... */
-	if (data_len > server->packet_size - (buf - server->packet)) {
-		printk(KERN_ERR "smb_proc_read: invalid data length!! "
-		       "%d > %d - (%p - %p)\n",
-		       data_len, server->packet_size, buf, server->packet);
-		result = -EIO;
-		goto out;
-	}
+	req->rq_page = data;
+	req->rq_rsize = count;
+	req->rq_callback = smb_proc_readX_data;
+	req->rq_buffer = pad;
+	req->rq_bufsize = SMB_READX_MAX_PAD;
+	req->rq_flags |= SMB_REQ_STATIC | SMB_REQ_NORETRY;
 
-	memcpy(data, buf, data_len);
-	result = data_len;
+	result = smb_request_ok(req, SMBreadX, 12, -1);
+	if (result < 0)
+		goto out_free;
+	result = WVAL(req->rq_header, smb_vwv5);
 
+out_free:
+	smb_rput(req);
 out:
-	smb_unlock_server(server);
 	VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",
 		inode->i_ino, SMB_I(inode)->fileid, count, result);
 	return result;
@@ -1476,33 +1434,42 @@
 	struct smb_sb_info *server = server_from_inode(inode);
 	int result;
 	u8 *p;
+	static u8 pad[4];
+	struct smb_request *req;
 
-	VERBOSE("ino=%ld, fileid=%d, count=%d@%Ld, packet_size=%d\n",
-		inode->i_ino, SMB_I(inode)->fileid, count, offset,
-		server->packet_size);
-
-	smb_lock_server(server);
-	p = smb_setup_header(server, SMBwriteX, 14, count + 2);
-	WSET(server->packet, smb_vwv0, 0x00ff);
-	WSET(server->packet, smb_vwv1, 0);
-	WSET(server->packet, smb_vwv2, SMB_I(inode)->fileid);
-	DSET(server->packet, smb_vwv3, (u32)offset);    /* low 32 bits */
-	DSET(server->packet, smb_vwv5, 0);
-	WSET(server->packet, smb_vwv7, 0);              /* write mode */
-	WSET(server->packet, smb_vwv8, 0);
-	WSET(server->packet, smb_vwv9, 0);
-	WSET(server->packet, smb_vwv10, count);         /* data length */
-	WSET(server->packet, smb_vwv11, p + 2 - smb_base(server->packet));
-	DSET(server->packet, smb_vwv12, (u32)(offset >> 32));
-	*p++ = 0;    /* FIXME: pad to short or long ... change +2 above also */
-	*p++ = 0;
-	memcpy(p, data, count);
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, 0)))
+		goto out;
 
-	result = smb_request_ok(server, SMBwriteX, 6, 0);
-	if (result >= 0)
-		result = WVAL(server->packet, smb_vwv2);
+	VERBOSE("ino=%ld, fileid=%d, count=%d@%Ld\n",
+		inode->i_ino, SMB_I(inode)->fileid, count, offset);
+
+	p = smb_setup_header(req, SMBwriteX, 14, count + 1);
+	WSET(req->rq_header, smb_vwv0, 0x00ff);
+	WSET(req->rq_header, smb_vwv1, 0);
+	WSET(req->rq_header, smb_vwv2, SMB_I(inode)->fileid);
+	DSET(req->rq_header, smb_vwv3, (u32)offset);	/* low 32 bits */
+	DSET(req->rq_header, smb_vwv5, 0);
+	WSET(req->rq_header, smb_vwv7, 0);		/* write mode */
+	WSET(req->rq_header, smb_vwv8, 0);
+	WSET(req->rq_header, smb_vwv9, 0);
+	WSET(req->rq_header, smb_vwv10, count);		/* data length */
+	WSET(req->rq_header, smb_vwv11, smb_vwv12 + 2 + 1);
+	DSET(req->rq_header, smb_vwv12, (u32)(offset >> 32));
+
+	req->rq_iov[1].iov_base = pad;
+	req->rq_iov[1].iov_len = 1;
+	req->rq_iov[2].iov_base = (char *) data;
+	req->rq_iov[2].iov_len = count;
+	req->rq_iovlen = 3;
+	req->rq_flags |= SMB_REQ_NORETRY;
+
+	result = smb_request_ok(req, SMBwriteX, 6, 0);
+ 	if (result >= 0)
+		result = WVAL(req->rq_header, smb_vwv2);
 
-	smb_unlock_server(server);
+	smb_rput(req);
+out:
 	return result;
 }
 
@@ -1512,29 +1479,30 @@
 	struct smb_sb_info *server = server_from_dentry(dentry);
 	char *p;
 	int result;
+	struct smb_request *req;
 
-	smb_lock_server(server);
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
+		goto out;
 
-      retry:
-	p = smb_setup_header(server, SMBcreate, 3, 0);
-	WSET(server->packet, smb_vwv0, attr);
-	DSET(server->packet, smb_vwv1, utc2local(server, ctime));
-	result = smb_simple_encode_path(server, &p, dentry, NULL);
+	p = smb_setup_header(req, SMBcreate, 3, 0);
+	WSET(req->rq_header, smb_vwv0, attr);
+	DSET(req->rq_header, smb_vwv1, utc2local(server, ctime));
+	result = smb_simple_encode_path(req, &p, dentry, NULL);
 	if (result < 0)
-		goto out;
-	smb_setup_bcc(server, p);
+		goto out_free;
+	smb_setup_bcc(req, p);
 
-	result = smb_request_ok(server, SMBcreate, 1, 0);
-	if (result < 0) {
-		if (smb_retry(server))
-			goto retry;
-		goto out;
-	}
-	*fileid = WVAL(server->packet, smb_vwv0);
+	result = smb_request_ok(req, SMBcreate, 1, 0);
+	if (result < 0)
+		goto out_free;
+
+	*fileid = WVAL(req->rq_header, smb_vwv0);
 	result = 0;
 
+out_free:
+	smb_rput(req);
 out:
-	smb_unlock_server(server);
 	return result;
 }
 
@@ -1544,28 +1512,29 @@
 	struct smb_sb_info *server = server_from_dentry(old_dentry);
 	char *p;
 	int result;
+	struct smb_request *req;
 
-	smb_lock_server(server);
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
+		goto out;
 
-      retry:
-	p = smb_setup_header(server, SMBmv, 1, 0);
-	WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN | aDIR);
-	result = smb_simple_encode_path(server, &p, old_dentry, NULL);
+	p = smb_setup_header(req, SMBmv, 1, 0);
+	WSET(req->rq_header, smb_vwv0, aSYSTEM | aHIDDEN | aDIR);
+	result = smb_simple_encode_path(req, &p, old_dentry, NULL);
 	if (result < 0)
-		goto out;
-	result = smb_simple_encode_path(server, &p, new_dentry, NULL);
+		goto out_free;
+	result = smb_simple_encode_path(req, &p, new_dentry, NULL);
 	if (result < 0)
-		goto out;
-	smb_setup_bcc(server, p);
+		goto out_free;
+	smb_setup_bcc(req, p);
 
-	if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) {
-		if (smb_retry(server))
-			goto retry;
-		goto out;
-	}
+	if ((result = smb_request_ok(req, SMBmv, 0, 0)) < 0)
+		goto out_free;
 	result = 0;
+
+out_free:
+	smb_rput(req);
 out:
-	smb_unlock_server(server);
 	return result;
 }
 
@@ -1578,25 +1547,26 @@
 	struct smb_sb_info *server = server_from_dentry(dentry);
 	char *p;
 	int result;
+	struct smb_request *req;
 
-	smb_lock_server(server);
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
+		goto out;
 
-      retry:
-	p = smb_setup_header(server, command, 0, 0);
-	result = smb_simple_encode_path(server, &p, dentry, NULL);
+	p = smb_setup_header(req, command, 0, 0);
+	result = smb_simple_encode_path(req, &p, dentry, NULL);
 	if (result < 0)
-		goto out;
-	smb_setup_bcc(server, p);
+		goto out_free;
+	smb_setup_bcc(req, p);
 
-	result = smb_request_ok(server, command, 0, 0);
-	if (result < 0) {
-		if (smb_retry(server))
-			goto retry;
-		goto out;
-	}
+	result = smb_request_ok(req, command, 0, 0);
+	if (result < 0)
+		goto out_free;
 	result = 0;
+
+out_free:
+	smb_rput(req);
 out:
-	smb_unlock_server(server);
 	return result;
 }
 
@@ -1616,7 +1586,6 @@
 /*
  * Removes readonly attribute from a file. Used by unlink to give posix
  * semantics.
- * Note: called with the server locked.
  */
 static int
 smb_set_rw(struct dentry *dentry,struct smb_sb_info *server)
@@ -1647,18 +1616,21 @@
 	int flag = 0;
 	char *p;
 	int result;
+	struct smb_request *req;
 
-	smb_lock_server(server);
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
+		goto out;
 
       retry:
-	p = smb_setup_header(server, SMBunlink, 1, 0);
-	WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
-	result = smb_simple_encode_path(server, &p, dentry, NULL);
+	p = smb_setup_header(req, SMBunlink, 1, 0);
+	WSET(req->rq_header, smb_vwv0, aSYSTEM | aHIDDEN);
+	result = smb_simple_encode_path(req, &p, dentry, NULL);
 	if (result < 0)
-		goto out;
-	smb_setup_bcc(server, p);
+		goto out_free;
+	smb_setup_bcc(req, p);
 
-	if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) {
+	if ((result = smb_request_ok(req, SMBunlink, 0, 0)) < 0) {
 #if SMBFS_POSIX_UNLINK
 		if (result == -EACCES && !flag) {
 			/* Posix semantics is for the read-only state
@@ -1681,25 +1653,34 @@
 			}
 		}
 #endif
-		if (smb_retry(server))
-			goto retry;
-		goto out;
+		goto out_free;
 	}
 	result = 0;
+
+out_free:
+	smb_rput(req);
 out:
-	smb_unlock_server(server);
 	return result;
 }
 
-/*
- * Called with the server locked
- */
 int
 smb_proc_flush(struct smb_sb_info *server, __u16 fileid)
 {
-	smb_setup_header(server, SMBflush, 1, 0);
-	WSET(server->packet, smb_vwv0, fileid);
-	return smb_request_ok(server, SMBflush, 0, 0);
+	int result;
+	struct smb_request *req;
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, 0)))
+		goto out;
+
+	smb_setup_header(req, SMBflush, 1, 0);
+	WSET(req->rq_header, smb_vwv0, fileid);
+	req->rq_flags |= SMB_REQ_NORETRY;
+	result = smb_request_ok(req, SMBflush, 0, 0);
+
+	smb_rput(req);
+out:
+	return result;
 }
 
 static int
@@ -1717,39 +1698,41 @@
 smb_proc_trunc64(struct inode *inode, loff_t length)
 {
 	struct smb_sb_info *server = server_from_inode(inode);
-	int command;
 	int result;
-	char *param = server->temp_buf;
-	char data[8];
-	unsigned char *resp_data = NULL;
-	unsigned char *resp_param = NULL;
-	int resp_data_len = 0;
-	int resp_param_len = 0;
+	char *param;
+	char *data;
+	struct smb_request *req;
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, 14)))
+		goto out;
+
+	param = req->rq_buffer;
+	data = req->rq_buffer + 6;
 
-	smb_lock_server(server);
-	command = TRANSACT2_SETFILEINFO;
- 
 	/* FIXME: must we also set allocation size? winNT seems to do that */
-retry:
 	WSET(param, 0, SMB_I(inode)->fileid);
 	WSET(param, 2, SMB_SET_FILE_END_OF_FILE_INFO);
 	WSET(param, 4, 0);
 	LSET(data, 0, length);
-	result = smb_trans2_request(server, command,
-				    8, data, 6, param,
-				    &resp_data_len, &resp_data,
-				    &resp_param_len, &resp_param);
-	if (result < 0) {
-		if (smb_retry(server))
-			goto retry;
-		goto out;
-	}
+
+	req->rq_trans2_command = TRANSACT2_SETFILEINFO;
+	req->rq_ldata = 8;
+	req->rq_data  = data;
+	req->rq_lparm = 6;
+	req->rq_parm  = param;
+	req->rq_flags |= SMB_REQ_NORETRY;
+	result = smb_add_request(req);
+	if (result < 0)
+		goto out_free;
+
 	result = 0;
-	if (server->rcls != 0)
-		result = smb_errno(server);
+	if (req->rq_rcls != 0)
+		result = smb_errno(req);
 
+out_free:
+	smb_rput(req);
 out:
-	smb_unlock_server(server);
 	return result;
 }
 
@@ -1766,9 +1749,7 @@
 	 *
 	 * FIXME: is this still necessary?
 	 */
-	smb_lock_server(server);
 	smb_proc_flush(server, SMB_I(inode)->fileid);
-	smb_unlock_server(server);
 	return result;
 }
 
@@ -1824,7 +1805,8 @@
  */
 static char *
 smb_decode_short_dirent(struct smb_sb_info *server, char *p,
-			struct qstr *qname, struct smb_fattr *fattr)
+			struct qstr *qname, struct smb_fattr *fattr,
+			unsigned char *name_buf)
 {
 	int len;
 
@@ -1867,12 +1849,12 @@
 #endif
 
 	qname->len = 0;
-	len = server->ops->convert(server->name_buf, SMB_MAXNAMELEN,
+	len = server->ops->convert(name_buf, SMB_MAXNAMELEN,
 				   qname->name, len,
 				   server->remote_nls, server->local_nls);
 	if (len > 0) {
 		qname->len = len;
-		qname->name = server->name_buf;
+		qname->name = name_buf;
 		DEBUG1("len=%d, name=%.*s\n",qname->len,qname->len,qname->name);
 	}
 
@@ -1904,28 +1886,36 @@
 		len:	3,
 	};
 	unsigned char *last_status;
+	struct smb_request *req;
+	unsigned char *name_buf;
 
 	VERBOSE("%s/%s\n", DENTRY_PATH(dir));
 
 	lock_kernel();
 
-	smb_lock_server(server);
+	result = -ENOMEM;
+	if (! (name_buf = kmalloc(SMB_MAXNAMELEN, GFP_KERNEL)))
+		goto out;
 
 	first = 1;
 	entries = 0;
 	entries_seen = 2; /* implicit . and .. */
 
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, server->opt.max_xmit)))
+		goto out_name;
+
 	while (1) {
-		p = smb_setup_header(server, SMBsearch, 2, 0);
-		WSET(server->packet, smb_vwv0, entries_asked);
-		WSET(server->packet, smb_vwv1, aDIR);
+		p = smb_setup_header(req, SMBsearch, 2, 0);
+		WSET(req->rq_header, smb_vwv0, entries_asked);
+		WSET(req->rq_header, smb_vwv1, aDIR);
 		if (first == 1) {
-			result = smb_simple_encode_path(server, &p, dir, &mask);
+			result = smb_simple_encode_path(req, &p, dir, &mask);
 			if (result < 0)
-				goto unlock_return;
-			if (p + 3 > (char*)server->packet+server->packet_size) {
+				goto out_free;
+			if (p + 3 > (char *)req->rq_buffer + req->rq_bufsize) {
 				result = -ENAMETOOLONG;
-				goto unlock_return;
+				goto out_free;
 			}
 			*p++ = 5;
 			WSET(p, 0, 0);
@@ -1933,9 +1923,9 @@
 			first = 0;
 		} else {
 			if (p + 5 + SMB_STATUS_SIZE >
-			    (char*)server->packet + server->packet_size) {
+			    (char *)req->rq_buffer + req->rq_bufsize) {
 				result = -ENAMETOOLONG;
-				goto unlock_return;
+				goto out_free;
 			}
 				
 			*p++ = 4;
@@ -1947,44 +1937,38 @@
 			p += SMB_STATUS_SIZE;
 		}
 
-		smb_setup_bcc(server, p);
+		smb_setup_bcc(req, p);
 
-		result = smb_request_ok(server, SMBsearch, 1, -1);
+		result = smb_request_ok(req, SMBsearch, 1, -1);
 		if (result < 0) {
-			if ((server->rcls == ERRDOS) && 
-			    (server->err  == ERRnofiles))
+			if ((req->rq_rcls == ERRDOS) && 
+			    (req->rq_err  == ERRnofiles))
 				break;
-			if (smb_retry(server)) {
-				ctl->idx = -1;	/* retry */
-				result = 0;
-			}
-			goto unlock_return;
+			goto out_free;
 		}
-		p = SMB_VWV(server->packet);
-		count = WVAL(p, 0);
+		count = WVAL(req->rq_header, smb_vwv0);
 		if (count <= 0)
 			break;
 
 		result = -EIO;
-		bcc = WVAL(p, 2);
+		bcc = smb_bcc(req->rq_header);
 		if (bcc != count * SMB_DIRINFO_SIZE + 3)
-			goto unlock_return;
-		p += 7;
+			goto out_free;
+		p = req->rq_buffer + 3;
 
 
 		/* Make sure the response fits in the buffer. Fixed sized 
 		   entries means we don't have to check in the decode loop. */
 
-		last_status = SMB_BUF(server->packet) + 3 + (count - 1) *
-			SMB_DIRINFO_SIZE;
+		last_status = req->rq_buffer + 3 + (count-1) * SMB_DIRINFO_SIZE;
 
 		if (last_status + SMB_DIRINFO_SIZE >=
-		    server->packet + server->packet_size) {
+		    req->rq_buffer + req->rq_bufsize) {
 			printk(KERN_ERR "smb_proc_readdir_short: "
 			       "last dir entry outside buffer! "
 			       "%d@%p  %d@%p\n", SMB_DIRINFO_SIZE, last_status,
-			       server->packet_size, server->packet);
-			goto unlock_return;
+			       req->rq_bufsize, req->rq_buffer);
+			goto out_free;
 		}
 
 		/* Read the last entry into the status field. */
@@ -1995,7 +1979,7 @@
 
 		for (i = 0; i < count; i++) {
 			p = smb_decode_short_dirent(server, p, 
-						    &qname, &fattr);
+						    &qname, &fattr, name_buf);
 			if (qname.len == 0)
 				continue;
 
@@ -2013,8 +1997,11 @@
 	}
 	result = entries;
 
-unlock_return:
-	smb_unlock_server(server);
+out_free:
+	smb_rput(req);
+out_name:
+	kfree(name_buf);
+out:
 	unlock_kernel();
 	return result;
 }
@@ -2032,7 +2019,8 @@
  */
 static char *
 smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level,
-		       struct qstr *qname, struct smb_fattr *fattr)
+		       struct qstr *qname, struct smb_fattr *fattr,
+		       unsigned char *name_buf)
 {
 	char *result;
 	unsigned int len = 0;
@@ -2114,12 +2102,12 @@
 #endif
 
 	qname->len = 0;
-	n = server->ops->convert(server->name_buf, SMB_MAXNAMELEN,
+	n = server->ops->convert(name_buf, SMB_MAXNAMELEN,
 				 qname->name, len,
 				 server->remote_nls, server->local_nls);
 	if (n > 0) {
 		qname->len = n;
-		qname->name = server->name_buf;
+		qname->name = name_buf;
 	}
 
 out:
@@ -2153,7 +2141,7 @@
 	struct smb_fattr fattr;
 
 	unsigned char *p, *lastname;
-	char *mask, *param = server->temp_buf;
+	char *mask, *param;
 	__u16 command;
 	int first, entries_seen;
 
@@ -2161,16 +2149,15 @@
 	int info_level = 260;
 	const int max_matches = 512;
 
-	unsigned char *resp_data = NULL;
-	unsigned char *resp_param = NULL;
-	int resp_data_len = 0;
-	int resp_param_len = 0;
-	int ff_searchcount = 0;
-	int ff_eos = 0;
-	int ff_lastname = 0;
-	int ff_dir_handle = 0;
-	int loop_count = 0;
-	int mask_len, i, result;
+	unsigned int ff_searchcount = 0;
+	unsigned int ff_eos = 0;
+	unsigned int ff_lastname = 0;
+	unsigned int ff_dir_handle = 0;
+	unsigned int loop_count = 0;
+	unsigned int mask_len, i;
+	int result;
+	struct smb_request *req;
+	unsigned char *name_buf;
 	static struct qstr star = {
 		name:	"*",
 		len:	1,
@@ -2184,7 +2171,12 @@
 	if (server->opt.protocol < SMB_PROTOCOL_NT1)
 		info_level = 1;
 
-	smb_lock_server(server);
+	result = -ENOMEM;
+	if (! (name_buf = kmalloc(SMB_MAXNAMELEN+2, GFP_KERNEL)))
+		goto out;
+	if (! (req = smb_alloc_request(server, server->opt.max_xmit)))
+		goto out_name;
+	param = req->rq_buffer;
 
 	/*
 	 * Encode the initial path
@@ -2194,7 +2186,7 @@
 	mask_len = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dir, &star);
 	if (mask_len < 0) {
 		result = mask_len;
-		goto unlock_return;
+		goto out_free;
 	}
 	mask_len--;	/* mask_len is strlen, not #bytes */
 	first = 1;
@@ -2223,8 +2215,8 @@
 		} else {
 			command = TRANSACT2_FINDNEXT;
 
-			VERBOSE("handle=0x%X, lastname=%d, mask=%s\n",
-				ff_dir_handle, ff_lastname, mask);
+			VERBOSE("handle=0x%X, lastname=%d, mask=%.*s\n",
+				ff_dir_handle, ff_lastname, mask_len, mask);
 
 			WSET(param, 0, ff_dir_handle);	/* search handle */
 			WSET(param, 2, max_matches);	/* max count */
@@ -2233,23 +2225,19 @@
 			WSET(param, 10, SMB_CONTINUE_BIT|SMB_CLOSE_IF_END);
 		}
 
-		result = smb_trans2_request(server, command,
-					    0, NULL, 12 + mask_len + 1, param,
-					    &resp_data_len, &resp_data,
-					    &resp_param_len, &resp_param);
-
+		req->rq_trans2_command = command;
+		req->rq_ldata = 0;
+		req->rq_data  = NULL;
+		req->rq_lparm = 12 + mask_len + 1;
+		req->rq_parm  = param;
+		req->rq_flags = 0;
+		result = smb_add_request(req);
 		if (result < 0) {
-			if (smb_retry(server)) {
-				PARANOIA("error=%d, retrying\n", result);
-				ctl->idx = -1;	/* retry */
-				result = 0;
-				goto unlock_return;
-			}
 			PARANOIA("error=%d, breaking\n", result);
 			break;
 		}
 
-		if (server->rcls == ERRSRV && server->err == ERRerror) {
+		if (req->rq_rcls == ERRSRV && req->rq_err == ERRerror) {
 			/* a damn Win95 bug - sometimes it clags if you 
 			   ask it too fast */
 			current->state = TASK_INTERRUPTIBLE;
@@ -2257,8 +2245,8 @@
 			continue;
                 }
 
-		if (server->rcls != 0) {
-			result = smb_errno(server);
+		if (req->rq_rcls != 0) {
+			result = smb_errno(req);
 			PARANOIA("name=%s, result=%d, rcls=%d, err=%d\n",
 				 mask, result, server->rcls, server->err);
 			break;
@@ -2266,19 +2254,53 @@
 
 		/* parse out some important return info */
 		if (first != 0) {
-			ff_dir_handle = WVAL(resp_param, 0);
-			ff_searchcount = WVAL(resp_param, 2);
-			ff_eos = WVAL(resp_param, 4);
-			ff_lastname = WVAL(resp_param, 8);
+			ff_dir_handle = WVAL(req->rq_parm, 0);
+			ff_searchcount = WVAL(req->rq_parm, 2);
+			ff_eos = WVAL(req->rq_parm, 4);
+			ff_lastname = WVAL(req->rq_parm, 8);
 		} else {
-			ff_searchcount = WVAL(resp_param, 0);
-			ff_eos = WVAL(resp_param, 2);
-			ff_lastname = WVAL(resp_param, 6);
+			ff_searchcount = WVAL(req->rq_parm, 0);
+			ff_eos = WVAL(req->rq_parm, 2);
+			ff_lastname = WVAL(req->rq_parm, 6);
 		}
 
 		if (ff_searchcount == 0)
 			break;
 
+		/* Now we are ready to parse smb directory entries. */
+
+		/* point to the data bytes */
+		p = req->rq_data;
+		for (i = 0; i < ff_searchcount; i++) {
+			/* make sure we stay within the buffer */
+			if (p >= req->rq_data + req->rq_ldata) {
+				printk(KERN_ERR "smb_proc_readdir_long: "
+				       "dirent pointer outside buffer! "
+				       "%p  %d@%p\n",
+				       p, req->rq_ldata, req->rq_data);
+				result = -EIO; /* always a comm. error? */
+				goto out_free;
+			}
+
+			p = smb_decode_long_dirent(server, p, info_level,
+						   &qname, &fattr, name_buf);
+
+			/* ignore . and .. from the server */
+			if (entries_seen == 2 && qname.name[0] == '.') {
+				if (qname.len == 1)
+					continue;
+				if (qname.name[1] == '.' && qname.len == 2)
+					continue;
+			}
+
+			if (!smb_fill_cache(filp, dirent, filldir, ctl, 
+					    &qname, &fattr))
+				;	/* stop reading? */
+			entries_seen++;
+		}
+
+		VERBOSE("received %d entries, eos=%d\n", ff_searchcount,ff_eos);
+
 		/*
 		 * We might need the lastname for continuations.
 		 *
@@ -2293,18 +2315,18 @@
 		 * Both are happy if we return the data they point to. So we do.
 		 */
 		mask_len = 0;
-		if (ff_lastname > 0 && ff_lastname < resp_data_len) {
-			lastname = resp_data + ff_lastname;
+		if (ff_lastname > 0 && ff_lastname < req->rq_ldata) {
+			lastname = req->rq_data + ff_lastname;
 
 			switch (info_level) {
 			case 260:
-				mask_len = resp_data_len - ff_lastname;
+				mask_len = req->rq_ldata - ff_lastname;
 				break;
 			case 1:
 				/* lastname points to a length byte */
 				mask_len = *lastname++;
-				if (ff_lastname + 1 + mask_len > resp_data_len)
-					mask_len = resp_data_len - ff_lastname - 1;
+				if (ff_lastname + 1 + mask_len > req->rq_ldata)
+					mask_len = req->rq_ldata - ff_lastname - 1;
 				break;
 			}
 
@@ -2320,49 +2342,17 @@
 		}
 		mask_len = strnlen(mask, mask_len);
 		VERBOSE("new mask, len=%d@%d of %d, mask=%.*s\n",
-			mask_len, ff_lastname, resp_data_len, mask_len, mask);
-
-		/* Now we are ready to parse smb directory entries. */
-
-		/* point to the data bytes */
-		p = resp_data;
-		for (i = 0; i < ff_searchcount; i++) {
-			/* make sure we stay within the buffer */
-			if (p >= resp_data + resp_data_len) {
-				printk(KERN_ERR "smb_proc_readdir_long: "
-				       "dirent pointer outside buffer! "
-				       "%p  %d@%p  %d@%p\n",
-				       p, resp_data_len, resp_data,
-				       server->packet_size, server->packet);
-				result = -EIO; /* always a comm. error? */
-				goto unlock_return;
-			}
-
-			p = smb_decode_long_dirent(server, p, info_level,
-						   &qname, &fattr);
-
-			/* ignore . and .. from the server */
-			if (entries_seen == 2 && qname.name[0] == '.') {
-				if (qname.len == 1)
-					continue;
-				if (qname.name[1] == '.' && qname.len == 2)
-					continue;
-			}
-
-			if (!smb_fill_cache(filp, dirent, filldir, ctl, 
-					    &qname, &fattr))
-				;	/* stop reading? */
-			entries_seen++;
-		}
-
-		VERBOSE("received %d entries, eos=%d\n", ff_searchcount,ff_eos);
+			mask_len, ff_lastname, req->rq_ldata, mask_len, mask);
 
 		first = 0;
 		loop_count = 0;
 	}
 
-unlock_return:
-	smb_unlock_server(server);
+out_free:
+	smb_rput(req);
+out_name:
+	kfree(name_buf);
+out:
 	unlock_kernel();
 	return result;
 }
@@ -2370,7 +2360,6 @@
 /*
  * This version uses the trans2 TRANSACT2_FINDFIRST message 
  * to get the attribute data.
- * Note: called with the server locked.
  *
  * Bugs Noted:
  */
@@ -2378,19 +2367,21 @@
 smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry,
 			struct smb_fattr *fattr)
 {
-	char *param = server->temp_buf, *mask = param + 12;
+	char *param, *mask;
 	__u16 date, time;
-	unsigned char *resp_data = NULL;
-	unsigned char *resp_param = NULL;
-	int resp_data_len = 0;
-	int resp_param_len = 0;
 	int mask_len, result;
+	struct smb_request *req;
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
+		goto out;
+	param = req->rq_buffer;
+	mask = param + 12;
 
-retry:
 	mask_len = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dentry,NULL);
 	if (mask_len < 0) {
 		result = mask_len;
-		goto out;
+		goto out_free;
 	}
 	VERBOSE("name=%s, len=%d\n", mask, mask_len);
 	WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
@@ -2399,86 +2390,82 @@
 	WSET(param, 6, 1);	/* info_level */
 	DSET(param, 8, 0);
 
-	result = smb_trans2_request(server, TRANSACT2_FINDFIRST,
-				    0, NULL, 12 + mask_len, param,
-				    &resp_data_len, &resp_data,
-				    &resp_param_len, &resp_param);
+	req->rq_trans2_command = TRANSACT2_FINDFIRST;
+	req->rq_ldata = 0;
+	req->rq_data  = NULL;
+	req->rq_lparm = 12 + mask_len;
+	req->rq_parm  = param;
+	req->rq_flags = 0;
+	result = smb_add_request(req);
 	if (result < 0)
-	{
-		if (smb_retry(server))
-			goto retry;
-		goto out;
-	}
-	if (server->rcls != 0)
-	{ 
-		result = smb_errno(server);
+		goto out_free;
+	if (server->rcls != 0) {
+		result = smb_errno(req);
 #ifdef SMBFS_PARANOIA
 		if (result != -ENOENT)
 			PARANOIA("error for %s, rcls=%d, err=%d\n",
-				 mask, server->rcls, server->err);
+				 mask, req->rq_rcls, req->rq_err);
 #endif
-		goto out;
+		goto out_free;
 	}
 	/* Make sure we got enough data ... */
 	result = -EINVAL;
-	if (resp_data_len < 22 || WVAL(resp_param, 2) != 1)
-	{
+	if (req->rq_ldata < 22 || WVAL(req->rq_parm, 2) != 1) {
 		PARANOIA("bad result for %s, len=%d, count=%d\n",
-			 mask, resp_data_len, WVAL(resp_param, 2));
-		goto out;
+			 mask, req->rq_ldata, WVAL(req->rq_parm, 2));
+		goto out_free;
 	}
 
 	/*
 	 * Decode the response into the fattr ...
 	 */
-	date = WVAL(resp_data, 0);
-	time = WVAL(resp_data, 2);
+	date = WVAL(req->rq_data, 0);
+	time = WVAL(req->rq_data, 2);
 	fattr->f_ctime = date_dos2unix(server, date, time);
 
-	date = WVAL(resp_data, 4);
-	time = WVAL(resp_data, 6);
+	date = WVAL(req->rq_data, 4);
+	time = WVAL(req->rq_data, 6);
 	fattr->f_atime = date_dos2unix(server, date, time);
 
-	date = WVAL(resp_data, 8);
-	time = WVAL(resp_data, 10);
+	date = WVAL(req->rq_data, 8);
+	time = WVAL(req->rq_data, 10);
 	fattr->f_mtime = date_dos2unix(server, date, time);
 	VERBOSE("name=%s, date=%x, time=%x, mtime=%ld\n",
 		mask, date, time, fattr->f_mtime);
-	fattr->f_size = DVAL(resp_data, 12);
+	fattr->f_size = DVAL(req->rq_data, 12);
 	/* ULONG allocation size */
-	fattr->attr = WVAL(resp_data, 20);
+	fattr->attr = WVAL(req->rq_data, 20);
 	result = 0;
 
+out_free:
+	smb_rput(req);
 out:
 	return result;
 }
 
-/*
- * Note: called with the server locked.
- */
 static int
 smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
 		      struct smb_fattr *fattr)
 {
 	int result;
 	char *p;
+	struct smb_request *req;
 
-      retry:
-	p = smb_setup_header(server, SMBgetatr, 0, 0);
-	result = smb_simple_encode_path(server, &p, dir, NULL);
-	if (result < 0)
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
 		goto out;
-	smb_setup_bcc(server, p);
 
-	if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
-	{
-		if (smb_retry(server))
-			goto retry;
-		goto out;
-	}
-	fattr->attr    = WVAL(server->packet, smb_vwv0);
-	fattr->f_mtime = local2utc(server, DVAL(server->packet, smb_vwv1));
-	fattr->f_size  = DVAL(server->packet, smb_vwv3);
+	p = smb_setup_header(req, SMBgetatr, 0, 0);
+	result = smb_simple_encode_path(req, &p, dir, NULL);
+	if (result < 0)
+ 		goto out_free;
+	smb_setup_bcc(req, p);
+
+	if ((result = smb_request_ok(req, SMBgetatr, 10, 0)) < 0)
+		goto out_free;
+	fattr->attr    = WVAL(req->rq_header, smb_vwv0);
+	fattr->f_mtime = local2utc(server, DVAL(req->rq_header, smb_vwv1));
+	fattr->f_size  = DVAL(req->rq_header, smb_vwv3);
 	fattr->f_ctime = fattr->f_mtime; 
 	fattr->f_atime = fattr->f_mtime; 
 #ifdef SMBFS_DEBUG_TIMESTAMP
@@ -2487,26 +2474,24 @@
 #endif
 	result = 0;
 
+out_free:
+	smb_rput(req);
 out:
 	return result;
 }
 
 /*
- * Note: called with the server locked.
- *
  * Bugs Noted:
  * (1) Win 95 swaps the date and time fields in the standard info level.
  */
 static int
 smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
-			int *lrdata, unsigned char **rdata,
-			int *lrparam, unsigned char **rparam,
-			int infolevel)
+			struct smb_request *req, int infolevel)
 {
-	char *p, *param = server->temp_buf;
+	char *p, *param;
 	int result;
 
-retry:
+	param = req->rq_buffer;
 	WSET(param, 0, infolevel);
 	DSET(param, 2, 0);
 	result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
@@ -2514,28 +2499,25 @@
 		goto out;
 	p = param + 6 + result;
 
-	result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
-				    0, NULL, p - param, param,
-				    lrdata, rdata,
-				    lrparam, rparam);
+	req->rq_trans2_command = TRANSACT2_QPATHINFO;
+	req->rq_ldata = 0;
+	req->rq_data  = NULL;
+	req->rq_lparm = p - param;
+	req->rq_parm  = param;
+	req->rq_flags = 0;
+	result = smb_add_request(req);
 	if (result < 0)
-	{
-		if (smb_retry(server))
-			goto retry;
 		goto out;
-	}
-	if (server->rcls != 0)
-	{
+	if (server->rcls != 0) {
 		VERBOSE("for %s: result=%d, rcls=%d, err=%d\n",
-			&param[6], result, server->rcls, server->err);
-		result = smb_errno(server);
+			&param[6], result, req->rq_rcls, req->rq_err);
+		result = smb_errno(req);
 		goto out;
 	}
 	result = -ENOENT;
-	if (*lrdata < 22)
-	{
+	if (req->rq_ldata < 22) {
 		PARANOIA("not enough data for %s, len=%d\n",
-			 &param[6], *lrdata);
+			 &param[6], req->rq_ldata);
 		goto out;
 	}
 
@@ -2550,18 +2532,17 @@
 {
 	u16 date, time;
 	int off_date = 0, off_time = 2;
-	unsigned char *resp_data = NULL;
-	unsigned char *resp_param = NULL;
-	int resp_data_len = 0;
-	int resp_param_len = 0;
-
-	int result = smb_proc_getattr_trans2(server, dir,
-					     &resp_data_len, &resp_data,
-					     &resp_param_len, &resp_param,
-					     SMB_INFO_STANDARD);
-	if (result < 0)
+	int result;
+	struct smb_request *req;
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
 		goto out;
 
+	result = smb_proc_getattr_trans2(server, dir, req, SMB_INFO_STANDARD);
+	if (result < 0)
+		goto out_free;
+
 	/*
 	 * Kludge alert: Win 95 swaps the date and time field,
 	 * contrary to the CIFS docs and Win NT practice.
@@ -2570,24 +2551,26 @@
 		off_date = 2;
 		off_time = 0;
 	}
-	date = WVAL(resp_data, off_date);
-	time = WVAL(resp_data, off_time);
+	date = WVAL(req->rq_data, off_date);
+	time = WVAL(req->rq_data, off_time);
 	attr->f_ctime = date_dos2unix(server, date, time);
 
-	date = WVAL(resp_data, 4 + off_date);
-	time = WVAL(resp_data, 4 + off_time);
+	date = WVAL(req->rq_data, 4 + off_date);
+	time = WVAL(req->rq_data, 4 + off_time);
 	attr->f_atime = date_dos2unix(server, date, time);
 
-	date = WVAL(resp_data, 8 + off_date);
-	time = WVAL(resp_data, 8 + off_time);
+	date = WVAL(req->rq_data, 8 + off_date);
+	time = WVAL(req->rq_data, 8 + off_time);
 	attr->f_mtime = date_dos2unix(server, date, time);
 #ifdef SMBFS_DEBUG_TIMESTAMP
 	printk(KERN_DEBUG "getattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n",
 	       DENTRY_PATH(dir), date, time, attr->f_mtime);
 #endif
-	attr->f_size = DVAL(resp_data, 12);
-	attr->attr = WVAL(resp_data, 20);
+	attr->f_size = DVAL(req->rq_data, 12);
+	attr->attr = WVAL(req->rq_data, 20);
 
+out_free:
+	smb_rput(req);
 out:
 	return result;
 }
@@ -2596,27 +2579,29 @@
 smb_proc_getattr_trans2_all(struct smb_sb_info *server, struct dentry *dir,
 			    struct smb_fattr *attr)
 {
-	unsigned char *resp_data = NULL;
-	unsigned char *resp_param = NULL;
-	int resp_data_len = 0;
-	int resp_param_len = 0;
- 
-	int result = smb_proc_getattr_trans2(server, dir,
-					     &resp_data_len, &resp_data,
-					     &resp_param_len, &resp_param,
-					     SMB_QUERY_FILE_ALL_INFO);
-	if (result < 0)
+	struct smb_request *req;
+	int result;
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
 		goto out;
- 
-	attr->f_ctime = smb_ntutc2unixutc(LVAL(resp_data, 0));
-	attr->f_atime = smb_ntutc2unixutc(LVAL(resp_data, 8));
-	attr->f_mtime = smb_ntutc2unixutc(LVAL(resp_data, 16));
+
+	result = smb_proc_getattr_trans2(server, dir, req,
+					 SMB_QUERY_FILE_ALL_INFO);
+	if (result < 0)
+		goto out_free;
+
+	attr->f_ctime = smb_ntutc2unixutc(LVAL(req->rq_data, 0));
+	attr->f_atime = smb_ntutc2unixutc(LVAL(req->rq_data, 8));
+	attr->f_mtime = smb_ntutc2unixutc(LVAL(req->rq_data, 16));
 	/* change (24) */
-	attr->attr = WVAL(resp_data, 32);
+	attr->attr = WVAL(req->rq_data, 32);
 	/* pad? (34) */
 	/* allocated size (40) */
-	attr->f_size = LVAL(resp_data, 48);
+	attr->f_size = LVAL(req->rq_data, 48);
 
+out_free:
+	smb_rput(req);
 out:
 	return result;
 }
@@ -2656,21 +2641,17 @@
 	struct smb_sb_info *server = server_from_dentry(dir);
 	int result;
 
-	smb_lock_server(server);
-
 	smb_init_dirent(server, fattr);
 	result = server->ops->getattr(server, dir, fattr);
 	smb_finish_dirent(server, fattr);
 
-	smb_unlock_server(server);
 	return result;
 }
 
 
 /*
- * Called with the server locked. Because of bugs in the
- * core protocol, we use this only to set attributes. See
- * smb_proc_settime() below for timestamp handling.
+ * Because of bugs in the core protocol, we use this only to set
+ * attributes. See smb_proc_settime() below for timestamp handling.
  *
  * Bugs Noted:
  * (1) If mtime is non-zero, both Win 3.1 and Win 95 fail
@@ -2685,34 +2666,38 @@
 {
 	char *p;
 	int result;
+	struct smb_request *req;
 
-      retry:
-	p = smb_setup_header(server, SMBsetatr, 8, 0);
-	WSET(server->packet, smb_vwv0, attr);
-	DSET(server->packet, smb_vwv1, 0); /* mtime */
-	WSET(server->packet, smb_vwv3, 0); /* reserved values */
-	WSET(server->packet, smb_vwv4, 0);
-	WSET(server->packet, smb_vwv5, 0);
-	WSET(server->packet, smb_vwv6, 0);
-	WSET(server->packet, smb_vwv7, 0);
-	result = smb_simple_encode_path(server, &p, dentry, NULL);
-	if (result < 0)
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
 		goto out;
-	if (p + 2 > (char *)server->packet + server->packet_size) {
+
+	p = smb_setup_header(req, SMBsetatr, 8, 0);
+	WSET(req->rq_header, smb_vwv0, attr);
+	DSET(req->rq_header, smb_vwv1, 0); /* mtime */
+	WSET(req->rq_header, smb_vwv3, 0); /* reserved values */
+	WSET(req->rq_header, smb_vwv4, 0);
+	WSET(req->rq_header, smb_vwv5, 0);
+	WSET(req->rq_header, smb_vwv6, 0);
+	WSET(req->rq_header, smb_vwv7, 0);
+	result = smb_simple_encode_path(req, &p, dentry, NULL);
+	if (result < 0)
+		goto out_free;
+	if (p + 2 > (char *)req->rq_buffer + req->rq_bufsize) {
 		result = -ENAMETOOLONG;
-		goto out;
+		goto out_free;
 	}
 	*p++ = 4;
 	*p++ = 0;
-	smb_setup_bcc(server, p);
+	smb_setup_bcc(req, p);
 
-	result = smb_request_ok(server, SMBsetatr, 0, 0);
-	if (result < 0) {
-		if (smb_retry(server))
-			goto retry;
-		goto out;
-	}
+	result = smb_request_ok(req, SMBsetatr, 0, 0);
+	if (result < 0)
+		goto out_free;
 	result = 0;
+
+out_free:
+	smb_rput(req);
 out:
 	return result;
 }
@@ -2730,15 +2715,12 @@
 
 	VERBOSE("setting %s/%s, open=%d\n", 
 		DENTRY_PATH(dir), smb_is_open(dir->d_inode));
-	smb_lock_server(server);
 	result = smb_proc_setattr_core(server, dir, fattr->attr);
-	smb_unlock_server(server);
 	return result;
 }
 
 /*
- * Called with the server locked. Sets the timestamps for an
- * file open with write permissions.
+ * Sets the timestamps for an file open with write permissions.
  */
 static int
 smb_proc_setattr_ext(struct smb_sb_info *server,
@@ -2746,38 +2728,40 @@
 {
 	__u16 date, time;
 	int result;
+	struct smb_request *req;
 
-      retry:
-	smb_setup_header(server, SMBsetattrE, 7, 0);
-	WSET(server->packet, smb_vwv0, SMB_I(inode)->fileid);
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, 0)))
+		goto out;
+
+	smb_setup_header(req, SMBsetattrE, 7, 0);
+	WSET(req->rq_header, smb_vwv0, SMB_I(inode)->fileid);
 	/* We don't change the creation time */
-	WSET(server->packet, smb_vwv1, 0);
-	WSET(server->packet, smb_vwv2, 0);
+	WSET(req->rq_header, smb_vwv1, 0);
+	WSET(req->rq_header, smb_vwv2, 0);
 	date_unix2dos(server, fattr->f_atime, &date, &time);
-	WSET(server->packet, smb_vwv3, date);
-	WSET(server->packet, smb_vwv4, time);
+	WSET(req->rq_header, smb_vwv3, date);
+	WSET(req->rq_header, smb_vwv4, time);
 	date_unix2dos(server, fattr->f_mtime, &date, &time);
-	WSET(server->packet, smb_vwv5, date);
-	WSET(server->packet, smb_vwv6, time);
+	WSET(req->rq_header, smb_vwv5, date);
+	WSET(req->rq_header, smb_vwv6, time);
 #ifdef SMBFS_DEBUG_TIMESTAMP
 	printk(KERN_DEBUG "smb_proc_setattr_ext: date=%d, time=%d, mtime=%ld\n",
 	       date, time, fattr->f_mtime);
 #endif
 
-	result = smb_request_ok(server, SMBsetattrE, 0, 0);
-	if (result < 0) {
-		if (smb_retry(server))
-			goto retry;
-		goto out;
-	}
+	req->rq_flags |= SMB_REQ_NORETRY;
+	result = smb_request_ok(req, SMBsetattrE, 0, 0);
+	if (result < 0)
+		goto out_free;
 	result = 0;
+out_free:
+	smb_rput(req);
 out:
 	return result;
 }
 
 /*
- * Note: called with the server locked.
- *
  * Bugs Noted:
  * (1) The TRANSACT2_SETPATHINFO message under Win NT 4.0 doesn't
  * set the file's attribute flags.
@@ -2787,20 +2771,21 @@
 			struct dentry *dir, struct smb_fattr *fattr)
 {
 	__u16 date, time;
-	char *p, *param = server->temp_buf;
-	unsigned char *resp_data = NULL;
-	unsigned char *resp_param = NULL;
-	int resp_data_len = 0;
-	int resp_param_len = 0;
+	char *p, *param;
 	int result;
 	char data[26];
+	struct smb_request *req;
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
+		goto out;
+	param = req->rq_buffer;
 
-      retry:
 	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
 	DSET(param, 2, 0);
 	result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
 	if (result < 0)
-		goto out;
+		goto out_free;
 	p = param + 6 + result;
 
 	WSET(data, 0, 0); /* creation time */
@@ -2820,20 +2805,21 @@
 	WSET(data, 20, 0); /* attr */
 	DSET(data, 22, 0); /* ULONG EA size */
 
-	result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
-				    26, data, p - param, param,
-				    &resp_data_len, &resp_data,
-				    &resp_param_len, &resp_param);
+	req->rq_trans2_command = TRANSACT2_SETPATHINFO;
+	req->rq_ldata = 26;
+	req->rq_data  = data;
+	req->rq_lparm = p - param;
+	req->rq_parm  = param;
+	req->rq_flags = 0;
+	result = smb_add_request(req);
 	if (result < 0)
-	{
-		if (smb_retry(server))
-			goto retry;
-		goto out;
-	}
+		goto out_free;
 	result = 0;
-	if (server->rcls != 0)
-		result = smb_errno(server);
+	if (req->rq_rcls != 0)
+		result = smb_errno(req);
 
+out_free:
+	smb_rput(req);
 out:
 	return result;
 }
@@ -2861,7 +2847,6 @@
 	VERBOSE("setting %s/%s, open=%d\n",
 		DENTRY_PATH(dentry), smb_is_open(inode));
 
-	smb_lock_server(server);
 	/* setting the time on a Win95 server fails (tridge) */
 	if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 && 
 	    !(server->mnt->flags & SMB_MOUNT_WIN95)) {
@@ -2890,7 +2875,6 @@
 		}
 	}
 
-	smb_unlock_server(server);
 	return result;
 }
 
@@ -2901,26 +2885,25 @@
 	int result;
 	char *p;
 	long unit;
+	struct smb_request *req;
 
-	smb_lock_server(server);
-
-      retry:
-	smb_setup_header(server, SMBdskattr, 0, 0);
-
-	if ((result = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) {
-		if (smb_retry(server))
-			goto retry;
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, 0)))
 		goto out;
-	}
-	p = SMB_VWV(server->packet);
+
+	smb_setup_header(req, SMBdskattr, 0, 0);
+	if ((result = smb_request_ok(req, SMBdskattr, 5, 0)) < 0)
+		goto out_free;
+	p = SMB_VWV(req->rq_header);
 	unit = (WVAL(p, 2) * WVAL(p, 4)) >> SMB_ST_BLKSHIFT;
 	attr->f_blocks = WVAL(p, 0) * unit;
 	attr->f_bsize  = SMB_ST_BLKSIZE;
 	attr->f_bavail = attr->f_bfree = WVAL(p, 6) * unit;
 	result = 0;
 
+out_free:
+	smb_rput(req);
 out:
-	smb_unlock_server(server);
 	return result;
 }
 
diff -Nru a/fs/smbfs/proto.h b/fs/smbfs/proto.h
--- a/fs/smbfs/proto.h	Tue Jul 16 16:49:43 2002
+++ b/fs/smbfs/proto.h	Tue Jul 16 16:49:43 2002
@@ -1,16 +1,17 @@
 /*
- *  Autogenerated with cproto on:  Thu Nov 22 21:18:04 CET 2001
+ *  Autogenerated with cproto on:  Fri Jul 12 22:15:26 CEST 2002
  */
 
+struct smb_request;
+
 /* proc.c */
 extern int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp);
 extern __u32 smb_len(__u8 *p);
 extern int smb_get_rsize(struct smb_sb_info *server);
 extern int smb_get_wsize(struct smb_sb_info *server);
-extern int smb_errno(struct smb_sb_info *server);
+extern int smb_errno(struct smb_request *req);
 extern int smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt);
-extern int smb_wakeup(struct smb_sb_info *server);
-extern __u8 *smb_setup_header(struct smb_sb_info *server, __u8 command, __u16 wct, __u16 bcc);
+extern __u8 *smb_setup_header(struct smb_request *req, __u8 command, __u16 wct, __u16 bcc);
 extern int smb_open(struct dentry *dentry, int wish);
 extern int smb_close(struct inode *ino);
 extern int smb_close_fileid(struct dentry *dentry, __u16 fileid);
@@ -36,19 +37,21 @@
 extern struct dentry *smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos);
 extern int smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctrl, struct qstr *qname, struct smb_fattr *entry);
 /* sock.c */
+extern void smb_data_ready(struct sock *sk, int len);
 extern int smb_valid_socket(struct inode *inode);
-extern int smb_catch_keepalive(struct smb_sb_info *server);
-extern int smb_dont_catch_keepalive(struct smb_sb_info *server);
 extern void smb_close_socket(struct smb_sb_info *server);
-extern int smb_round_length(int len);
-extern int smb_request(struct smb_sb_info *server);
-extern int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command, int ldata, unsigned char *data, int lparam, unsigned char *param, int *lrdata, unsigned char **rdata, int *lrparam, unsigned char **rparam);
+extern int smb_recv_available(struct smb_sb_info *server);
+extern int smb_receive_header(struct smb_sb_info *server);
+extern int smb_receive_drop(struct smb_sb_info *server);
+extern int smb_receive(struct smb_sb_info *server, struct smb_request *req);
+extern int smb_send_request(struct smb_request *req);
 /* inode.c */
 extern struct inode *smb_iget(struct super_block *sb, struct smb_fattr *fattr);
 extern void smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr);
 extern void smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr);
 extern void smb_invalidate_inodes(struct smb_sb_info *server);
 extern int smb_revalidate_inode(struct dentry *dentry);
+extern int smb_fill_super(struct super_block *sb, void *raw_data, int silent);
 extern int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
 extern int smb_notify_change(struct dentry *dentry, struct iattr *attr);
 /* file.c */
@@ -57,3 +60,19 @@
 extern struct inode_operations smb_file_inode_operations;
 /* ioctl.c */
 extern int smb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
+/* smbiod.c */
+extern void smbiod_wake_up(void);
+extern void smbiod_register_server(struct smb_sb_info *server);
+extern void smbiod_unregister_server(struct smb_sb_info *server);
+extern void smbiod_flush(struct smb_sb_info *server);
+extern int smbiod_retry(struct smb_sb_info *server);
+/* request.c */
+extern int smb_init_request_cache(void);
+extern void smb_destroy_request_cache(void);
+extern struct smb_request *smb_alloc_request(struct smb_sb_info *server, int bufsize);
+extern void smb_rget(struct smb_request *req);
+extern void smb_rput(struct smb_request *req);
+extern int smb_add_request(struct smb_request *req);
+extern int smb_request_send_req(struct smb_request *req);
+extern int smb_request_send_server(struct smb_sb_info *server);
+extern int smb_request_recv(struct smb_sb_info *server);
diff -Nru a/fs/smbfs/request.c b/fs/smbfs/request.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/smbfs/request.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,796 @@
+/*
+ *  request.c
+ *
+ *  Copyright (C) 2001 by Urban Widmark
+ *
+ *  Please add a note about your changes to smbfs in the ChangeLog file.
+ */
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+
+#include <linux/smb_fs.h>
+#include <linux/smbno.h>
+#include <linux/smb_mount.h>
+
+#include "smb_debug.h"
+#include "request.h"
+#include "proto.h"
+
+/* #define SMB_SLAB_DEBUG	(SLAB_RED_ZONE | SLAB_POISON) */
+#define SMB_SLAB_DEBUG	0
+
+#define ROUND_UP(x) (((x)+3) & ~3)
+
+/* cache for request structures */
+static kmem_cache_t *req_cachep;
+
+/*
+  /proc/slabinfo:
+  name, active, num, objsize, active_slabs, num_slaps, #pages
+*/
+
+
+int smb_init_request_cache(void)
+{
+	req_cachep = kmem_cache_create("smb_request",
+				       sizeof(struct smb_request), 0,
+				       SMB_SLAB_DEBUG | SLAB_HWCACHE_ALIGN,
+				       NULL, NULL);
+	if (req_cachep == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void smb_destroy_request_cache(void)
+{
+	if (kmem_cache_destroy(req_cachep))
+		printk(KERN_INFO "smb_destroy_request_cache: not all structures were freed\n");
+}
+
+/*
+ * Allocate and initialise a request structure
+ */
+static struct smb_request *smb_do_alloc_request(struct smb_sb_info *server,
+						int bufsize)
+{
+	struct smb_request *req;
+	unsigned char *buf = NULL;
+
+	req = kmem_cache_alloc(req_cachep, SLAB_KERNEL);
+	VERBOSE("allocating request: %p\n", req);
+	if (!req)
+		goto out;
+
+	if (bufsize > 0) {
+		buf = smb_kmalloc(bufsize, GFP_NOFS);
+		if (!buf) {
+			kmem_cache_free(req_cachep, req);
+			return NULL;
+		}
+	}
+
+	memset(req, 0, sizeof(struct smb_request));
+	req->rq_buffer = buf;
+	req->rq_bufsize = bufsize;
+	req->rq_server = server;
+	init_waitqueue_head(&req->rq_wait);
+	INIT_LIST_HEAD(&req->rq_queue);
+	atomic_set(&req->rq_count, 1);
+
+out:
+	return req;
+}
+
+struct smb_request *smb_alloc_request(struct smb_sb_info *server, int bufsize)
+{
+	struct smb_request *req = NULL;
+
+	for (;;) {
+		atomic_inc(&server->nr_requests);
+		if (atomic_read(&server->nr_requests) <= MAX_REQUEST_HARD) {
+			req = smb_do_alloc_request(server, bufsize);
+			if (req != NULL)
+				break;
+		}
+
+#if 0
+		/*
+		 * Try to free up at least one request in order to stay
+		 * below the hard limit
+		 */
+                if (nfs_try_to_free_pages(server))
+			continue;
+
+		if (signalled() && (server->flags & NFS_MOUNT_INTR))
+			return ERR_PTR(-ERESTARTSYS);
+		current->policy = SCHED_YIELD;
+		schedule();
+#else
+		/* FIXME: we want something like nfs does above, but that
+		   requires changes to all callers and can wait. */
+		break;
+#endif
+	}
+	return req;
+}
+
+static void smb_free_request(struct smb_request *req)
+{
+	atomic_dec(&req->rq_server->nr_requests);
+	if (req->rq_buffer && !(req->rq_flags & SMB_REQ_STATIC))
+		smb_kfree(req->rq_buffer);
+	if (req->rq_trans2buffer)
+		smb_kfree(req->rq_trans2buffer);
+	kmem_cache_free(req_cachep, req);
+}
+
+/*
+ * What prevents a rget to race with a rput? The count must never drop to zero
+ * while it is in use. Only rput if it is ok that it is free'd.
+ */
+void smb_rget(struct smb_request *req)
+{
+	atomic_inc(&req->rq_count);
+}
+void smb_rput(struct smb_request *req)
+{
+	if (atomic_dec_and_test(&req->rq_count)) {
+		list_del_init(&req->rq_queue);
+		smb_free_request(req);
+	}
+}
+
+/* setup to receive the data part of the SMB */
+static int smb_setup_bcc(struct smb_request *req)
+{
+	int result = 0;
+	req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd;
+
+	if (req->rq_rlen > req->rq_bufsize) {
+		PARANOIA("Packet too large %d > %d\n",
+			 req->rq_rlen, req->rq_bufsize);
+		return -ENOBUFS;
+	}
+
+	req->rq_iov[0].iov_base = req->rq_buffer;
+	req->rq_iov[0].iov_len  = req->rq_rlen;
+	req->rq_iovlen = 1;
+
+	return result;
+}
+
+/*
+ * Prepare a "normal" request structure.
+ */
+static int smb_setup_request(struct smb_request *req)
+{
+	int len = smb_len(req->rq_header) + 4;
+	req->rq_slen = len;
+
+	/* if we expect a data part in the reply we set the iov's to read it */
+	if (req->rq_resp_bcc)
+		req->rq_setup_read = smb_setup_bcc;
+
+	/* This tries to support re-using the same request */
+	req->rq_bytes_sent = 0;
+	req->rq_rcls = 0;
+	req->rq_err = 0;
+	req->rq_errno = 0;
+	req->rq_fragment = 0;
+	if (req->rq_trans2buffer)
+		smb_kfree(req->rq_trans2buffer);
+
+	return 0;
+}
+
+/*
+ * Prepare a transaction2 request structure
+ */
+static int smb_setup_trans2request(struct smb_request *req)
+{
+	struct smb_sb_info *server = req->rq_server;
+	int mparam, mdata;
+	static unsigned char padding[4] = { 0, };
+
+	/* I know the following is very ugly, but I want to build the
+	   smb packet as efficiently as possible. */
+
+	const int smb_parameters = 15;
+	const int header = SMB_HEADER_LEN + 2 * smb_parameters + 2;
+	const int oparam = ROUND_UP(header + 3);
+	const int odata  = ROUND_UP(oparam + req->rq_lparm);
+	const int bcc = (req->rq_data ? odata + req->rq_ldata :
+					oparam + req->rq_lparm) - header;
+
+	if ((bcc + oparam) > server->opt.max_xmit)
+		return -ENOMEM;
+	smb_setup_header(req, SMBtrans2, smb_parameters, bcc);
+
+	/*
+	 * max parameters + max data + max setup == bufsize to make NT4 happy
+	 * and not abort the transfer or split into multiple responses. It also
+	 * makes smbfs happy as handling packets larger than the buffer size
+	 * is extra work.
+	 *
+	 * OS/2 is probably going to hate me for this ...
+	 */
+	mparam = SMB_TRANS2_MAX_PARAM;
+	mdata = req->rq_bufsize - mparam;
+
+	mdata = server->opt.max_xmit - mparam - 100;
+	if (mdata < 1024) {
+		mdata = 1024;
+		mparam = 20;
+	}
+
+#if 0
+	/* NT/win2k has ~4k max_xmit, so with this we request more than it wants
+	   to return as one SMB. Useful for testing the fragmented trans2
+	   handling. */
+	mdata = 8192;
+#endif
+
+	WSET(req->rq_header, smb_tpscnt, req->rq_lparm);
+	WSET(req->rq_header, smb_tdscnt, req->rq_ldata);
+	WSET(req->rq_header, smb_mprcnt, mparam);
+	WSET(req->rq_header, smb_mdrcnt, mdata);
+	WSET(req->rq_header, smb_msrcnt, 0);    /* max setup always 0 ? */
+	WSET(req->rq_header, smb_flags, 0);
+	DSET(req->rq_header, smb_timeout, 0);
+	WSET(req->rq_header, smb_pscnt, req->rq_lparm);
+	WSET(req->rq_header, smb_psoff, oparam - 4);
+	WSET(req->rq_header, smb_dscnt, req->rq_ldata);
+	WSET(req->rq_header, smb_dsoff, req->rq_data ? odata - 4 : 0);
+	*(req->rq_header + smb_suwcnt) = 0x01;          /* setup count */
+	*(req->rq_header + smb_suwcnt + 1) = 0x00;      /* reserved */
+	WSET(req->rq_header, smb_setup0, req->rq_trans2_command);
+
+	req->rq_iovlen = 2;
+	req->rq_iov[0].iov_base = (void *) req->rq_header;
+	req->rq_iov[0].iov_len = oparam;
+	req->rq_iov[1].iov_base = (req->rq_parm==NULL) ? padding : req->rq_parm;
+	req->rq_iov[1].iov_len = req->rq_lparm;
+	req->rq_slen = oparam + req->rq_lparm;
+
+	if (req->rq_data) {
+		req->rq_iovlen += 2;
+		req->rq_iov[2].iov_base = padding;
+		req->rq_iov[2].iov_len = odata - oparam - req->rq_lparm;
+		req->rq_iov[3].iov_base = req->rq_data;
+		req->rq_iov[3].iov_len = req->rq_ldata;
+		req->rq_slen = odata + req->rq_ldata;
+	}
+
+	/* always a data part for trans2 replies */
+	req->rq_setup_read = smb_setup_bcc;
+
+	return 0;
+}
+
+/*
+ * Add a request and tell smbiod to process it
+ */
+int smb_add_request(struct smb_request *req)
+{
+	long timeleft;
+	struct smb_sb_info *server = req->rq_server;
+	int result = 0;
+
+	smb_setup_request(req);
+	if (req->rq_trans2_command) {
+		if (req->rq_buffer == NULL) {
+			PARANOIA("trans2 attempted without response buffer!\n");
+			return -EIO;
+		}
+		result = smb_setup_trans2request(req);
+	}
+	if (result < 0)
+		return result;
+
+#ifdef SMB_DEBUG_PACKET_SIZE
+	add_xmit_stats(req);
+#endif
+
+	/* add 'req' to the queue of requests */
+	if (smb_lock_server_interruptible(server))
+		return -EINTR;
+
+	/*
+	 * Try to send the request as the process. If that fails we queue the
+	 * request and let smbiod send it later.
+	 */
+
+	/* FIXME: each server has a number on the maximum number of parallel
+	   requests. 10, 50 or so. We should not allow more requests to be
+	   active. */
+	if (server->mid > 0xf000)
+		server->mid = 0;
+	req->rq_mid = server->mid++;
+	WSET(req->rq_header, smb_mid, req->rq_mid);
+
+	result = 0;
+	if (server->state == CONN_VALID) {
+		if (list_empty(&server->xmitq))
+			result = smb_request_send_req(req);
+		if (result < 0) {
+			/* Connection lost? */
+			server->conn_error = result;
+			server->state = CONN_INVALID;
+		}
+	}
+	if (result != 1)
+		list_add_tail(&req->rq_queue, &server->xmitq);
+	smb_rget(req);
+
+	if (server->state != CONN_VALID)
+		smbiod_retry(server);
+
+	smb_unlock_server(server);
+
+	smbiod_wake_up();
+
+	/* FIXME: replace with a timeout-able wake_event_interruptible */
+	timeleft = interruptible_sleep_on_timeout(&req->rq_wait, 30*HZ);
+	if (!timeleft || signal_pending(current)) {
+		/*
+		 * On timeout or on interrupt we want to try and remove the
+		 * request from the recvq/xmitq.
+		 */
+		smb_lock_server(server);
+		if (!(req->rq_flags & SMB_REQ_RECEIVED)) {
+			list_del_init(&req->rq_queue);
+			smb_rput(req);
+		}
+		smb_unlock_server(server);
+	}
+		
+	if (!timeleft) {
+		PARANOIA("request [%p, mid=%d] timed out!\n",
+			 req, req->rq_mid);
+		VERBOSE("smb_com:  %02x\n", *(req->rq_header + smb_com));
+		VERBOSE("smb_rcls: %02x\n", *(req->rq_header + smb_rcls));
+		VERBOSE("smb_flg:  %02x\n", *(req->rq_header + smb_flg));
+		VERBOSE("smb_tid:  %04x\n", WVAL(req->rq_header, smb_tid));
+		VERBOSE("smb_pid:  %04x\n", WVAL(req->rq_header, smb_pid));
+		VERBOSE("smb_uid:  %04x\n", WVAL(req->rq_header, smb_uid));
+		VERBOSE("smb_mid:  %04x\n", WVAL(req->rq_header, smb_mid));
+		VERBOSE("smb_wct:  %02x\n", *(req->rq_header + smb_wct));
+
+		req->rq_rcls = ERRSRV;
+		req->rq_err  = ERRtimeout;
+
+		/* Just in case it was "stuck" */
+		smbiod_wake_up();
+	}
+	VERBOSE("woke up, rcls=%d\n", req->rq_rcls);
+
+	if (req->rq_rcls != 0)
+		req->rq_errno = smb_errno(req);
+	if (signal_pending(current))
+		req->rq_errno = -ERESTARTSYS;
+	return req->rq_errno;
+}
+
+/*
+ * Send a request and place it on the recvq if successfully sent.
+ * Must be called with the server lock held.
+ */
+int smb_request_send_req(struct smb_request *req)
+{
+	struct smb_sb_info *server = req->rq_server;
+	int result;
+
+	result = smb_send_request(req);
+	if (result < 0 && result != -EAGAIN)
+		goto out;
+
+	result = 0;
+	if (!(req->rq_flags & SMB_REQ_TRANSMITTED))
+		goto out;
+
+	list_del_init(&req->rq_queue);
+	list_add_tail(&req->rq_queue, &server->recvq);
+	result = 1;
+out:
+	return result;
+}
+
+/*
+ * Sends one request for this server. (smbiod)
+ * Must be called with the server lock held.
+ * Returns: <0 on error
+ *           0 if no request could be completely sent
+ *           1 if all data for one request was sent
+ */
+int smb_request_send_server(struct smb_sb_info *server)
+{
+	struct list_head *head;
+	struct smb_request *req;
+	int result;
+
+	if (server->state != CONN_VALID)
+		return 0;
+
+	/* dequeue first request, if any */
+	req = NULL;
+	head = server->xmitq.next;
+	if (head != &server->xmitq) {
+		req = list_entry(head, struct smb_request, rq_queue);
+	}
+	if (!req)
+		return 0;
+
+	result = smb_request_send_req(req);
+	if (result < 0) {
+		server->conn_error = result;
+		list_del_init(&req->rq_queue);
+		list_add(&req->rq_queue, &server->xmitq);
+		result = -EIO;
+		goto out;
+	}
+
+out:
+	return result;
+}
+
+/*
+ * Try to find a request matching this "mid". Typically the first entry will
+ * be the matching one.
+ */
+static struct smb_request *find_request(struct smb_sb_info *server, int mid)
+{
+	struct list_head *tmp;
+	struct smb_request *req = NULL;
+
+	list_for_each(tmp, &server->recvq) {
+		req = list_entry(tmp, struct smb_request, rq_queue);
+		if (req->rq_mid == mid) {
+			break;
+		}
+		req = NULL;
+	}
+
+	if (!req) {
+		VERBOSE("received reply with mid %d but no request!\n",
+			WVAL(server->header, smb_mid));
+		server->rstate = SMB_RECV_DROP;
+	}
+
+	return req;
+}
+
+/*
+ * Called when we have read the smb header and believe this is a response.
+ */
+static int smb_init_request(struct smb_sb_info *server, struct smb_request *req)
+{
+	int hdrlen, wct;
+
+	memcpy(req->rq_header, server->header, SMB_HEADER_LEN);
+
+	wct = *(req->rq_header + smb_wct);
+	if (wct > 20) {	
+		PARANOIA("wct too large, %d > 20\n", wct);
+		server->rstate = SMB_RECV_DROP;
+		return 0;
+	}
+
+	req->rq_resp_wct = wct;
+	hdrlen = SMB_HEADER_LEN + wct*2 + 2;
+	VERBOSE("header length: %d   smb_wct: %2d\n", hdrlen, wct);
+
+	req->rq_bytes_recvd = SMB_HEADER_LEN;
+	req->rq_rlen = hdrlen;
+	req->rq_iov[0].iov_base = req->rq_header;
+	req->rq_iov[0].iov_len  = hdrlen;
+	req->rq_iovlen = 1;
+	server->rstate = SMB_RECV_PARAM;
+
+#ifdef SMB_DEBUG_PACKET_SIZE
+	add_recv_stats(smb_len(server->header));
+#endif
+	return 0;
+}
+
+/*
+ * Reads the SMB parameters
+ */
+static int smb_recv_param(struct smb_sb_info *server, struct smb_request *req)
+{
+	int result;
+
+	result = smb_receive(server, req);
+	if (result < 0)
+		return result;
+	if (req->rq_bytes_recvd < req->rq_rlen)
+		return 0;
+
+	VERBOSE("result: %d   smb_bcc:  %04x\n", result,
+		WVAL(req->rq_header, SMB_HEADER_LEN +
+		     (*(req->rq_header + smb_wct) * 2)));
+
+	result = 0;
+	req->rq_iov[0].iov_base = NULL;
+	req->rq_rlen = 0;
+	if (req->rq_callback)
+		req->rq_callback(req);
+	else if (req->rq_setup_read)
+		result = req->rq_setup_read(req);
+	if (result < 0) {
+		server->rstate = SMB_RECV_DROP;
+		return result;
+	}
+
+	server->rstate = req->rq_rlen > 0 ? SMB_RECV_DATA : SMB_RECV_END;
+
+	req->rq_bytes_recvd = 0;	// recvd out of the iov
+
+	VERBOSE("rlen: %d\n", req->rq_rlen);
+	if (req->rq_rlen < 0) {
+		PARANOIA("Parameters read beyond end of packet!\n");
+		server->rstate = SMB_RECV_END;
+		return -EIO;
+	}
+	return 0;
+}
+
+/*
+ * Reads the SMB data
+ */
+static int smb_recv_data(struct smb_sb_info *server, struct smb_request *req)
+{
+	int result;
+
+	result = smb_receive(server, req);
+	if (result < 0)
+		goto out;
+	if (req->rq_bytes_recvd < req->rq_rlen)
+		goto out;
+	server->rstate = SMB_RECV_END;
+out:
+	VERBOSE("result: %d\n", result);
+	return result;
+}
+
+/*
+ * Receive a transaction2 response
+ * Return: 0 if the response has been fully read
+ *         1 if there are further "fragments" to read
+ *        <0 if there is an error
+ */
+static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req)
+{
+	unsigned char *inbuf;
+	unsigned int parm_disp, parm_offset, parm_count, parm_tot;
+	unsigned int data_disp, data_offset, data_count, data_tot;
+	int hdrlen = SMB_HEADER_LEN + req->rq_resp_wct*2 - 2;
+
+	VERBOSE("handling trans2\n");
+
+	inbuf = req->rq_header;
+	data_tot    = WVAL(inbuf, smb_tdrcnt);
+	parm_tot    = WVAL(inbuf, smb_tprcnt);
+	parm_disp   = WVAL(inbuf, smb_prdisp);
+	parm_offset = WVAL(inbuf, smb_proff);
+	parm_count  = WVAL(inbuf, smb_prcnt);
+	data_disp   = WVAL(inbuf, smb_drdisp);
+	data_offset = WVAL(inbuf, smb_droff);
+	data_count  = WVAL(inbuf, smb_drcnt);
+
+	/* Modify offset for the split header/buffer we use */
+	data_offset -= hdrlen;
+	parm_offset -= hdrlen;
+
+	if (parm_count == parm_tot && data_count == data_tot) {
+		/*
+		 * This packet has all the trans2 data.
+		 *
+		 * We setup the request so that this will be the common
+		 * case. It may be a server error to not return a
+		 * response that fits.
+		 */
+		VERBOSE("single trans2 response  "
+			"dcnt=%d, pcnt=%d, doff=%d, poff=%d\n",
+			data_count, parm_count,
+			data_offset, parm_offset);
+		req->rq_ldata = data_count;
+		req->rq_lparm = parm_count;
+		req->rq_data = req->rq_buffer + data_offset;
+		req->rq_parm = req->rq_buffer + parm_offset;
+		return 0;
+	}
+
+	VERBOSE("multi trans2 response  "
+		"frag=%d, dcnt=%d, pcnt=%d, doff=%d, poff=%d\n",
+		req->rq_fragment,
+		data_count, parm_count,
+		data_offset, parm_offset);
+
+	if (!req->rq_fragment) {
+		int buf_len;
+
+		/* We got the first trans2 fragment */
+		req->rq_fragment = 1;
+		req->rq_total_data = data_tot;
+		req->rq_total_parm = parm_tot;
+		req->rq_ldata = 0;
+		req->rq_lparm = 0;
+
+		buf_len = data_tot + parm_tot;
+		if (buf_len > SMB_MAX_PACKET_SIZE)
+			goto out_too_long;
+
+		req->rq_trans2bufsize = buf_len;
+		req->rq_trans2buffer = smb_kmalloc(buf_len, GFP_NOFS);
+		if (!req->rq_trans2buffer)
+			goto out_no_mem;
+
+		req->rq_parm = req->rq_trans2buffer;
+		req->rq_data = req->rq_trans2buffer + parm_tot;
+	} else if (req->rq_total_data < data_tot ||
+		   req->rq_total_parm < parm_tot)
+		goto out_data_grew;
+
+	if (parm_disp + parm_count > req->rq_total_parm)
+		goto out_bad_parm;
+	if (data_disp + data_count > req->rq_total_data)
+		goto out_bad_data;
+
+	inbuf = req->rq_buffer;
+	memcpy(req->rq_parm + parm_disp, inbuf + parm_offset, parm_count);
+	memcpy(req->rq_data + data_disp, inbuf + data_offset, data_count);
+
+	req->rq_ldata += data_count;
+	req->rq_lparm += parm_count;
+
+	/*
+	 * Check whether we've received all of the data. Note that
+	 * we use the packet totals -- total lengths might shrink!
+	 */
+	if (req->rq_ldata >= data_tot && req->rq_lparm >= parm_tot)
+		return 0;
+	return 1;
+
+out_too_long:
+	printk(KERN_ERR "smb_trans2: data/param too long, data=%d, parm=%d\n",
+		data_tot, parm_tot);
+	req->rq_errno = -EIO;
+	goto out;
+out_no_mem:
+	printk(KERN_ERR "smb_trans2: couldn't allocate data area of %d bytes\n",
+	       req->rq_trans2bufsize);
+	req->rq_errno = -ENOMEM;
+	goto out;
+out_data_grew:
+	printk(KERN_ERR "smb_trans2: data/params grew!\n");
+	req->rq_errno = -EIO;
+	goto out;
+out_bad_parm:
+	printk(KERN_ERR "smb_trans2: invalid parms, disp=%d, cnt=%d, tot=%d\n",
+	       parm_disp, parm_count, parm_tot);
+	req->rq_errno = -EIO;
+	goto out;
+out_bad_data:
+	printk(KERN_ERR "smb_trans2: invalid data, disp=%d, cnt=%d, tot=%d\n",
+	       data_disp, data_count, data_tot);
+	req->rq_errno = -EIO;
+out:
+	return req->rq_errno;
+}
+
+/*
+ * State machine for receiving responses. We handle the fact that we can't
+ * read the full response in one try by having states telling us how much we
+ * have read.
+ *
+ * Must be called with the server lock held (only called from smbiod).
+ *
+ * Return: <0 on error
+ */
+int smb_request_recv(struct smb_sb_info *server)
+{
+	struct smb_request *req = NULL;
+	int result = 0;
+
+	if (smb_recv_available(server) <= 0)
+		return 0;
+
+	VERBOSE("state: %d\n", server->rstate);
+	switch (server->rstate) {
+	case SMB_RECV_DROP:
+		result = smb_receive_drop(server);
+		if (result < 0)
+			break;
+		if (server->rstate == SMB_RECV_DROP)
+			break;
+		server->rstate = SMB_RECV_START;
+		/* fallthrough */
+	case SMB_RECV_START:
+		server->smb_read = 0;
+		server->rstate = SMB_RECV_HEADER;
+		/* fallthrough */
+	case SMB_RECV_HEADER:
+		result = smb_receive_header(server);
+		if (result < 0)
+			break;
+		if (server->rstate == SMB_RECV_HEADER)
+			break;
+		if (! (*(server->header + smb_flg) & SMB_FLAGS_REPLY) ) {
+			server->rstate = SMB_RECV_REQUEST;
+			break;
+		}
+		if (server->rstate != SMB_RECV_HCOMPLETE)
+			break;
+		/* fallthrough */
+	case SMB_RECV_HCOMPLETE:
+		req = find_request(server, WVAL(server->header, smb_mid));
+		if (!req)
+			break;
+		smb_init_request(server, req);
+		req->rq_rcls = *(req->rq_header + smb_rcls);
+		req->rq_err  = WVAL(req->rq_header, smb_err);
+		if (server->rstate != SMB_RECV_PARAM)
+			break;
+		/* fallthrough */
+	case SMB_RECV_PARAM:
+		if (!req)
+			req = find_request(server,WVAL(server->header,smb_mid));
+		if (!req)
+			break;
+		result = smb_recv_param(server, req);
+		if (result < 0)
+			break;
+		if (server->rstate != SMB_RECV_DATA)
+			break;
+		/* fallthrough */
+	case SMB_RECV_DATA:
+		if (!req)
+			req = find_request(server,WVAL(server->header,smb_mid));
+		if (!req)
+			break;
+		result = smb_recv_data(server, req);
+		if (result < 0)
+			break;
+		break;
+
+		/* We should never be called with any of these states */
+	case SMB_RECV_END:
+	case SMB_RECV_REQUEST:
+		server->rstate = SMB_RECV_END;
+		break;
+	}
+
+	if (result < 0) {
+		/* We saw an error */
+		return result;
+	}
+
+	if (server->rstate != SMB_RECV_END)
+		return 0;
+
+	result = 0;
+	if (req->rq_trans2_command && req->rq_rcls == SUCCESS)
+		result = smb_recv_trans2(server, req);
+
+	/*
+	 * Response completely read. Drop any extra bytes sent by the server.
+	 * (Yes, servers sometimes add extra bytes to requests)
+	 */
+	VERBOSE("smb_len: %d   smb_read: %d\n",
+		server->smb_len, server->smb_read);
+	if (server->smb_read < server->smb_len)
+		smb_receive_drop(server);
+
+	server->rstate = SMB_RECV_START;
+
+	if (!result) {
+		list_del_init(&req->rq_queue);
+		req->rq_flags |= SMB_REQ_RECEIVED;
+		smb_rput(req);
+		wake_up_interruptible(&req->rq_wait);
+	}
+	return 0;
+}
diff -Nru a/fs/smbfs/request.h b/fs/smbfs/request.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/smbfs/request.h	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,69 @@
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+
+struct smb_request {
+	struct list_head rq_queue;	/* recvq or xmitq for the server */
+
+	atomic_t rq_count;
+
+	wait_queue_head_t rq_wait;
+	int rq_flags;
+	int rq_mid;	/* multiplex ID, set by request.c */
+
+	struct smb_sb_info *rq_server;
+
+	/* header + word count + parameter words + byte count */
+	unsigned char rq_header[SMB_HEADER_LEN + 20*2 + 2];
+
+	int rq_bufsize;
+	unsigned char *rq_buffer;
+
+	/* FIXME: this is not good enough for merging IO requests. */
+	unsigned char *rq_page;
+	int rq_rsize;
+
+	int rq_resp_wct;
+	int rq_resp_bcc;
+
+	int rq_rlen;
+	int rq_bytes_recvd;
+
+	int rq_slen;
+	int rq_bytes_sent;
+
+	int rq_iovlen;
+	struct iovec rq_iov[4];
+
+	int (*rq_setup_read) (struct smb_request *);
+	void (*rq_callback) (struct smb_request *);
+
+	/* ------ trans2 stuff ------ */
+
+	u16 rq_trans2_command;	/* 0 if not a trans2 request */
+	unsigned int rq_ldata;
+	unsigned char *rq_data;
+	unsigned int rq_lparm;
+	unsigned char *rq_parm;
+
+	int rq_fragment;
+	u32 rq_total_data;
+	u32 rq_total_parm;
+	int rq_trans2bufsize;
+	unsigned char *rq_trans2buffer;
+
+	/* ------ response ------ */
+
+	unsigned short rq_rcls;
+	unsigned short rq_err;
+	int rq_errno;
+};
+
+#define SMB_REQ_STATIC		0x0001	/* rq_buffer is static */
+#define SMB_REQ_NORETRY		0x0002	/* request is invalid after retry */
+
+#define SMB_REQ_TRANSMITTED	0x4000	/* all data has been sent */
+#define SMB_REQ_RECEIVED	0x8000	/* reply received, smbiod is done */
+
+#define xSMB_REQ_NOREPLY	0x0004	/* we don't want the reply (if any) */
+#define xSMB_REQ_NORECEIVER	0x0008	/* caller doesn't wait for response */
diff -Nru a/fs/smbfs/smbiod.c b/fs/smbfs/smbiod.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/smbfs/smbiod.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,325 @@
+/*
+ *  smbiod.c
+ *
+ *  Copyright (C) 2000, Charles Loep / Corel Corp.
+ *  Copyright (C) 2001, Urban Widmark
+ */
+
+#include <linux/config.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/dcache.h>
+#include <linux/smp_lock.h>
+#include <net/ip.h>
+
+#include <linux/smb_fs.h>
+#include <linux/smbno.h>
+#include <linux/smb_mount.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "smb_debug.h"
+#include "request.h"
+#include "proto.h"
+
+static int smbiod_pid = -1;
+static DECLARE_WAIT_QUEUE_HEAD(smbiod_wait);
+static LIST_HEAD(smb_servers);
+static spinlock_t servers_lock = SPIN_LOCK_UNLOCKED;
+
+#define SMBIOD_DATA_READY	(1<<0)
+static long smbiod_flags;
+
+static int smbiod(void *);
+static void smbiod_start(void);
+static void smbiod_stop(void);
+
+/*
+ * called when there's work for us to do
+ */
+void smbiod_wake_up()
+{
+	if (smbiod_pid == -1)
+		return;
+	set_bit(SMBIOD_DATA_READY, &smbiod_flags);
+	wake_up_interruptible(&smbiod_wait);
+}
+
+/*
+ * start smbiod if none is running
+ */
+static void smbiod_start()
+{
+	if (smbiod_pid != -1)
+		return;
+	smbiod_pid = kernel_thread(smbiod, NULL, 0);
+}
+
+/*
+ * stop smbiod if there are no open connections
+ */
+static void smbiod_stop()
+{
+	if (smbiod_pid != -1 && list_empty(&smb_servers))
+		kill_proc(smbiod_pid, SIGKILL, 1);
+}
+
+/*
+ * register a server & start smbiod if necessary
+ */
+void smbiod_register_server(struct smb_sb_info *server)
+{
+	spin_lock(&servers_lock);
+	list_add(&server->entry, &smb_servers);
+	VERBOSE("%p\n", server);
+	smbiod_start();
+	spin_unlock(&servers_lock);
+}
+
+/*
+ * unregister a server & stop smbiod if necessary
+ */
+void smbiod_unregister_server(struct smb_sb_info *server)
+{
+	spin_lock(&servers_lock);
+	list_del_init(&server->entry);
+	VERBOSE("%p\n", server);
+	smbiod_stop();
+	spin_unlock(&servers_lock);
+
+	smb_lock_server(server);
+	smbiod_flush(server);
+	smb_unlock_server(server);
+}
+
+void smbiod_flush(struct smb_sb_info *server)
+{
+	struct list_head *tmp, *n;
+	struct smb_request *req;
+
+	list_for_each_safe(tmp, n, &server->xmitq) {
+		req = list_entry(tmp, struct smb_request, rq_queue);
+		req->rq_errno = -EIO;
+		list_del_init(&req->rq_queue);
+		smb_rput(req);
+		wake_up_interruptible(&req->rq_wait);
+	}
+	list_for_each_safe(tmp, n, &server->recvq) {
+		req = list_entry(tmp, struct smb_request, rq_queue);
+		req->rq_errno = -EIO;
+		list_del_init(&req->rq_queue);
+		smb_rput(req);
+		wake_up_interruptible(&req->rq_wait);
+	}
+}
+
+/*
+ * Wake up smbmount and make it reconnect to the server.
+ * This must be called with the server locked.
+ *
+ * FIXME: add smbconnect version to this
+ */
+int smbiod_retry(struct smb_sb_info *server)
+{
+	struct list_head *head;
+	struct smb_request *req;
+	pid_t pid = server->conn_pid;
+	int result = 0;
+
+	VERBOSE("state: %d\n", server->state);
+	if (server->state == CONN_VALID || server->state == CONN_RETRYING)
+		goto out;
+
+	smb_invalidate_inodes(server);
+
+	/*
+	 * Some requests are meaningless after a retry, so we abort them.
+	 * One example are all requests using 'fileid' since the files are
+	 * closed on retry.
+	 */
+	head = server->xmitq.next;
+	while (head != &server->xmitq) {
+		req = list_entry(head, struct smb_request, rq_queue);
+		head = head->next;
+		if (req->rq_flags & SMB_REQ_NORETRY) {
+			VERBOSE("aborting request %p on xmitq\n", req);
+			req->rq_errno = -EIO;
+			list_del_init(&req->rq_queue);
+			smb_rput(req);
+			wake_up_interruptible(&req->rq_wait);
+		}
+	}
+
+	/*
+	 * FIXME: test the code for retrying request we already sent
+	 */
+	head = server->recvq.next;
+	while (head != &server->recvq) {
+		req = list_entry(head, struct smb_request, rq_queue);
+		head = head->next;
+#if 0
+		if (req->rq_flags & SMB_REQ_RETRY) {
+			/* must move the request to the xmitq */
+			VERBOSE("retrying request %p on recvq\n", req);
+			list_del(&req->rq_queue);
+			list_add(&req->rq_queue, &server->xmitq);
+			continue;
+		}
+#endif
+
+		VERBOSE("aborting request %p on recvq\n", req);
+		/* req->rq_rcls = ???; */ /* FIXME: set smb error code too? */
+		req->rq_errno = -EIO;
+		list_del_init(&req->rq_queue);
+		smb_rput(req);
+		wake_up_interruptible(&req->rq_wait);
+	}
+
+	smb_close_socket(server);
+
+	if (pid == 0) {
+		/* FIXME: this is fatal, umount? */
+		printk(KERN_ERR "smb_retry: no connection process\n");
+		server->state = CONN_RETRIED;
+		goto out;
+	}
+
+	/*
+	 * Change state so that only one retry per server will be started.
+	 */
+	server->state = CONN_RETRYING;
+
+	/*
+	 * Note: use the "priv" flag, as a user process may need to reconnect.
+	 */
+	result = kill_proc(pid, SIGUSR1, 1);
+	if (result) {
+		/* FIXME: this is most likely fatal, umount? */
+		printk(KERN_ERR "smb_retry: signal failed [%d]\n", result);
+		goto out;
+	}
+	VERBOSE("signalled pid %d\n", pid);
+
+	/* FIXME: The retried requests should perhaps get a "time boost". */
+
+out:
+	return result;
+}
+
+/*
+ * Currently handles lockingX packets.
+ */
+static void smbiod_handle_request(struct smb_sb_info *server)
+{
+	PARANOIA("smbiod got a request ... and we don't implement oplocks!\n");
+	server->rstate = SMB_RECV_DROP;
+}
+
+/*
+ * Do some IO for one server.
+ */
+static void smbiod_doio(struct smb_sb_info *server)
+{
+	int result;
+	int maxwork = 7;
+
+	if (server->state != CONN_VALID)
+		goto out;
+
+	do {
+		result = smb_request_recv(server);
+		if (result < 0) {
+			server->state = CONN_INVALID;
+			smbiod_retry(server);
+			goto out;	/* reconnecting is slow */
+		} else if (server->rstate == SMB_RECV_REQUEST)
+			smbiod_handle_request(server);
+	} while (result > 0 && maxwork-- > 0);
+
+	/*
+	 * If there is more to read then we want to be sure to wake up again.
+	 */
+	if (server->state != CONN_VALID)
+		goto out;
+	if (smb_recv_available(server) > 0)
+		set_bit(SMBIOD_DATA_READY, &smbiod_flags);
+
+	do {
+		result = smb_request_send_server(server);
+		if (result < 0) {
+			server->state = CONN_INVALID;
+			smbiod_retry(server);
+			goto out;	/* reconnecting is slow */
+		}
+	} while (result > 0);
+
+	/*
+	 * If the last request was not sent out we want to wake up again.
+	 */
+	if (!list_empty(&server->xmitq))
+		set_bit(SMBIOD_DATA_READY, &smbiod_flags);
+
+out:
+}
+
+/*
+ * smbiod kernel thread
+ */
+static int smbiod(void *unused)
+{
+	daemonize();
+
+	spin_lock_irq(&current->sigmask_lock);
+	siginitsetinv(&current->blocked, sigmask(SIGKILL));
+	recalc_sigpending();
+	spin_unlock_irq(&current->sigmask_lock);
+
+	strcpy(current->comm, "smbiod");
+
+	VERBOSE("SMB Kernel thread starting (%d) ...\n", current->pid);
+
+	for (;;) {
+		struct smb_sb_info *server;
+		struct list_head *pos, *n;
+
+		/* FIXME: Use poll? */
+		wait_event_interruptible(smbiod_wait,
+			 test_bit(SMBIOD_DATA_READY, &smbiod_flags));
+		if (signal_pending(current))
+			break;
+
+		clear_bit(SMBIOD_DATA_READY, &smbiod_flags);
+
+		/*
+		 * We must hold the servers_lock while looking for servers
+		 * to check or else we have a race with put_super.
+		 */
+		spin_lock(&servers_lock);
+		list_for_each_safe(pos, n, &smb_servers) {
+			server = list_entry(pos, struct smb_sb_info, entry);
+			VERBOSE("checking server %p\n", server);
+			smb_lock_server(server);
+			spin_unlock(&servers_lock);
+
+			smbiod_doio(server);
+
+			smb_unlock_server(server);
+			spin_lock(&servers_lock);
+		}
+		spin_unlock(&servers_lock);
+	}
+
+	VERBOSE("SMB Kernel thread exiting (%d) ...\n", current->pid);
+	smbiod_pid = -1;
+
+	return 0;
+}
diff -Nru a/fs/smbfs/sock.c b/fs/smbfs/sock.c
--- a/fs/smbfs/sock.c	Tue Jul 16 16:49:42 2002
+++ b/fs/smbfs/sock.c	Tue Jul 16 16:49:42 2002
@@ -15,6 +15,7 @@
 #include <linux/file.h>
 #include <linux/in.h>
 #include <linux/net.h>
+#include <linux/tcp.h>
 #include <linux/mm.h>
 #include <linux/netdevice.h>
 #include <linux/smp_lock.h>
@@ -27,19 +28,26 @@
 #include <linux/smbno.h>
 
 #include <asm/uaccess.h>
+#include <asm/ioctls.h>
 
 #include "smb_debug.h"
 #include "proto.h"
+#include "request.h"
 
 
 static int
-_recvfrom(struct socket *socket, unsigned char *ubuf, int size,
-	  unsigned flags)
+_recvfrom(struct socket *socket, unsigned char *ubuf, int size, unsigned flags)
 {
 	struct iovec iov;
 	struct msghdr msg;
 	struct scm_cookie scm;
+	mm_segment_t fs;
+
+	fs = get_fs();
+	set_fs(get_ds());
+	flags |= MSG_DONTWAIT | MSG_NOSIGNAL;
 
+	msg.msg_flags = flags;
 	msg.msg_name = NULL;
 	msg.msg_namelen = 0;
 	msg.msg_iov = &iov;
@@ -47,131 +55,37 @@
 	msg.msg_control = NULL;
 	iov.iov_base = ubuf;
 	iov.iov_len = size;
-	
-	memset(&scm, 0,sizeof(scm));
-	size=socket->ops->recvmsg(socket, &msg, size, flags, &scm);
-	if(size>=0)
-		scm_recv(socket,&msg,&scm,flags);
-	return size;
-}
-
-static int
-_send(struct socket *socket, const void *buff, int len)
-{
-	struct iovec iov;
-	struct msghdr msg;
-	struct scm_cookie scm;
-	int err;
-
-	msg.msg_name = NULL;
-	msg.msg_namelen = 0;
-	msg.msg_iov = &iov;
-	msg.msg_iovlen = 1;
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
-	
-	iov.iov_base = (void *)buff;
-	iov.iov_len = len;
 
-	msg.msg_flags = 0;
+	memset(&scm, 0, sizeof(scm));
+	size = socket->ops->recvmsg(socket, &msg, size, flags, &scm);
+	if (size >= 0)
+		scm_recv(socket, &msg, &scm, flags);
 
-	err = scm_send(socket, &msg, &scm);
-        if (err >= 0)
-	{
-		err = socket->ops->sendmsg(socket, &msg, len, &scm);
-		scm_destroy(&scm);
-	}
-	return err;
+	set_fs(fs);
+	return size;
 }
 
-struct data_callback {
-	struct tq_struct cb;
-	struct sock *sk;
-};
 /*
- * N.B. What happens if we're in here when the socket closes??
+ * Return the server this socket belongs to
  */
-static void
-found_data(struct sock *sk)
+static struct smb_sb_info *
+server_from_socket(struct socket *socket)
 {
-	/*
-	 * FIXME: copied from sock_def_readable, it should be a call to
-	 * server->data_ready()	-- manfreds@colorfullife.com
-	 */
-	read_lock(&sk->callback_lock);
-	if(!sk->dead) {
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,1,POLL_IN);
-	}
-	read_unlock(&sk->callback_lock);
+	return socket->sk->user_data;
 }
 
-static void
-smb_data_callback(void* ptr)
-{
-	struct data_callback* job=ptr;
-	struct socket *socket = job->sk->socket;
-	unsigned char peek_buf[4];
-	int result = 0;
-	mm_segment_t fs;
-	int count = 100;   /* this is a lot, we should have some data waiting */
-	int found = 0;
-
-	fs = get_fs();
-	set_fs(get_ds());
-
-	lock_kernel();
-	while (count-- > 0) {
-		peek_buf[0] = 0;
-
-		result = -EIO;
-		if (job->sk->dead) {
-			PARANOIA("sock dead!\n");
-			break;
-		}
-
-		result = _recvfrom(socket, (void *) peek_buf, 1,
-				   MSG_PEEK | MSG_DONTWAIT);
-		if (result < 0)
-			break;
-		if (peek_buf[0] != 0x85)
-			break;
-
-		/* got SESSION KEEP ALIVE */
-		result = _recvfrom(socket, (void *) peek_buf, 4,
-				   MSG_DONTWAIT);
-
-		DEBUG1("got SESSION KEEPALIVE\n");
-
-		if (result < 0)
-			break;
-		found = 1;
-	}
-	unlock_kernel();
-	set_fs(fs);
-
-	DEBUG1("found=%d, count=%d, result=%d\n", found, count, result);
-	if (found)
-		found_data(job->sk);
-	smb_kfree(ptr);
-}
-
-static void
+/*
+ * Called when there is data on the socket.
+ */
+void
 smb_data_ready(struct sock *sk, int len)
 {
-	struct data_callback* job;
-	job = smb_kmalloc(sizeof(struct data_callback),GFP_ATOMIC);
-	if(job == 0) {
-		printk("smb_data_ready: lost SESSION KEEPALIVE due to OOM.\n");
-		found_data(sk);
-		return;
-	}
-	INIT_LIST_HEAD(&job->cb.list);
-	job->cb.sync = 0;
-	job->cb.routine = smb_data_callback;
-	job->cb.data = job;
-	job->sk = sk;
-	schedule_task(&job->cb);
+	struct smb_sb_info *server = server_from_socket(sk->socket);
+	void (*data_ready)(struct sock *, int) = server->data_ready;
+
+	data_ready(sk, len);
+	VERBOSE("(%p, %d)\n", sk, len);
+	smbiod_wake_up();
 }
 
 int
@@ -197,691 +111,336 @@
 	return NULL;
 }
 
-int
-smb_catch_keepalive(struct smb_sb_info *server)
-{
-	struct socket *socket;
-	struct sock *sk;
-	void *data_ready;
-	int error;
-
-	error = -EINVAL;
-	socket = server_sock(server);
-	if (!socket)
-	{
-		printk(KERN_DEBUG "smb_catch_keepalive: did not get valid server!\n");
-		server->data_ready = NULL;
-		goto out;
-	}
-
-	sk = socket->sk;
-	if (sk == NULL)
-	{
-		DEBUG1("sk == NULL");
-		server->data_ready = NULL;
-		goto out;
-	}
-	DEBUG1("sk->d_r = %x, server->d_r = %x\n",
-		 (unsigned int) (sk->data_ready),
-		 (unsigned int) (server->data_ready));
-
-	/*
-	 * Install the callback atomically to avoid races ...
-	 */
-	data_ready = xchg(&sk->data_ready, smb_data_ready);
-	if (data_ready != smb_data_ready) {
-		server->data_ready = data_ready;
-		error = 0;
-	} else
-		printk(KERN_ERR "smb_catch_keepalive: already done\n");
-out:
-	return error;
-}
-
-int
-smb_dont_catch_keepalive(struct smb_sb_info *server)
-{
-	struct socket *socket;
-	struct sock *sk;
-	void * data_ready;
-	int error;
-
-	error = -EINVAL;
-	socket = server_sock(server);
-	if (!socket)
-	{
-		printk(KERN_DEBUG "smb_dont_catch_keepalive: did not get valid server!\n");
-		goto out;
-	}
-
-	sk = socket->sk;
-	if (sk == NULL)
-	{
-		DEBUG1("sk == NULL");
-		goto out;
-	}
-
-	/* Is this really an error?? */
-	if (server->data_ready == NULL)
-	{
-		printk(KERN_DEBUG "smb_dont_catch_keepalive: "
-		       "server->data_ready == NULL\n");
-		goto out;
-	}
-	DEBUG1("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
-	       (unsigned int) (sk->data_ready),
-	       (unsigned int) (server->data_ready));
-
-	/*
-	 * Restore the original callback atomically to avoid races ...
-	 */
-	data_ready = xchg(&sk->data_ready, server->data_ready);
-	server->data_ready = NULL;
-	if (data_ready != smb_data_ready)
-	{
-		printk(KERN_ERR "smb_dont_catch_keepalive: "
-		       "sk->data_ready != smb_data_ready\n");
-	}
-	error = 0;
-out:
-	return error;
-}
-
-/*
- * Called with the server locked.
- */
 void
 smb_close_socket(struct smb_sb_info *server)
 {
 	struct file * file = server->sock_file;
 
-	if (file)
-	{
-		VERBOSE("closing socket %p\n", server_sock(server));
-#ifdef SMBFS_PARANOIA
-		if (server_sock(server)->sk->data_ready == smb_data_ready)
-			PARANOIA("still catching keepalives!\n");
-#endif
+	if (file) {
+		struct socket *sock = server_sock(server);
+
+		VERBOSE("closing socket %p\n", sock);
+		sock->sk->data_ready = server->data_ready;
 		server->sock_file = NULL;
 		fput(file);
 	}
 }
 
 static int
-smb_send_raw(struct socket *socket, unsigned char *source, int length)
-{
-	int result;
-	int already_sent = 0;
-
-	while (already_sent < length)
-	{
-		result = _send(socket,
-			       (void *) (source + already_sent),
-			       length - already_sent);
-
-		if (result == 0)
-		{
-			return -EIO;
-		}
-		if (result < 0)
-		{
-			DEBUG1("smb_send_raw: sendto error = %d\n", -result);
-			return result;
-		}
-		already_sent += result;
-	}
-	return already_sent;
-}
-
-static int
-smb_receive_raw(struct socket *socket, unsigned char *target, int length)
-{
-	int result;
-	int already_read = 0;
-
-	while (already_read < length)
-	{
-		result = _recvfrom(socket,
-				   (void *) (target + already_read),
-				   length - already_read, 0);
-
-		if (result == 0)
-		{
-			return -EIO;
-		}
-		if (result < 0)
-		{
-			DEBUG1("recvfrom error = %d\n", -result);
-			return result;
-		}
-		already_read += result;
-	}
-	return already_read;
-}
-
-static int
 smb_get_length(struct socket *socket, unsigned char *header)
 {
 	int result;
-	unsigned char peek_buf[4];
-	mm_segment_t fs;
 
-      re_recv:
-	fs = get_fs();
-	set_fs(get_ds());
-	result = smb_receive_raw(socket, peek_buf, 4);
-	set_fs(fs);
-
-	if (result < 0)
-	{
+	result = _recvfrom(socket, header, 4, MSG_PEEK);
+	if (result == -EAGAIN)
+		return -ENODATA;
+	if (result < 0) {
 		PARANOIA("recv error = %d\n", -result);
 		return result;
 	}
-	switch (peek_buf[0])
-	{
+	if (result < 4)
+		return -ENODATA;
+
+	switch (header[0]) {
 	case 0x00:
 	case 0x82:
 		break;
 
 	case 0x85:
 		DEBUG1("Got SESSION KEEP ALIVE\n");
-		goto re_recv;
+		_recvfrom(socket, header, 4, 0);	/* read away */
+		return -ENODATA;
 
 	default:
-		PARANOIA("Invalid NBT packet, code=%x\n", peek_buf[0]);
+		PARANOIA("Invalid NBT packet, code=%x\n", header[0]);
 		return -EIO;
 	}
 
-	if (header != NULL)
-	{
-		memcpy(header, peek_buf, 4);
-	}
 	/* The length in the RFC NB header is the raw data length */
-	return smb_len(peek_buf);
+	return smb_len(header);
 }
 
-/*
- * Since we allocate memory in increments of PAGE_SIZE,
- * round up the packet length to the next multiple.
- */
 int
-smb_round_length(int len)
+smb_recv_available(struct smb_sb_info *server)
 {
-	return (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+	mm_segment_t oldfs;
+	int avail, err;
+	struct socket *sock = server_sock(server);
+
+	oldfs = get_fs();
+	set_fs(get_ds());
+	err = sock->ops->ioctl(sock, SIOCINQ, (unsigned long) &avail);
+	set_fs(oldfs);
+	return (err >= 0) ? avail : err;
 }
- 
+
 /*
- * smb_receive
- * fs points to the correct segment
+ * Adjust the iovec to move on 'n' bytes (from nfs/sunrpc)
  */
 static int
-smb_receive(struct smb_sb_info *server)
+smb_move_iov(struct msghdr *msg, struct iovec *niv, unsigned amount)
 {
-	struct socket *socket = server_sock(server);
-	unsigned char * packet = server->packet;
-	int len, result;
-	unsigned char peek_buf[4];
+	struct iovec *iv = msg->msg_iov;
+	int i;
+	int len;
 
-	result = smb_get_length(socket, peek_buf);
-	if (result < 0)
-		goto out;
-	len = result;
 	/*
-	 * Some servers do not respect our max_xmit and send
-	 * larger packets.  Try to allocate a new packet,
-	 * but don't free the old one unless we succeed.
+	 *	Eat any sent iovecs
 	 */
-	if (len + 4 > server->packet_size)
-	{
-		int new_len = smb_round_length(len + 4);
+	while (iv->iov_len <= amount) {
+		amount -= iv->iov_len;
+		iv++;
+		msg->msg_iovlen--;
+	}
 
-		result = -ENOMEM;
-		packet = smb_vmalloc(new_len);
-		if (packet == NULL)
-			goto out;
-		smb_vfree(server->packet);
-		server->packet = packet;
-		server->packet_size = new_len;
-	}
-	memcpy(packet, peek_buf, 4);
-	result = smb_receive_raw(socket, packet + 4, len);
-	if (result < 0)
-	{
-		VERBOSE("receive error: %d\n", result);
-		goto out;
+	/*
+	 *	And chew down the partial one
+	 */
+	niv[0].iov_len = iv->iov_len-amount;
+	niv[0].iov_base =((unsigned char *)iv->iov_base)+amount;
+	iv++;
+
+	len = niv[0].iov_len;
+
+	/*
+	 *	And copy any others
+	 */
+	for (i = 1; i < msg->msg_iovlen; i++) {
+		niv[i] = *iv++;
+		len += niv[i].iov_len;
 	}
-	server->rcls = *(packet + smb_rcls);
-	server->err  = WVAL(packet, smb_err);
 
-#ifdef SMBFS_DEBUG_VERBOSE
-	if (server->rcls != 0)
-		VERBOSE("rcls=%d, err=%d\n", server->rcls, server->err);
-#endif
-out:
-	return result;
+	msg->msg_iov = niv;
+	return len;
 }
 
 /*
- * This routine checks first for "fast track" processing, as most
- * packets won't need to be copied. Otherwise, it allocates a new
- * packet to hold the incoming data.
- *
- * Note that the final server packet must be the larger of the two;
- * server packets aren't allowed to shrink.
+ * smb_receive_header
+ * Only called by the smbiod thread.
  */
-static int
-smb_receive_trans2(struct smb_sb_info *server,
-		   int *ldata, unsigned char **data,
-		   int *lparm, unsigned char **parm)
-{
-	unsigned char *inbuf, *base, *rcv_buf = NULL;
-	unsigned int parm_disp, parm_offset, parm_count, parm_tot, parm_len = 0;
-	unsigned int data_disp, data_offset, data_count, data_tot, data_len = 0;
-	unsigned int total_p = 0, total_d = 0, buf_len = 0;
-	int result;
+int
+smb_receive_header(struct smb_sb_info *server)
+{
+	struct socket *sock;
+	int result = 0;
+	unsigned char peek_buf[4];
+
+	result = -EIO; 
+	sock = server_sock(server);
+	if (!sock)
+		goto out;
+	if (sock->sk->state != TCP_ESTABLISHED)
+		goto out;
 
-	while (1) {
-		result = smb_receive(server);
-		if (result < 0)
+	if (!server->smb_read) {
+		result = smb_get_length(sock, peek_buf);
+		if (result < 0) {
+			if (result == -ENODATA)
+				result = 0;
 			goto out;
-		inbuf = server->packet;
-		if (server->rcls != 0) {
-			*parm = *data = inbuf;
-			*ldata = *lparm = 0;
+		}
+		server->smb_len = result + 4;
+
+		if (server->smb_len < SMB_HEADER_LEN) {
+			PARANOIA("short packet: %d\n", result);
+			server->rstate = SMB_RECV_DROP;
+			result = -EIO;
+			goto out;
+		}
+		if (server->smb_len > SMB_MAX_PACKET_SIZE) {
+			PARANOIA("long packet: %d\n", result);
+			server->rstate = SMB_RECV_DROP;
+			result = -EIO;
 			goto out;
 		}
-		/*
-		 * Extract the control data from the packet.
-		 */
-		data_tot    = WVAL(inbuf, smb_tdrcnt);
-		parm_tot    = WVAL(inbuf, smb_tprcnt);
-		parm_disp   = WVAL(inbuf, smb_prdisp);
-		parm_offset = WVAL(inbuf, smb_proff);
-		parm_count  = WVAL(inbuf, smb_prcnt);
-		data_disp   = WVAL(inbuf, smb_drdisp);
-		data_offset = WVAL(inbuf, smb_droff);
-		data_count  = WVAL(inbuf, smb_drcnt);
-		base = smb_base(inbuf);
-
-		/*
-		 * Assume success and increment lengths.
-		 */
-		parm_len += parm_count;
-		data_len += data_count;
-
-		if (!rcv_buf) {
-			/*
-			 * Check for fast track processing ... just this packet.
-			 */
-			if (parm_count == parm_tot && data_count == data_tot) {
-				VERBOSE("fast track, parm=%u %u %u, data=%u %u %u\n",
-					parm_disp, parm_offset, parm_count,
-					data_disp, data_offset, data_count);
-				*parm  = base + parm_offset;
-				*data  = base + data_offset;
-				goto success;
-			}
-
-			/*
-			 * Save the total parameter and data length.
-			 */
-			total_d = data_tot;
-			total_p = parm_tot;
-
-			buf_len = total_d + total_p;
-			if (server->packet_size > buf_len)
-				buf_len = server->packet_size;
-			buf_len = smb_round_length(buf_len);
-			if (buf_len > SMB_MAX_PACKET_SIZE)
-				goto out_too_long;
-
-			rcv_buf = smb_vmalloc(buf_len);
-			if (!rcv_buf)
-				goto out_no_mem;
-			*parm = rcv_buf;
-			*data = rcv_buf + total_p;
-		} else if (data_tot > total_d || parm_tot > total_p)
-			goto out_data_grew;
-
-		if (parm_disp + parm_count > total_p)
-			goto out_bad_parm;
-		if (data_disp + data_count > total_d)
-			goto out_bad_data;
-		memcpy(*parm + parm_disp, base + parm_offset, parm_count);
-		memcpy(*data + data_disp, base + data_offset, data_count);
-
-		PARANOIA("copied, parm=%u of %u, data=%u of %u\n",
-			 parm_len, parm_tot, data_len, data_tot);
-
-		/*
-		 * Check whether we've received all of the data. Note that
-		 * we use the packet totals -- total lengths might shrink!
-		 */
-		if (data_len >= data_tot && parm_len >= parm_tot)
-			break;
 	}
 
-	/*
-	 * Install the new packet.  Note that it's possible, though
-	 * unlikely, that the new packet could be smaller than the
-	 * old one, in which case we just copy the data.
-	 */
-	inbuf = server->packet;
-	if (buf_len >= server->packet_size) {
-		server->packet_size = buf_len;
-		server->packet = rcv_buf;
-		rcv_buf = inbuf;
-	} else {
-		PARANOIA("copying data, old size=%d, new size=%u\n",
-			 server->packet_size, buf_len);
-		memcpy(inbuf, rcv_buf, parm_len + data_len);
+	result = _recvfrom(sock, server->header + server->smb_read,
+			   SMB_HEADER_LEN - server->smb_read, 0);
+	VERBOSE("_recvfrom: %d\n", result);
+	if (result < 0) {
+		VERBOSE("receive error: %d\n", result);
+		goto out;
 	}
+	server->smb_read += result;
 
-success:
-	*ldata = data_len;
-	*lparm = parm_len;
+	if (server->smb_read == SMB_HEADER_LEN)
+		server->rstate = SMB_RECV_HCOMPLETE;
 out:
-	if (rcv_buf)
-		smb_vfree(rcv_buf);
 	return result;
-
-out_no_mem:
-	PARANOIA("couldn't allocate data area\n");
-	result = -ENOMEM;
-	goto out;
-out_too_long:
-	printk(KERN_ERR "smb_receive_trans2: data/param too long, data=%d, parm=%d\n",
-		data_tot, parm_tot);
-	goto out_error;
-out_data_grew:
-	printk(KERN_ERR "smb_receive_trans2: data/params grew!\n");
-	goto out_error;
-out_bad_parm:
-	printk(KERN_ERR "smb_receive_trans2: invalid parms, disp=%d, cnt=%d, tot=%d\n",
-		parm_disp, parm_count, parm_tot);
-	goto out_error;
-out_bad_data:
-	printk(KERN_ERR "smb_receive_trans2: invalid data, disp=%d, cnt=%d, tot=%d\n",
-		data_disp, data_count, data_tot);
-out_error:
-	result = -EIO;
-	goto out;
 }
 
+static char drop_buffer[PAGE_SIZE];
+
 /*
- * Called with the server locked
+ * smb_receive_drop - read and throw away the data
+ * Only called by the smbiod thread.
+ *
+ * FIXME: we are in the kernel, could we just tell the socket that we want
+ * to drop stuff from the buffer?
  */
 int
-smb_request(struct smb_sb_info *server)
+smb_receive_drop(struct smb_sb_info *server)
 {
-	unsigned long flags, sigpipe;
+	struct socket *sock;
+	unsigned int flags;
+	struct iovec iov;
+	struct msghdr msg;
+	struct scm_cookie scm;
 	mm_segment_t fs;
-	sigset_t old_set;
-	int len, result;
-	unsigned char *buffer;
-
-	result = -EBADF;
-	buffer = server->packet;
-	if (!buffer)
-		goto bad_no_packet;
-
-	result = -EIO;
-	if (server->state != CONN_VALID)
-		goto bad_no_conn;
-
-	if ((result = smb_dont_catch_keepalive(server)) != 0)
-		goto bad_conn;
-
-	len = smb_len(buffer) + 4;
-	DEBUG1("len = %d cmd = 0x%X\n", len, buffer[8]);
-
-	spin_lock_irqsave(&current->sigmask_lock, flags);
-	sigpipe = sigismember(&current->pending.signal, SIGPIPE);
-	old_set = current->blocked;
-	siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));
-	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
+	int rlen = smb_len(server->header) - server->smb_read + 4;
+	int result = -EIO;
+
+	sock = server_sock(server);
+	if (!sock)
+		goto out;
+	if (sock->sk->state != TCP_ESTABLISHED)
+		goto out;
 
 	fs = get_fs();
 	set_fs(get_ds());
 
-	result = smb_send_raw(server_sock(server), (void *) buffer, len);
-	if (result > 0)
-	{
-		result = smb_receive(server);
-	}
+	flags = MSG_DONTWAIT | MSG_NOSIGNAL;
+	iov.iov_base = drop_buffer;
+	iov.iov_len = PAGE_SIZE;
+	msg.msg_flags = flags;
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = NULL;
 
-	/* read/write errors are handled by errno */
-	spin_lock_irqsave(&current->sigmask_lock, flags);
-	if (result == -EPIPE && !sigpipe)
-		sigdelset(&current->pending.signal, SIGPIPE);
-	current->blocked = old_set;
-	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
+	if (rlen > PAGE_SIZE)
+		rlen = PAGE_SIZE;
+
+	memset(&scm, 0, sizeof(scm));
+	result = sock->ops->recvmsg(sock, &msg, rlen, flags, &scm);
+	if (result >= 0)
+		scm_recv(sock, &msg, &scm, flags);
 
 	set_fs(fs);
 
-	if (result >= 0)
-	{
-		int result2 = smb_catch_keepalive(server);
-		if (result2 < 0)
-		{
-			printk(KERN_ERR "smb_request: catch keepalive failed\n");
-			result = result2;
-		}
-	}
-	if (result < 0)
-		goto bad_conn;
-	/*
-	 * Check for fatal server errors ...
-	 */
-	if (server->rcls) {
-		int error = smb_errno(server);
-		if (error == -EBADSLT) {
-			printk(KERN_ERR "smb_request: tree ID invalid\n");
-			result = error;
-			goto bad_conn;
-		}
+	VERBOSE("read: %d\n", result);
+	if (result < 0) {
+		VERBOSE("receive error: %d\n", result);
+		goto out;
 	}
+	server->smb_read += result;
+
+	if (server->smb_read >= server->smb_len)
+		server->rstate = SMB_RECV_END;
 
 out:
-	DEBUG1("result = %d\n", result);
 	return result;
-	
-bad_conn:
-	PARANOIA("result %d, setting invalid\n", result);
-	server->state = CONN_INVALID;
-	smb_invalidate_inodes(server);
-	goto out;		
-bad_no_packet:
-	printk(KERN_ERR "smb_request: no packet!\n");
-	goto out;
-bad_no_conn:
-	printk(KERN_ERR "smb_request: connection %d not valid!\n",
-	       server->state);
-	goto out;
 }
 
-#define ROUND_UP(x) (((x)+3) & ~3)
-static int
-smb_send_trans2(struct smb_sb_info *server, __u16 trans2_command,
-		int ldata, unsigned char *data,
-		int lparam, unsigned char *param)
+/*
+ * smb_receive
+ * Only called by the smbiod thread.
+ */
+int
+smb_receive(struct smb_sb_info *server, struct smb_request *req)
 {
-	struct socket *sock = server_sock(server);
-	struct scm_cookie scm;
-	int err;
-	int mparam, mdata;
-
-	/* I know the following is very ugly, but I want to build the
-	   smb packet as efficiently as possible. */
-
-	const int smb_parameters = 15;
-	const int oparam =
-		ROUND_UP(SMB_HEADER_LEN + 2 * smb_parameters + 2 + 3);
-	const int odata =
-		ROUND_UP(oparam + lparam);
-	const int bcc =
-		odata + ldata - (SMB_HEADER_LEN + 2 * smb_parameters + 2);
-	const int packet_length =
-		SMB_HEADER_LEN + 2 * smb_parameters + bcc + 2;
-
-	unsigned char padding[4] =
-	{0,};
-	char *p;
-
+	struct socket *sock;
+	unsigned int flags;
 	struct iovec iov[4];
 	struct msghdr msg;
+	struct scm_cookie scm;
+	mm_segment_t fs;
+	int rlen;
+	int result = -EIO;
 
-	/* FIXME! this test needs to include SMB overhead too, I think ... */
-	if ((bcc + oparam) > server->opt.max_xmit)
-		return -ENOMEM;
-	p = smb_setup_header(server, SMBtrans2, smb_parameters, bcc);
-
-	/*
-	 * max parameters + max data + max setup == max_xmit to make NT4 happy
-	 * and not abort the transfer or split into multiple responses.
-	 *
-	 * -100 is to make room for headers, which OS/2 seems to include in the
-	 * size calculation while NT4 does not?
-	 */
-	mparam = SMB_TRANS2_MAX_PARAM;
-	mdata = server->opt.max_xmit - mparam - 100;
-	if (mdata < 1024) {
-		mdata = 1024;
-		mparam = 20;
-	}
-
-	WSET(server->packet, smb_tpscnt, lparam);
-	WSET(server->packet, smb_tdscnt, ldata);
-	WSET(server->packet, smb_mprcnt, mparam);
-	WSET(server->packet, smb_mdrcnt, mdata);
-	WSET(server->packet, smb_msrcnt, 0);    /* max setup always 0 ? */
-	WSET(server->packet, smb_flags, 0);
-	DSET(server->packet, smb_timeout, 0);
-	WSET(server->packet, smb_pscnt, lparam);
-	WSET(server->packet, smb_psoff, oparam - 4);
-	WSET(server->packet, smb_dscnt, ldata);
-	WSET(server->packet, smb_dsoff, odata - 4);
-	WSET(server->packet, smb_suwcnt, 1);
-	WSET(server->packet, smb_setup0, trans2_command);
-	*p++ = 0;		/* null smb_name for trans2 */
-	*p++ = 'D';		/* this was added because OS/2 does it */
-	*p++ = ' ';
+	sock = server_sock(server);
+	if (!sock)
+		goto out;
+	if (sock->sk->state != TCP_ESTABLISHED)
+		goto out;
 
+	fs = get_fs();
+	set_fs(get_ds());
 
+	flags = MSG_DONTWAIT | MSG_NOSIGNAL;;
+	msg.msg_flags = flags;
 	msg.msg_name = NULL;
 	msg.msg_namelen = 0;
+	msg.msg_iov = req->rq_iov;
+	msg.msg_iovlen = req->rq_iovlen;
 	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
-	msg.msg_iov = iov;
-	msg.msg_iovlen = 4;
-	msg.msg_flags = 0;
-	
-	iov[0].iov_base = (void *) server->packet;
-	iov[0].iov_len = oparam;
-	iov[1].iov_base = (param == NULL) ? padding : param;
-	iov[1].iov_len = lparam;
-	iov[2].iov_base = padding;
-	iov[2].iov_len = odata - oparam - lparam;
-	iov[3].iov_base = (data == NULL) ? padding : data;
-	iov[3].iov_len = ldata;
-
-	err = scm_send(sock, &msg, &scm);
-        if (err >= 0) {
-		err = sock->ops->sendmsg(sock, &msg, packet_length, &scm);
-		scm_destroy(&scm);
+
+	/* Dont repeat bytes and count available bufferspace */
+	rlen = smb_move_iov(&msg, iov, req->rq_bytes_recvd);
+	if (req->rq_rlen < rlen)
+		rlen = req->rq_rlen;
+
+	memset(&scm, 0, sizeof(scm));
+	result = sock->ops->recvmsg(sock, &msg, rlen, flags, &scm);
+	if (result >= 0)
+		scm_recv(sock, &msg, &scm, flags);
+
+	set_fs(fs);
+
+	VERBOSE("read: %d\n", result);
+	if (result < 0) {
+		VERBOSE("receive error: %d\n", result);
+		goto out;
 	}
-	return err;
+	req->rq_bytes_recvd += result;
+	server->smb_read += result;
+
+out:
+	return result;
 }
 
 /*
- * This is not really a trans2 request, we assume that you only have
- * one packet to send.
+ * Try to send a SMB request. This may return after sending only parts of the
+ * request. SMB_REQ_TRANSMITTED will be set if a request was fully sent.
+ *
+ * Parts of this was taken from xprt_sendmsg from net/sunrpc/xprt.c
  */
 int
-smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
-		   int ldata, unsigned char *data,
-		   int lparam, unsigned char *param,
-		   int *lrdata, unsigned char **rdata,
-		   int *lrparam, unsigned char **rparam)
+smb_send_request(struct smb_request *req)
 {
-	sigset_t old_set;
-	unsigned long flags, sigpipe;
 	mm_segment_t fs;
-	int result;
-
-	DEBUG1("com=%d, ld=%d, lp=%d\n", trans2_command, ldata, lparam);
-
-	/*
-	 * These are initialized in smb_request_ok, but not here??
-	 */
-	server->rcls = 0;
-	server->err = 0;
+	struct smb_sb_info *server = req->rq_server;
+	struct socket *sock;
+	struct scm_cookie scm;
+	struct msghdr msg;
+        int slen = req->rq_slen - req->rq_bytes_sent;
+	int result = -EIO;
+	struct iovec iov[4];
 
-	result = -EIO;
-	if (server->state != CONN_VALID)
+	sock = server_sock(server);
+	if (!sock)
+		goto out;
+	if (sock->sk->state != TCP_ESTABLISHED)
 		goto out;
 
-	if ((result = smb_dont_catch_keepalive(server)) != 0)
-		goto bad_conn;
-
-	spin_lock_irqsave(&current->sigmask_lock, flags);
-	sigpipe = sigismember(&current->pending.signal, SIGPIPE);
-	old_set = current->blocked;
-	siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));
-	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_iov = req->rq_iov;
+	msg.msg_iovlen = req->rq_iovlen;
+	msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT;
+
+	/* Dont repeat bytes */
+	if (req->rq_bytes_sent)
+		smb_move_iov(&msg, iov, req->rq_bytes_sent);
 
 	fs = get_fs();
 	set_fs(get_ds());
-
-	result = smb_send_trans2(server, trans2_command,
-				 ldata, data, lparam, param);
-	if (result >= 0)
-	{
-		result = smb_receive_trans2(server,
-					    lrdata, rdata, lrparam, rparam);
+	result = scm_send(sock, &msg, &scm);
+	if (result >= 0) {
+		result = sock->ops->sendmsg(sock, &msg, slen, &scm);
+		scm_destroy(&scm);
 	}
-
-	/* read/write errors are handled by errno */
-	spin_lock_irqsave(&current->sigmask_lock, flags);
-	if (result == -EPIPE && !sigpipe)
-		sigdelset(&current->pending.signal, SIGPIPE);
-	current->blocked = old_set;
-	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
-
 	set_fs(fs);
 
-	if (result >= 0)
-	{
-		int result2 = smb_catch_keepalive(server);
-		if (result2 < 0)
-		{
-			result = result2;
-		}
+	if (result >= 0) {
+		req->rq_bytes_sent += result;
+		if (req->rq_bytes_sent >= req->rq_slen)
+			req->rq_flags |= SMB_REQ_TRANSMITTED;
 	}
-	if (result < 0)
-		goto bad_conn;
-	/*
-	 * Check for fatal server errors ...
-	 */
-	if (server->rcls) {
-		int error = smb_errno(server);
-		if (error == -EBADSLT) {
-			printk(KERN_ERR "smb_request: tree ID invalid\n");
-			result = error;
-			goto bad_conn;
-		}
-	}
-
 out:
 	return result;
-
-bad_conn:
-	PARANOIA("result=%d, setting invalid\n", result);
-	server->state = CONN_INVALID;
-	smb_invalidate_inodes(server);
-	goto out;
 }
diff -Nru a/include/asm-alpha/siginfo.h b/include/asm-alpha/siginfo.h
--- a/include/asm-alpha/siginfo.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-alpha/siginfo.h	Tue Jul 16 16:49:42 2002
@@ -6,7 +6,6 @@
 #define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
 
 #define HAVE_ARCH_COPY_SIGINFO
-#define HAVE_ARCH_COPY_SIGINFO_TO_USER
 
 #include <asm-generic/siginfo.h>
 
diff -Nru a/include/asm-arm/arch-adifcc/param.h b/include/asm-arm/arch-adifcc/param.h
--- a/include/asm-arm/arch-adifcc/param.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/arch-adifcc/param.h	Tue Jul 16 16:49:42 2002
@@ -1,3 +1,3 @@
 /*
- * linux/include/asm-arm/arch-adifcc/param.h
+ *  linux/include/asm-arm/arch-adifcc/param.h
  */
diff -Nru a/include/asm-arm/arch-anakin/param.h b/include/asm-arm/arch-anakin/param.h
--- a/include/asm-arm/arch-anakin/param.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/arch-anakin/param.h	Tue Jul 16 16:49:42 2002
@@ -11,11 +11,6 @@
  *   11-Apr-2001 TTC	Created
  */
 
-#ifndef __ASM_ARCH_PARAM_H
-#define __ASM_ARCH_PARAM_H
-
 /*
  * Reserved for future use
  */
-
-#endif
diff -Nru a/include/asm-arm/arch-arc/param.h b/include/asm-arm/arch-arc/param.h
--- a/include/asm-arm/arch-arc/param.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-arm/arch-arc/param.h	Tue Jul 16 16:49:41 2002
@@ -1,3 +1,3 @@
 /*
- * linux/include/asm-arm/arch-arc/param.h
+ *  linux/include/asm-arm/arch-arc/param.h
  */
diff -Nru a/include/asm-arm/arch-cl7500/param.h b/include/asm-arm/arch-cl7500/param.h
--- a/include/asm-arm/arch-cl7500/param.h	Tue Jul 16 16:49:43 2002
+++ b/include/asm-arm/arch-cl7500/param.h	Tue Jul 16 16:49:43 2002
@@ -1,7 +1,5 @@
 /*
- * linux/include/asm-arm/arch-cl7500/param.h
+ *  linux/include/asm-arm/arch-cl7500/param.h
  *
  * Copyright (C) 1999 Nexus Electronics Ltd
  */
-
-#define HZ 100
diff -Nru a/include/asm-arm/arch-clps711x/param.h b/include/asm-arm/arch-clps711x/param.h
--- a/include/asm-arm/arch-clps711x/param.h	Tue Jul 16 16:49:43 2002
+++ b/include/asm-arm/arch-clps711x/param.h	Tue Jul 16 16:49:43 2002
@@ -17,5 +17,3 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
-#define HZ 100
diff -Nru a/include/asm-arm/arch-ebsa110/param.h b/include/asm-arm/arch-ebsa110/param.h
--- a/include/asm-arm/arch-ebsa110/param.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-arm/arch-ebsa110/param.h	Tue Jul 16 16:49:41 2002
@@ -1,3 +1,3 @@
 /*
- * linux/include/asm-arm/arch-ebsa110/param.h
+ *  linux/include/asm-arm/arch-ebsa110/param.h
  */
diff -Nru a/include/asm-arm/arch-ebsa285/param.h b/include/asm-arm/arch-ebsa285/param.h
--- a/include/asm-arm/arch-ebsa285/param.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/arch-ebsa285/param.h	Tue Jul 16 16:49:42 2002
@@ -1,3 +1,3 @@
 /*
- * linux/include/asm-arm/arch-ebsa285/param.h
+ *  linux/include/asm-arm/arch-ebsa285/param.h
  */
diff -Nru a/include/asm-arm/arch-epxa10db/param.h b/include/asm-arm/arch-epxa10db/param.h
--- a/include/asm-arm/arch-epxa10db/param.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/arch-epxa10db/param.h	Tue Jul 16 16:49:42 2002
@@ -17,5 +17,3 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
-#define HZ 100
diff -Nru a/include/asm-arm/arch-integrator/param.h b/include/asm-arm/arch-integrator/param.h
--- a/include/asm-arm/arch-integrator/param.h	Tue Jul 16 16:49:43 2002
+++ b/include/asm-arm/arch-integrator/param.h	Tue Jul 16 16:49:43 2002
@@ -17,5 +17,3 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
-#define HZ 100
diff -Nru a/include/asm-arm/arch-iop310/param.h b/include/asm-arm/arch-iop310/param.h
--- a/include/asm-arm/arch-iop310/param.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-arm/arch-iop310/param.h	Tue Jul 16 16:49:41 2002
@@ -1,3 +1,3 @@
 /*
- * linux/include/asm-arm/arch-iop80310/param.h
+ *  linux/include/asm-arm/arch-iop80310/param.h
  */
diff -Nru a/include/asm-arm/arch-l7200/param.h b/include/asm-arm/arch-l7200/param.h
--- a/include/asm-arm/arch-l7200/param.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/arch-l7200/param.h	Tue Jul 16 16:49:42 2002
@@ -1,5 +1,5 @@
 /*
- * linux/include/asm-arm/arch-l7200/param.h
+ *  linux/include/asm-arm/arch-l7200/param.h
  *
  * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net)
  *                    Steve Hill (sjhill@cotw.com)
@@ -12,21 +12,8 @@
  *   04-25-2000 SJH     Cleaned up file
  *   05-03-2000 SJH     Change comments and rate
  */
-#ifndef __ASM_ARCH_PARAM_H
-#define __ASM_ARCH_PARAM_H
 
 /*
  * See 'time.h' for how the RTC HZ rate is set
  */
-#define HZ 128
-
-/*
- * Define hz_to_std, since we have a non 100Hz define
- * (see include/asm-arm/param.h)
- */
-
-#if defined(__KERNEL__)
-#define hz_to_std(a) ((a * HZ)/100)
-#endif
-
-#endif
+#define __KERNEL_HZ 128
diff -Nru a/include/asm-arm/arch-nexuspci/param.h b/include/asm-arm/arch-nexuspci/param.h
--- a/include/asm-arm/arch-nexuspci/param.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-arm/arch-nexuspci/param.h	Tue Jul 16 16:49:41 2002
@@ -1,3 +1,3 @@
 /*
- * linux/include/asm-arm/arch-nexuspci/param.h
+ *  linux/include/asm-arm/arch-nexuspci/param.h
  */
diff -Nru a/include/asm-arm/arch-rpc/param.h b/include/asm-arm/arch-rpc/param.h
--- a/include/asm-arm/arch-rpc/param.h	Tue Jul 16 16:49:43 2002
+++ b/include/asm-arm/arch-rpc/param.h	Tue Jul 16 16:49:43 2002
@@ -1,3 +1,3 @@
 /*
- * linux/include/asm-arm/arch-rpc/param.h
+ *  linux/include/asm-arm/arch-rpc/param.h
  */
diff -Nru a/include/asm-arm/arch-sa1100/assabet.h b/include/asm-arm/arch-sa1100/assabet.h
--- a/include/asm-arm/arch-sa1100/assabet.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-arm/arch-sa1100/assabet.h	Tue Jul 16 16:49:41 2002
@@ -25,6 +25,13 @@
 
 #define ASSABET_SCR_INIT	-1
 
+extern unsigned long SCR_value;
+
+#ifdef CONFIG_ASSABET_NEPONSET
+#define machine_has_neponset()  ((SCR_value & ASSABET_SCR_SA1111) == 0)
+#else
+#define machine_has_neponset()	(0)
+#endif
 
 /* Board Control Register */
 
@@ -57,8 +64,6 @@
 #define ASSABET_BCR_RAD_ON	(1<<22)	/* Radio Power On */
 #define ASSABET_BCR_SPK_OFF	(1<<23)	/* 1 = Speaker amplifier power off */
 
-extern unsigned long SCR_value;
-
 #ifdef CONFIG_SA1100_ASSABET
 extern void ASSABET_BCR_frob(unsigned int mask, unsigned int set);
 #else
@@ -97,71 +102,5 @@
 #define ASSABET_IRQ_GPIO_CF_CD		IRQ_GPIO22
 #define ASSABET_IRQ_GPIO_CF_BVD2	IRQ_GPIO24
 #define ASSABET_IRQ_GPIO_CF_BVD1	IRQ_GPIO25
-
-
-/*
- * Neponset definitions: 
- */
-
-#define NEPONSET_CPLD_BASE      (0x10000000)
-#define Nep_p2v( x )            ((x) - NEPONSET_CPLD_BASE + 0xf3000000)
-#define Nep_v2p( x )            ((x) - 0xf3000000 + NEPONSET_CPLD_BASE)
-
-#define _IRR                    0x10000024      /* Interrupt Reason Register */
-#define _AUD_CTL                0x100000c0      /* Audio controls (RW)       */
-#define _MDM_CTL_0              0x100000b0      /* Modem control 0 (RW)      */
-#define _MDM_CTL_1              0x100000b4      /* Modem control 1 (RW)      */
-#define _NCR_0	                0x100000a0      /* Control Register (RW)     */
-#define _KP_X_OUT               0x10000090      /* Keypad row write (RW)     */
-#define _KP_Y_IN                0x10000080      /* Keypad column read (RO)   */
-#define _SWPK                   0x10000020      /* Switch pack (RO)          */
-#define _WHOAMI                 0x10000000      /* System ID Register (RO)   */
-
-#define _LEDS                   0x10000010      /* LEDs [31:0] (WO)          */
-
-#define IRR                     (*((volatile u_char *) Nep_p2v(_IRR)))
-#define AUD_CTL                 (*((volatile u_char *) Nep_p2v(_AUD_CTL)))
-#define MDM_CTL_0               (*((volatile u_char *) Nep_p2v(_MDM_CTL_0)))
-#define MDM_CTL_1               (*((volatile u_char *) Nep_p2v(_MDM_CTL_1)))
-#define NCR_0			(*((volatile u_char *) Nep_p2v(_NCR_0)))
-#define KP_X_OUT                (*((volatile u_char *) Nep_p2v(_KP_X_OUT)))
-#define KP_Y_IN                 (*((volatile u_char *) Nep_p2v(_KP_Y_IN)))
-#define SWPK                    (*((volatile u_char *) Nep_p2v(_SWPK)))
-#define WHOAMI                  (*((volatile u_char *) Nep_p2v(_WHOAMI)))
-
-#define LEDS                    (*((volatile Word   *) Nep_p2v(_LEDS)))
-
-#define IRR_ETHERNET		(1<<0)
-#define IRR_USAR		(1<<1)
-#define IRR_SA1111		(1<<2)
-
-#define AUD_SEL_1341            (1<<0)
-#define AUD_MUTE_1341           (1<<1)
-
-#define MDM_CTL0_RTS1		(1 << 0)
-#define MDM_CTL0_DTR1		(1 << 1)
-#define MDM_CTL0_RTS2		(1 << 2)
-#define MDM_CTL0_DTR2		(1 << 3)
-
-#define MDM_CTL1_CTS1		(1 << 0)
-#define MDM_CTL1_DSR1		(1 << 1)
-#define MDM_CTL1_DCD1		(1 << 2)
-#define MDM_CTL1_CTS2		(1 << 3)
-#define MDM_CTL1_DSR2		(1 << 4)
-#define MDM_CTL1_DCD2		(1 << 5)
-
-#define NCR_GP01_OFF		(1<<0)
-#define NCR_TP_PWR_EN		(1<<1)
-#define NCR_MS_PWR_EN		(1<<2)
-#define NCR_ENET_OSC_EN		(1<<3)
-#define NCR_SPI_KB_WK_UP	(1<<4)
-#define NCR_A0VPP		(1<<5)
-#define NCR_A1VPP		(1<<6)
-
-#ifdef CONFIG_ASSABET_NEPONSET
-#define machine_has_neponset()  ((SCR_value & ASSABET_SCR_SA1111) == 0)
-#else
-#define machine_has_neponset()	(0)
-#endif
 
 #endif
diff -Nru a/include/asm-arm/arch-sa1100/neponset.h b/include/asm-arm/arch-sa1100/neponset.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-arm/arch-sa1100/neponset.h	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,74 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/assabet.h
+ *
+ * Created 2000/06/05 by Nicolas Pitre <nico@cam.org>
+ *
+ * This file contains the hardware specific definitions for Assabet
+ * Only include this file from SA1100-specific files.
+ *
+ * 2000/05/23 John Dorsey <john+@cs.cmu.edu>
+ *      Definitions for Neponset added.
+ */
+#ifndef __ASM_ARCH_NEPONSET_H
+#define __ASM_ARCH_NEPONSET_H
+
+/*
+ * Neponset definitions: 
+ */
+
+#define NEPONSET_CPLD_BASE      (0x10000000)
+#define Nep_p2v( x )            ((x) - NEPONSET_CPLD_BASE + 0xf3000000)
+#define Nep_v2p( x )            ((x) - 0xf3000000 + NEPONSET_CPLD_BASE)
+
+#define _IRR                    0x10000024      /* Interrupt Reason Register */
+#define _AUD_CTL                0x100000c0      /* Audio controls (RW)       */
+#define _MDM_CTL_0              0x100000b0      /* Modem control 0 (RW)      */
+#define _MDM_CTL_1              0x100000b4      /* Modem control 1 (RW)      */
+#define _NCR_0	                0x100000a0      /* Control Register (RW)     */
+#define _KP_X_OUT               0x10000090      /* Keypad row write (RW)     */
+#define _KP_Y_IN                0x10000080      /* Keypad column read (RO)   */
+#define _SWPK                   0x10000020      /* Switch pack (RO)          */
+#define _WHOAMI                 0x10000000      /* System ID Register (RO)   */
+
+#define _LEDS                   0x10000010      /* LEDs [31:0] (WO)          */
+
+#define IRR                     (*((volatile u_char *) Nep_p2v(_IRR)))
+#define AUD_CTL                 (*((volatile u_char *) Nep_p2v(_AUD_CTL)))
+#define MDM_CTL_0               (*((volatile u_char *) Nep_p2v(_MDM_CTL_0)))
+#define MDM_CTL_1               (*((volatile u_char *) Nep_p2v(_MDM_CTL_1)))
+#define NCR_0			(*((volatile u_char *) Nep_p2v(_NCR_0)))
+#define KP_X_OUT                (*((volatile u_char *) Nep_p2v(_KP_X_OUT)))
+#define KP_Y_IN                 (*((volatile u_char *) Nep_p2v(_KP_Y_IN)))
+#define SWPK                    (*((volatile u_char *) Nep_p2v(_SWPK)))
+#define WHOAMI                  (*((volatile u_char *) Nep_p2v(_WHOAMI)))
+
+#define LEDS                    (*((volatile Word   *) Nep_p2v(_LEDS)))
+
+#define IRR_ETHERNET		(1<<0)
+#define IRR_USAR		(1<<1)
+#define IRR_SA1111		(1<<2)
+
+#define AUD_SEL_1341            (1<<0)
+#define AUD_MUTE_1341           (1<<1)
+
+#define MDM_CTL0_RTS1		(1 << 0)
+#define MDM_CTL0_DTR1		(1 << 1)
+#define MDM_CTL0_RTS2		(1 << 2)
+#define MDM_CTL0_DTR2		(1 << 3)
+
+#define MDM_CTL1_CTS1		(1 << 0)
+#define MDM_CTL1_DSR1		(1 << 1)
+#define MDM_CTL1_DCD1		(1 << 2)
+#define MDM_CTL1_CTS2		(1 << 3)
+#define MDM_CTL1_DSR2		(1 << 4)
+#define MDM_CTL1_DCD2		(1 << 5)
+
+#define NCR_GP01_OFF		(1<<0)
+#define NCR_TP_PWR_EN		(1<<1)
+#define NCR_MS_PWR_EN		(1<<2)
+#define NCR_ENET_OSC_EN		(1<<3)
+#define NCR_SPI_KB_WK_UP	(1<<4)
+#define NCR_A0VPP		(1<<5)
+#define NCR_A1VPP		(1<<6)
+
+#endif
diff -Nru a/include/asm-arm/arch-sa1100/param.h b/include/asm-arm/arch-sa1100/param.h
--- a/include/asm-arm/arch-sa1100/param.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/arch-sa1100/param.h	Tue Jul 16 16:49:42 2002
@@ -1,3 +1,3 @@
 /*
- * linux/include/asm-arm/arch-sa1100/param.h
+ *  linux/include/asm-arm/arch-sa1100/param.h
  */
diff -Nru a/include/asm-arm/arch-sa1100/pfs168.h b/include/asm-arm/arch-sa1100/pfs168.h
--- a/include/asm-arm/arch-sa1100/pfs168.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/arch-sa1100/pfs168.h	Tue Jul 16 16:49:42 2002
@@ -47,8 +47,6 @@
 #define SA1111_BASE             (0x40000000)
 
 #ifndef __ASSEMBLY__
-#define machine_has_neponset() (0)
-
 #define PFS168_COM5_VBASE		(*((volatile unsigned char *)(0xf0000000UL)))
 #define PFS168_COM6_VBASE		(*((volatile unsigned char *)(0xf0001000UL)))
 #define PFS168_SYSC1RTS			(*((volatile unsigned char *)(0xf0002000UL)))
diff -Nru a/include/asm-arm/arch-sa1100/serial.h b/include/asm-arm/arch-sa1100/serial.h
--- a/include/asm-arm/arch-sa1100/serial.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-arm/arch-sa1100/serial.h	Tue Jul 16 16:49:41 2002
@@ -7,6 +7,26 @@
  * This is included by serial.c -- serial_sa1100.c makes no use of it.
  */
 
+/* Standard COM flags */
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+
+/*
+ * Rather empty table...
+ * Hardwired serial ports should be defined here.
+ * PCMCIA will fill it dynamically.
+ */
+#ifdef CONFIG_SA1100_TRIZEPS
+
+#define RS_TABLE_SIZE 2
+
+#define STD_SERIAL_PORT_DEFNS	\
+       /* UART	CLK     	PORT		IRQ		FLAGS		*/ \
+	{ 0,	1500000,	TRIZEPS_UART5,	IRQ_GPIO16,	STD_COM_FLAGS },   \
+	{ 0,	1500000,	TRIZEPS_UART6,	IRQ_GPIO17,	STD_COM_FLAGS }
+
+#else
+
+#define RS_TABLE_SIZE 4
 
 /*
  * This assumes you have a 1.8432 MHz clock for your UART.
@@ -17,17 +37,6 @@
  */
 #define BASE_BAUD ( 1843200 / 16 )
 
-/* Standard COM flags */
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-#define RS_TABLE_SIZE 4
-
-
-/*
- * Rather empty table...
- * Hardwired serial ports should be defined here.
- * PCMCIA will fill it dynamically.
- */
 #define STD_SERIAL_PORT_DEFNS	\
        /* UART	CLK     	PORT		IRQ	FLAGS		*/ \
 	{ 0,	BASE_BAUD,	0, 		0,	STD_COM_FLAGS },   \
@@ -35,5 +44,6 @@
 	{ 0,	BASE_BAUD,	0, 		0,	STD_COM_FLAGS },   \
 	{ 0,	BASE_BAUD,	0, 		0,	STD_COM_FLAGS }
 
-#define EXTRA_SERIAL_PORT_DEFNS
+#endif
 
+#define EXTRA_SERIAL_PORT_DEFNS
diff -Nru a/include/asm-arm/arch-shark/param.h b/include/asm-arm/arch-shark/param.h
--- a/include/asm-arm/arch-shark/param.h	Tue Jul 16 16:49:43 2002
+++ b/include/asm-arm/arch-shark/param.h	Tue Jul 16 16:49:43 2002
@@ -1,8 +1,5 @@
 /*
- * linux/include/asm-arm/arch-shark/param.h
+ *  linux/include/asm-arm/arch-shark/param.h
  *
  * by Alexander Schulz
  */
-
-#define HZ 100
-
diff -Nru a/include/asm-arm/arch-shark/system.h b/include/asm-arm/arch-shark/system.h
--- a/include/asm-arm/arch-shark/system.h	Tue Jul 16 16:49:43 2002
+++ b/include/asm-arm/arch-shark/system.h	Tue Jul 16 16:49:43 2002
@@ -11,7 +11,7 @@
 static void arch_reset(char mode)
 {
 	short temp;
-	cli();
+	local_irq_disable();
 	/* Reset the Machine via pc[3] of the sequoia chipset */
 	outw(0x09,0x24);
 	temp=inw(0x26);
diff -Nru a/include/asm-arm/arch-tbox/param.h b/include/asm-arm/arch-tbox/param.h
--- a/include/asm-arm/arch-tbox/param.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/arch-tbox/param.h	Tue Jul 16 16:49:42 2002
@@ -1 +1,4 @@
-#define HZ 1000
+/*
+ *  linux/include/asm-arm/arch-tbox/param.h
+ */
+#define __KERNEL_HZ 1000
diff -Nru a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h
--- a/include/asm-arm/cacheflush.h	Tue Jul 16 16:49:43 2002
+++ b/include/asm-arm/cacheflush.h	Tue Jul 16 16:49:43 2002
@@ -10,6 +10,8 @@
 #ifndef _ASMARM_CACHEFLUSH_H
 #define _ASMARM_CACHEFLUSH_H
 
+#include <linux/sched.h>
+#include <linux/mm.h>
 #include <asm/proc/cache.h>
 
 #endif
diff -Nru a/include/asm-arm/glue.h b/include/asm-arm/glue.h
--- a/include/asm-arm/glue.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-arm/glue.h	Tue Jul 16 16:49:41 2002
@@ -89,7 +89,8 @@
  *	  v4_early	- ARMv4 without Thumb early abort handler
  *	  v4t_late	- ARMv4 with Thumb late abort handler
  *	  v4t_early	- ARMv4 with Thumb early abort handler
- *	  v5ej_early	- ARMv5 with Thumb and Java early abort handler
+ *	  v5tej_early	- ARMv5 with Thumb and Java early abort handler
+ *	  xscale	- ARMv5 with Thumb with Xscale extensions
  */
 #undef CPU_ABORT_HANDLER
 #undef MULTI_ABORT
@@ -127,7 +128,7 @@
 #endif
 
 #if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
-    defined(CONFIG_CPU_ARM1020) || defined(CONFIG_CPU_XSCALE)
+    defined(CONFIG_CPU_ARM1020)
 # ifdef CPU_ABORT_HANDLER
 #  define MULTI_ABORT 1
 # else
@@ -139,7 +140,15 @@
 # ifdef CPU_ABORT_HANDLER
 #  define MULTI_ABORT 1
 # else
-#  define CPU_ABORT_HANDLER v5ej_early_abort
+#  define CPU_ABORT_HANDLER v5tej_early_abort
+# endif
+#endif
+
+#if defined(CONFIG_CPU_XSCALE)
+# ifdef CPU_ABORT_HANDLER
+#  define MULTI_ABORT 1
+# else
+#  define CPU_ABORT_HANDLER xscale_abort
 # endif
 #endif
 
@@ -161,7 +170,7 @@
  *	  v4wt		- ARMv4 with writethrough cache, without minicache
  *	  v4wb		- ARMv4 with writeback cache, without minicache
  *	  v4_mc		- ARMv4 with minicache
- *	  v5te_mc	- ARMv5TE with minicache
+ *	  xscale	- Xscale
  */
 #undef _USER
 #undef MULTI_USER
@@ -204,7 +213,7 @@
 # ifdef _USER
 #  define MULTI_USER 1
 # else
-#  define _USER v5te_mc
+#  define _USER xscale_mc
 # endif
 #endif
 
diff -Nru a/include/asm-arm/hardware/sa1111.h b/include/asm-arm/hardware/sa1111.h
--- a/include/asm-arm/hardware/sa1111.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/hardware/sa1111.h	Tue Jul 16 16:49:42 2002
@@ -49,6 +49,9 @@
  */
 #define __CCREG(x)	__REGP(SA1111_VBASE + (x))
 
+#define sa1111_writel(val,addr)	({ *(volatile unsigned int *)(addr) = (val); })
+#define sa1111_readl(addr)	(*(volatile unsigned int *)(addr))
+
 /*
  * System Bus Interface (SBI)
  *
@@ -696,5 +699,11 @@
 };
 
 extern struct sa1111_device *sa1111;
+
+/*
+ * These frob the SKPCR register.
+ */
+void sa1111_enable_device(unsigned int mask);
+void sa1111_disable_device(unsigned int mask);
 
 #endif  /* _ASM_ARCH_SA1111 */
diff -Nru a/include/asm-arm/irq.h b/include/asm-arm/irq.h
--- a/include/asm-arm/irq.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/irq.h	Tue Jul 16 16:49:42 2002
@@ -37,6 +37,7 @@
 #define IRQT_BOTHEDGE	(__IRQT_RISEDGE|__IRQT_FALEDGE)
 #define IRQT_LOW	(__IRQT_LOWLVL)
 #define IRQT_HIGH	(__IRQT_HIGHLVL)
+#define IRQT_PROBE	(1 << 4)
 
 int set_irq_type(unsigned int irq, unsigned int type);
 
diff -Nru a/include/asm-arm/mach/serial_sa1100.h b/include/asm-arm/mach/serial_sa1100.h
--- a/include/asm-arm/mach/serial_sa1100.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/mach/serial_sa1100.h	Tue Jul 16 16:49:42 2002
@@ -19,11 +19,8 @@
 struct sa1100_port_fns {
 	void	(*set_mctrl)(struct uart_port *, u_int);
 	u_int	(*get_mctrl)(struct uart_port *);
-	void	(*enable_ms)(struct uart_port *);
 	void	(*pm)(struct uart_port *, u_int, u_int);
 	int	(*set_wake)(struct uart_port *, u_int);
-	int	(*open)(struct uart_port *, struct uart_info *);
-	void	(*close)(struct uart_port *, struct uart_info *);
 };
 
 #ifdef CONFIG_SERIAL_SA1100
diff -Nru a/include/asm-arm/mmu_context.h b/include/asm-arm/mmu_context.h
--- a/include/asm-arm/mmu_context.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/mmu_context.h	Tue Jul 16 16:49:42 2002
@@ -13,13 +13,10 @@
 #ifndef __ASM_ARM_MMU_CONTEXT_H
 #define __ASM_ARM_MMU_CONTEXT_H
 
-#include <asm/bitops.h>
-#include <asm/pgtable.h>
-#include <asm/arch/memory.h>
 #include <asm/proc-fns.h>
 
-#define destroy_context(mm)		do { } while(0)
 #define init_new_context(tsk,mm)	0
+#define destroy_context(mm)		do { } while(0)
 
 /*
  * This is called when "tsk" is about to enter lazy TLB mode.
@@ -30,7 +27,8 @@
  *
  * tsk->mm will be NULL
  */
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+static inline void
+enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
 {
 }
 
@@ -42,11 +40,12 @@
 switch_mm(struct mm_struct *prev, struct mm_struct *next,
 	  struct task_struct *tsk, unsigned int cpu)
 {
-	if (prev != next)
-		cpu_switch_mm(next->pgd, next);
+	cpu_switch_mm(next->pgd, next);
 }
 
-#define activate_mm(prev, next) \
-	switch_mm((prev),(next),NULL,smp_processor_id())
+static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+	cpu_switch_mm(next->pgd, next);
+}
 
 #endif
diff -Nru a/include/asm-arm/param.h b/include/asm-arm/param.h
--- a/include/asm-arm/param.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/param.h	Tue Jul 16 16:49:42 2002
@@ -13,11 +13,16 @@
 #include <asm/arch/param.h>	/* for HZ */
 #include <asm/proc/page.h>	/* for EXEC_PAGE_SIZE */
 
-#ifndef HZ
-#define HZ 100
+#ifndef __KERNEL_HZ
+#define __KERNEL_HZ	100
 #endif
-#if defined(__KERNEL__) && (HZ == 100)
-#define hz_to_std(a) (a)
+
+#ifdef __KERNEL__
+# define HZ		__KERNEL_HZ	/* Internal kernel timer frequency */
+# define USER_HZ	100		/* User interfaces are in "ticks" */
+# define CLOCKS_PER_SEC	(USER_HZ)	/* like times() */
+#else
+# define HZ		100
 #endif
 
 #ifndef NGROUPS
@@ -30,10 +35,6 @@
 
 /* max length of hostname */
 #define MAXHOSTNAMELEN  64
-
-#ifdef __KERNEL__
-# define CLOCKS_PER_SEC	HZ
-#endif
 
 #endif
 
diff -Nru a/include/asm-arm/proc-armv/pgtable.h b/include/asm-arm/proc-armv/pgtable.h
--- a/include/asm-arm/proc-armv/pgtable.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-arm/proc-armv/pgtable.h	Tue Jul 16 16:49:41 2002
@@ -144,13 +144,13 @@
  * The following macros handle the cache and bufferable bits...
  */
 #define _L_PTE_DEFAULT	L_PTE_PRESENT | L_PTE_YOUNG
-#define _L_PTE_READ	L_PTE_USER | L_PTE_CACHEABLE | L_PTE_BUFFERABLE
+#define _L_PTE_READ	L_PTE_USER | L_PTE_EXEC | L_PTE_CACHEABLE | L_PTE_BUFFERABLE
 
 #define PAGE_NONE       __pgprot(_L_PTE_DEFAULT)
 #define PAGE_COPY       __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
 #define PAGE_SHARED     __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_WRITE)
 #define PAGE_READONLY   __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
-#define PAGE_KERNEL     __pgprot(_L_PTE_DEFAULT | L_PTE_CACHEABLE | L_PTE_BUFFERABLE | L_PTE_DIRTY | L_PTE_WRITE)
+#define PAGE_KERNEL     __pgprot(_L_PTE_DEFAULT | L_PTE_CACHEABLE | L_PTE_BUFFERABLE | L_PTE_DIRTY | L_PTE_WRITE | L_PTE_EXEC)
 
 #define _PAGE_CHG_MASK	(PAGE_MASK | L_PTE_DIRTY | L_PTE_YOUNG)
 
diff -Nru a/include/asm-arm/proc-armv/ptrace.h b/include/asm-arm/proc-armv/ptrace.h
--- a/include/asm-arm/proc-armv/ptrace.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/proc-armv/ptrace.h	Tue Jul 16 16:49:42 2002
@@ -32,6 +32,7 @@
 #define PSR_F_BIT	0x00000040
 #define PSR_I_BIT	0x00000080
 #define PSR_J_BIT	0x01000000
+#define PSR_Q_BIT	0x08000000
 #define PSR_V_BIT	0x10000000
 #define PSR_C_BIT	0x20000000
 #define PSR_Z_BIT	0x40000000
@@ -39,6 +40,14 @@
 #define PCMASK		0
 
 /*
+ * Groups of PSR bits
+ */
+#define PSR_f		0xff000000	/* Flags		*/
+#define PSR_s		0x00ff0000	/* Status		*/
+#define PSR_x		0x0000ff00	/* Extension		*/
+#define PSR_c		0x000000ff	/* Control		*/
+
+/*
  * CR1 bits
  */
 #define CR1_M		0x00000001	/* MMU			*/
@@ -121,7 +130,7 @@
 	/*
 	 * Force CPSR to something logical...
 	 */
-	regs->ARM_cpsr &= (PSR_V_BIT|PSR_C_BIT|PSR_Z_BIT|PSR_N_BIT|MODE32_BIT);
+	regs->ARM_cpsr &= PSR_f | PSR_s | PSR_x | PSR_T_BIT | MODE32_BIT;
 
 	return 0;
 }
diff -Nru a/include/asm-arm/proc-armv/system.h b/include/asm-arm/proc-armv/system.h
--- a/include/asm-arm/proc-armv/system.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-arm/proc-armv/system.h	Tue Jul 16 16:49:41 2002
@@ -182,12 +182,12 @@
 			break;
 #else
 		case 1:	__asm__ __volatile__ ("swpb %0, %1, [%2]"
-					: "=r" (ret)
+					: "=&r" (ret)
 					: "r" (x), "r" (ptr)
 					: "memory");
 			break;
 		case 4:	__asm__ __volatile__ ("swp %0, %1, [%2]"
-					: "=r" (ret)
+					: "=&r" (ret)
 					: "r" (x), "r" (ptr)
 					: "memory");
 			break;
diff -Nru a/include/asm-arm/procinfo.h b/include/asm-arm/procinfo.h
--- a/include/asm-arm/procinfo.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-arm/procinfo.h	Tue Jul 16 16:49:41 2002
@@ -50,13 +50,14 @@
 
 #define PROC_INFO_SZ	44
 
-#define HWCAP_SWP	 1
-#define HWCAP_HALF	 2
-#define HWCAP_THUMB	 4
-#define HWCAP_26BIT	 8	/* Play it safe */
-#define HWCAP_FAST_MULT	 16
-#define HWCAP_FPA        32
-#define HWCAP_VFP        64
-#define HWCAP_EDSP	 128
+#define HWCAP_SWP	1
+#define HWCAP_HALF	2
+#define HWCAP_THUMB	4
+#define HWCAP_26BIT	8	/* Play it safe */
+#define HWCAP_FAST_MULT	16
+#define HWCAP_FPA	32
+#define HWCAP_VFP	64
+#define HWCAP_EDSP	128
+#define HWCAP_JAVA	256
 
 #endif
diff -Nru a/include/asm-arm/suspend.h b/include/asm-arm/suspend.h
--- a/include/asm-arm/suspend.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-arm/suspend.h	Tue Jul 16 16:49:42 2002
@@ -0,0 +1,4 @@
+#ifdef _ASMARM_SUSPEND_H
+#define _ASMARM_SUSPEND_H
+
+#endif
diff -Nru a/include/asm-arm/system.h b/include/asm-arm/system.h
--- a/include/asm-arm/system.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-arm/system.h	Tue Jul 16 16:49:41 2002
@@ -64,7 +64,12 @@
 struct thread_info;
 extern struct task_struct *__switch_to(struct thread_info *, struct thread_info *);
 
-#define switch_to(prev,next)						\
+#define prepare_arch_schedule(prev)		do { } while(0)
+#define finish_arch_schedule(prev)		do { } while(0)
+#define prepare_arch_switch(rq)			do { } while(0)
+#define finish_arch_switch(rq)			spin_unlock_irq(&(rq)->lock)
+
+#define switch_to(prev,next,last)					\
 	do {			 					\
 		__switch_to(prev->thread_info,next->thread_info);	\
 		mb();							\
diff -Nru a/include/asm-cris/pgtable.h b/include/asm-cris/pgtable.h
--- a/include/asm-cris/pgtable.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-cris/pgtable.h	Tue Jul 16 16:49:41 2002
@@ -164,7 +164,7 @@
  */
 #define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
 /*
- * (pmds are folded into pgds so this doesnt get actually called,
+ * (pmds are folded into pgds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
  */
 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
diff -Nru a/include/asm-cris/siginfo.h b/include/asm-cris/siginfo.h
--- a/include/asm-cris/siginfo.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-cris/siginfo.h	Tue Jul 16 16:49:42 2002
@@ -1,8 +1,6 @@
 #ifndef _CRIS_SIGINFO_H
 #define _CRIS_SIGINFO_H
 
-#define HAVE_ARCH_COPY_SIGINFO_TO_USER
-
 #include <asm-generic/siginfo.h>
 
 #endif
diff -Nru a/include/asm-i386/suspend.h b/include/asm-i386/suspend.h
--- a/include/asm-i386/suspend.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-i386/suspend.h	Tue Jul 16 16:49:42 2002
@@ -38,7 +38,6 @@
                        : /* no output */ \
                        :"r" ((thread)->debugreg[register]))
 
-extern void do_fpu_end(void);
 extern void fix_processor_context(void);
 extern void do_magic(int resume);
 
diff -Nru a/include/asm-m68k/mac_via.h b/include/asm-m68k/mac_via.h
--- a/include/asm-m68k/mac_via.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-m68k/mac_via.h	Tue Jul 16 16:49:41 2002
@@ -3,7 +3,7 @@
  *
  *	There are two of these on the Mac II. Some IRQ's are vectored
  *	via them as are assorted bits and bobs - eg rtc, adb. The picture
- *	is a bit incomplete as the Mac documentation doesnt cover this well
+ *	is a bit incomplete as the Mac documentation doesn't cover this well
  */
  
 #ifndef _ASM_MAC_VIA_H_
diff -Nru a/include/asm-parisc/semaphore.h b/include/asm-parisc/semaphore.h
--- a/include/asm-parisc/semaphore.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-parisc/semaphore.h	Tue Jul 16 16:49:41 2002
@@ -53,7 +53,7 @@
  *	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
  *
  * i'd rather use the more flexible initialization above, but sadly
- * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well.
+ * GCC 2.7.2.3 emits a bogus warning. EGCS doesn't. Oh well.
  */
 	atomic_set(&sem->count, val);
 	sem->waking = 0;
diff -Nru a/include/asm-ppc/keyboard.h b/include/asm-ppc/keyboard.h
--- a/include/asm-ppc/keyboard.h	Tue Jul 16 16:49:43 2002
+++ b/include/asm-ppc/keyboard.h	Tue Jul 16 16:49:43 2002
@@ -36,20 +36,22 @@
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 #define INIT_KBD
 
+extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
+				 char raw_mode);
+extern char mac_hid_kbd_unexpected_up(unsigned char keycode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern unsigned char pckbd_sysrq_xlate[128];
+
 static inline int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
 {
-	if ( ppc_md.kbd_setkeycode )
-		return ppc_md.kbd_setkeycode(scancode, keycode);
-	else
-		return 0;
+	return 0;
 }
   
 static inline int kbd_getkeycode(unsigned int scancode)
 {
-	if ( ppc_md.kbd_getkeycode )
-		return ppc_md.kbd_getkeycode(scancode);
-	else
-		return 0;
+	return 0;
 }
   
 static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
@@ -58,7 +60,7 @@
 	if ( ppc_md.kbd_translate )
 		return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
 	else
-		return 0;
+		return pckbd_translate(keycode, keycodep, raw_mode);
 }
   
 static inline int kbd_unexpected_up(unsigned char keycode)
@@ -66,22 +68,18 @@
 	if ( ppc_md.kbd_unexpected_up )
 		return ppc_md.kbd_unexpected_up(keycode);
 	else
-		return 0;
+		return pckbd_unexpected_up(keycode);
 }
   
 static inline void kbd_leds(unsigned char leds)
 {
-	if ( ppc_md.kbd_leds )
-		ppc_md.kbd_leds(leds);
 }
 
 static inline void kbd_init_hw(void)
 {
-	if ( ppc_md.kbd_init_hw )
-		ppc_md.kbd_init_hw();
 }
 
-#define kbd_sysrq_xlate	(ppc_md.ppc_kbd_sysrq_xlate)
+#define kbd_sysrq_xlate	pckbd_sysrq_xlate
 
 extern unsigned long SYSRQ_KEY;
 
diff -Nru a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
--- a/include/asm-ppc/machdep.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-ppc/machdep.h	Tue Jul 16 16:49:42 2002
@@ -57,16 +57,10 @@
 	void		(*nvram_write_val)(int addr, unsigned char val);
 
 	/* Tons of keyboard stuff. */
-	int		(*kbd_setkeycode)(unsigned int scancode,
-				unsigned int keycode);
-	int		(*kbd_getkeycode)(unsigned int scancode);
 	int		(*kbd_translate)(unsigned char scancode,
 				unsigned char *keycode,
 				char raw_mode);
 	char		(*kbd_unexpected_up)(unsigned char keycode);
-	void		(*kbd_leds)(unsigned char leds);
-	void		(*kbd_init_hw)(void);
-	unsigned char 	*ppc_kbd_sysrq_xlate;
 
 	/*
 	 * optional PCI "hooks"
diff -Nru a/include/asm-sh/pgtable-2level.h b/include/asm-sh/pgtable-2level.h
--- a/include/asm-sh/pgtable-2level.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-sh/pgtable-2level.h	Tue Jul 16 16:49:42 2002
@@ -42,7 +42,7 @@
  */
 #define set_pte(pteptr, pteval) (*(pteptr) = pteval)
 /*
- * (pmds are folded into pgds so this doesnt get actually called,
+ * (pmds are folded into pgds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
  */
 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
diff -Nru a/include/asm-sparc/cache.h b/include/asm-sparc/cache.h
--- a/include/asm-sparc/cache.h	Tue Jul 16 16:49:43 2002
+++ b/include/asm-sparc/cache.h	Tue Jul 16 16:49:43 2002
@@ -10,6 +10,7 @@
 
 #include <asm/asi.h>
 
+#define L1_CACHE_SHIFT 5
 #define L1_CACHE_BYTES 32
 #define L1_CACHE_ALIGN(x) ((((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)))
 
diff -Nru a/include/asm-sparc/param.h b/include/asm-sparc/param.h
--- a/include/asm-sparc/param.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-sparc/param.h	Tue Jul 16 16:49:41 2002
@@ -2,6 +2,12 @@
 #ifndef _ASMSPARC_PARAM_H
 #define _ASMSPARC_PARAM_H
 
+#ifdef __KERNEL__
+# define HZ		100	/* Internal kernel timer frequency */
+# define USER_HZ	100	/* .. some user interfaces are in "ticks" */
+# define CLOCKS_PER_SEC (USER_HZ)
+#endif
+
 #ifndef HZ
 #define HZ 100
 #endif
@@ -17,9 +23,5 @@
 #endif
 
 #define MAXHOSTNAMELEN	64	/* max length of hostname */
-
-#ifdef __KERNEL__
-# define CLOCKS_PER_SEC	HZ	/* frequency at which times() counts */
-#endif
 
 #endif
diff -Nru a/include/asm-sparc64/cache.h b/include/asm-sparc64/cache.h
--- a/include/asm-sparc64/cache.h	Tue Jul 16 16:49:42 2002
+++ b/include/asm-sparc64/cache.h	Tue Jul 16 16:49:42 2002
@@ -5,7 +5,8 @@
 #define __ARCH_SPARC64_CACHE_H
 
 /* bytes per L1 cache line */
-#define        L1_CACHE_BYTES		32 /* Two 16-byte sub-blocks per line. */
+#define        L1_CACHE_SHIFT	5
+#define        L1_CACHE_BYTES	32 /* Two 16-byte sub-blocks per line. */
 
 #define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
 
diff -Nru a/include/asm-sparc64/param.h b/include/asm-sparc64/param.h
--- a/include/asm-sparc64/param.h	Tue Jul 16 16:49:41 2002
+++ b/include/asm-sparc64/param.h	Tue Jul 16 16:49:41 2002
@@ -2,6 +2,12 @@
 #ifndef _ASMSPARC64_PARAM_H
 #define _ASMSPARC64_PARAM_H
 
+#ifdef __KERNEL__
+# define HZ		100	/* Internal kernel timer frequency */
+# define USER_HZ	100	/* .. some user interfaces are in "ticks" */
+# define CLOCKS_PER_SEC (USER_HZ)
+#endif
+
 #ifndef HZ
 #define HZ 100
 #endif
@@ -17,9 +23,5 @@
 #endif
 
 #define MAXHOSTNAMELEN	64	/* max length of hostname */
-
-#ifdef __KERNEL__
-# define CLOCKS_PER_SEC	HZ	/* frequency at which times() counts */
-#endif
 
 #endif /* _ASMSPARC64_PARAM_H */
diff -Nru a/include/linux/atapi.h b/include/linux/atapi.h
--- a/include/linux/atapi.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/atapi.h	Tue Jul 16 16:49:42 2002
@@ -12,6 +12,9 @@
  * more details.
  */
 
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
 /*
  * With each packet command, we allocate a buffer.
  * This is used for several packet
@@ -79,3 +82,281 @@
 extern void atapi_read(struct ata_device *, u8 *, unsigned int);
 extern void atapi_write(struct ata_device *, u8 *, unsigned int);
 
+
+/*
+ *	ATAPI Status Register.
+ */
+typedef union {
+	u8 all			: 8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		u8 check	: 1;	/* Error occurred */
+		u8 idx		: 1;	/* Reserved */
+		u8 corr		: 1;	/* Correctable error occurred */
+		u8 drq		: 1;	/* Data is request by the device */
+		u8 dsc		: 1;	/* Media access command finished / Buffer availability */
+		u8 reserved5	: 1;	/* Reserved */
+		u8 drdy		: 1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
+		u8 bsy		: 1;	/* The device has access to the command block */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		u8 bsy		: 1;
+		u8 drdy		: 1;
+		u8 reserved5	: 1;
+		u8 dsc		: 1;
+		u8 drq		: 1;
+		u8 corr		: 1;
+		u8 idx		: 1;
+		u8 check	: 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_status_reg_t;
+
+/*
+ *	ATAPI error register.
+ */
+typedef union {
+	u8 all			: 8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		u8 ili		: 1;	/* Illegal Length Indication */
+		u8 eom		: 1;	/* End Of Media Detected */
+		u8 abrt		: 1;	/* Aborted command - As defined by ATA */
+		u8 mcr		: 1;	/* Media Change Requested - As defined by ATA */
+		u8 sense_key	: 4;	/* Sense key of the last failed packet command */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		u8 sense_key	: 4;
+		u8 mcr		: 1;
+		u8 abrt		: 1;
+		u8 eom		: 1;
+		u8 ili		: 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_error_reg_t;
+
+/* Currently unused, but please do not remove.  --bkz */
+/*
+ *	ATAPI Feature Register.
+ */
+typedef union {
+	u8 all			: 8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		u8 dma		: 1;	/* Using DMA or PIO */
+		u8 reserved321	: 3;	/* Reserved */
+		u8 reserved654	: 3;	/* Reserved (Tag Type) */
+		u8 reserved7	: 1;	/* Reserved */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		u8 reserved7	: 1;
+		u8 reserved654	: 3;
+		u8 reserved321	: 3;
+		u8 dma		: 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_feature_reg_t;
+
+/*
+ *	ATAPI Byte Count Register.
+ */
+typedef union {
+	u16 all			: 16;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		u8 low;			/* LSB */
+		u8 high;		/* MSB */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		u8 high;
+		u8 low;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_bcount_reg_t;
+
+/*
+ *	ATAPI Interrupt Reason Register.
+ */
+typedef union {
+	u8 all			: 8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		u8 cod		: 1;	/* Information transferred is command (1) or data (0) */
+		u8 io		: 1;	/* The device requests us to read (1) or write (0) */
+		u8 reserved	: 6;	/* Reserved */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		u8 reserved	: 6;
+		u8 io		: 1;
+		u8 cod		: 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_ireason_reg_t;
+
+/* Currently unused, but please do not remove.  --bkz */
+/*
+ *	ATAPI Drive Select Register.
+ */
+typedef union {
+	u8 all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		u8 sam_lun	:3;	/* Logical unit number */
+		u8 reserved3	:1;	/* Reserved */
+		u8 drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
+		u8 one5		:1;	/* Should be set to 1 */
+		u8 reserved6	:1;	/* Reserved */
+		u8 one7		:1;	/* Should be set to 1 */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		u8 one7		:1;
+		u8 reserved6	:1;
+		u8 one5		:1;
+		u8 drv		:1;
+		u8 reserved3	:1;
+		u8 sam_lun	:3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_drivesel_reg_t;
+
+/* Currently unused, but please do not remove.  --bkz */
+/*
+ *	ATAPI Device Control Register.
+ */
+typedef union {
+	u8 all			: 8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		u8 zero0	: 1;	/* Should be set to zero */
+		u8 nien		: 1;	/* Device interrupt is disabled (1) or enabled (0) */
+		u8 srst		: 1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
+		u8 one3		: 1;	/* Should be set to 1 */
+		u8 reserved4567	: 4;	/* Reserved */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		u8 reserved4567	: 4;
+		u8 one3		: 1;
+		u8 srst		: 1;
+		u8 nien		: 1;
+		u8 zero0	: 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_control_reg_t;
+
+/*
+ *	The following is used to format the general configuration word
+ *	of the ATAPI IDENTIFY DEVICE command.
+ */
+struct atapi_id_gcw {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u8 packet_size		: 2;	/* Packet Size */
+	u8 reserved234		: 3;	/* Reserved */
+	u8 drq_type		: 2;	/* Command packet DRQ type */
+	u8 removable		: 1;	/* Removable media */
+	u8 device_type		: 5;	/* Device type */
+	u8 reserved13		: 1;	/* Reserved */
+	u8 protocol		: 2;	/* Protocol type */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	u8 protocol		: 2;
+	u8 reserved13		: 1;
+	u8 device_type		: 5;
+	u8 removable		: 1;
+	u8 drq_type		: 2;
+	u8 reserved234		: 3;
+	u8 packet_size		: 2;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+};
+
+/*
+ *	INQUIRY packet command - Data Format.
+ */
+typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u8	device_type	: 5;	/* Peripheral Device Type */
+	u8	reserved0_765	: 3;	/* Peripheral Qualifier - Reserved */
+	u8	reserved1_6t0	: 7;	/* Reserved */
+	u8	rmb		: 1;	/* Removable Medium Bit */
+	u8	ansi_version	: 3;	/* ANSI Version */
+	u8	ecma_version	: 3;	/* ECMA Version */
+	u8	iso_version	: 2;	/* ISO Version */
+	u8	response_format : 4;	/* Response Data Format */
+	u8	reserved3_45	: 2;	/* Reserved */
+	u8	reserved3_6	: 1;	/* TrmIOP - Reserved */
+	u8	reserved3_7	: 1;	/* AENC - Reserved */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	u8	reserved0_765	: 3;
+	u8	device_type	: 5;
+	u8	rmb		: 1;
+	u8	reserved1_6t0	: 7;
+	u8	iso_version	: 2;
+	u8	ecma_version	: 3;
+	u8	ansi_version	: 3;
+	u8	reserved3_7	: 1;
+	u8	reserved3_6	: 1;
+	u8	reserved3_45	: 2;
+	u8	response_format : 4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	u8	additional_length;	/* Additional Length (total_length-4) */
+	u8	rsv5, rsv6, rsv7;	/* Reserved */
+	u8	vendor_id[8];		/* Vendor Identification */
+	u8	product_id[16];		/* Product Identification */
+	u8	revision_level[4];	/* Revision Level */
+	u8	vendor_specific[20];	/* Vendor Specific - Optional */
+	u8	reserved56t95[40];	/* Reserved - Optional */
+					/* Additional information may be returned */
+} atapi_inquiry_result_t;
+
+/*
+ *	REQUEST SENSE packet command result - Data Format.
+ */
+typedef struct atapi_request_sense {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u8	error_code	: 7;	/* Error Code (0x70 - current or 0x71 - deferred) */
+	u8	valid		: 1;	/* The information field conforms to standard */
+	u8	reserved1	: 8;	/* Reserved (Segment Number) */
+	u8	sense_key	: 4;	/* Sense Key */
+	u8	reserved2_4	: 1;	/* Reserved */
+	u8	ili		: 1;	/* Incorrect Length Indicator */
+	u8	eom		: 1;	/* End Of Medium */
+	u8	filemark	: 1;	/* Filemark */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	u8	valid		: 1;
+	u8	error_code	: 7;
+	u8	reserved1	: 8;
+	u8	filemark	: 1;
+	u8	eom		: 1;
+	u8	ili		: 1;
+	u8	reserved2_4	: 1;
+	u8	sense_key	: 4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	u32	information __attribute__ ((packed));
+	u8	asl;			/* Additional sense length (n-7) */
+	u32	command_specific;	/* Additional command specific information */
+	u8	asc;			/* Additional Sense Code */
+	u8	ascq;			/* Additional Sense Code Qualifier */
+	u8	replaceable_unit_code;	/* Field Replaceable Unit Code */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u8	sk_specific1	: 7;	/* Sense Key Specific */
+	u8	sksv		: 1;	/* Sense Key Specific information is valid */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	u8	sksv		: 1;	/* Sense Key Specific information is valid */
+	u8	sk_specific1	: 7;	/* Sense Key Specific */
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	u8	sk_specific[2];		/* Sense Key Specific */
+	u8	pad[2];			/* Padding to 20 bytes */
+} atapi_request_sense_result_t;
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Tue Jul 16 16:49:41 2002
+++ b/include/linux/blkdev.h	Tue Jul 16 16:49:41 2002
@@ -283,7 +283,9 @@
 extern inline request_queue_t *bdev_get_queue(struct block_device *bdev);
 extern void blkdev_release_request(struct request *);
 extern void blk_attempt_remerge(request_queue_t *, struct request *);
+extern void __blk_attempt_remerge(request_queue_t *, struct request *);
 extern struct request *blk_get_request(request_queue_t *, int, int);
+extern struct request *__blk_get_request(request_queue_t *, int);
 extern void blk_put_request(struct request *);
 extern void blk_plug_device(request_queue_t *);
 extern int blk_remove_plug(request_queue_t *);
diff -Nru a/include/linux/brlock.h b/include/linux/brlock.h
--- a/include/linux/brlock.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/brlock.h	Tue Jul 16 16:49:42 2002
@@ -19,7 +19,7 @@
  *
  *                 David S. Miller <davem@redhat.com>
  *
- * David has an implementation that doesnt use atomic operations in
+ * David has an implementation that doesn't use atomic operations in
  * the read branch via memory ordering tricks - i guess we need to
  * split this up into a per-arch thing? The atomicity issue is a
  * secondary item in profiles, at least on x86 platforms.
diff -Nru a/include/linux/buffer_head.h b/include/linux/buffer_head.h
--- a/include/linux/buffer_head.h	Tue Jul 16 16:49:41 2002
+++ b/include/linux/buffer_head.h	Tue Jul 16 16:49:41 2002
@@ -185,8 +185,6 @@
 sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
 int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
 int block_truncate_page(struct address_space *, loff_t, get_block_t *);
-int generic_direct_IO(int, struct inode *, struct kiobuf *,
-			unsigned long, int, get_block_t *);
 int file_fsync(struct file *, struct dentry *, int);
 
 #define OSYNC_METADATA	(1<<0)
diff -Nru a/include/linux/console_struct.h b/include/linux/console_struct.h
--- a/include/linux/console_struct.h	Tue Jul 16 16:49:41 2002
+++ b/include/linux/console_struct.h	Tue Jul 16 16:49:41 2002
@@ -33,6 +33,7 @@
 	unsigned int	vc_top, vc_bottom;	/* Scrolling region */
 	unsigned int	vc_state;		/* Escape sequence parser state */
 	unsigned int	vc_npar,vc_par[NPAR];	/* Parameters of current escape sequence */
+	struct tty_struct *vc_tty;		/* TTY we are attached to */
 	unsigned long	vc_origin;		/* [!] Start of real screen */
 	unsigned long	vc_scr_end;		/* [!] End of real screen */
 	unsigned long	vc_visible_origin;	/* [!] Top of visible window */
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/fs.h	Tue Jul 16 16:49:42 2002
@@ -303,8 +303,8 @@
 	int (*bmap)(struct address_space *, long);
 	int (*invalidatepage) (struct page *, unsigned long);
 	int (*releasepage) (struct page *, int);
-#define KERNEL_HAS_O_DIRECT /* this is for modules out of the kernel */
-	int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int);
+	int (*direct_IO)(int, struct inode *, char *buf,
+				loff_t offset, size_t count);
 };
 
 struct backing_dev_info;
@@ -988,7 +988,6 @@
 extern struct vfsmount *kern_mount(struct file_system_type *);
 extern int may_umount(struct vfsmount *);
 extern long do_mount(char *, char *, char *, unsigned long, void *);
-extern void umount_tree(struct vfsmount *);
 
 #define kern_umount mntput
 
@@ -1128,7 +1127,7 @@
 extern int invalidate_inodes(struct super_block *);
 extern int invalidate_device(kdev_t, int);
 extern void invalidate_inode_pages(struct inode *);
-extern void invalidate_inode_pages2(struct address_space *);
+extern void invalidate_inode_pages2(struct address_space *mapping);
 extern void write_inode_now(struct inode *, int);
 extern int filemap_fdatawrite(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
@@ -1233,6 +1232,11 @@
 extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
 extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
 extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t);
+ssize_t generic_file_direct_IO(int rw, struct inode *inode, char *buf,
+				loff_t offset, size_t count);
+int generic_direct_IO(int rw, struct inode *inode, char *buf,
+			loff_t offset, size_t count, get_block_t *get_block);
+
 extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t remote_llseek(struct file *file, loff_t offset, int origin);
diff -Nru a/include/linux/gameport.h b/include/linux/gameport.h
--- a/include/linux/gameport.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/gameport.h	Tue Jul 16 16:49:42 2002
@@ -38,7 +38,6 @@
 	void *driver;	/* Private pointer for gameport drivers */
 	char *name;
 	char *phys;
-	int number;
 
 	unsigned short idbus;
 	unsigned short idvendor;
diff -Nru a/include/linux/hiddev.h b/include/linux/hiddev.h
--- a/include/linux/hiddev.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/hiddev.h	Tue Jul 16 16:49:42 2002
@@ -49,6 +49,13 @@
 	unsigned num_applications;
 };
 
+struct hiddev_collection_info {
+	unsigned index;
+	unsigned type;
+	unsigned usage;
+	unsigned level;
+};
+
 #define HID_STRING_SIZE 256
 struct hiddev_string_descriptor {
 	int index;
@@ -64,9 +71,9 @@
 /* To do a GUSAGE/SUSAGE, fill in at least usage_code,  report_type and 
  * report_id.  Set report_id to REPORT_ID_UNKNOWN if the rest of the fields 
  * are unknown.  Otherwise use a usage_ref struct filled in from a previous 
- * successful GUSAGE/SUSAGE call to save time.  To actually send a value
- * to the device, perform a SUSAGE first, followed by a SREPORT.  If an
- * INITREPORT is done, a GREPORT isn't necessary before a GUSAGE.
+ * successful GUSAGE call to save time.  To actually send a value to the
+ * device, perform a SUSAGE first, followed by a SREPORT.  An INITREPORT or a
+ * GREPORT isn't necessary for a GUSAGE to return valid data.
  */
 #define HID_REPORT_ID_UNKNOWN 0xffffffff
 #define HID_REPORT_ID_FIRST   0x00000100
@@ -129,7 +136,7 @@
  * Protocol version.
  */
 
-#define HID_VERSION		0x010003
+#define HID_VERSION		0x010004
 
 /*
  * IOCTLs (0x00 - 0x7f)
@@ -150,6 +157,8 @@
 #define HIDIOCGUCODE		_IOWR('H', 0x0D, struct hiddev_usage_ref)
 #define HIDIOCGFLAG		_IOR('H', 0x0E, int)
 #define HIDIOCSFLAG		_IOW('H', 0x0F, int)
+#define HIDIOCGCOLLECTIONINDEX	_IOW('H', 0x10, struct hiddev_usage_ref)
+#define HIDIOCGCOLLECTIONINFO	_IOWR('H', 0x11, struct hiddev_collection_info)
 
 /* 
  * Flags to be used in HIDIOCSFLAG
@@ -193,13 +202,17 @@
 #ifdef CONFIG_USB_HIDDEV
 int hiddev_connect(struct hid_device *);
 void hiddev_disconnect(struct hid_device *);
-void hiddev_hid_event(struct hid_device *, struct hiddev_usage_ref *ref);
+void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
+		      struct hid_usage *usage, __s32 value);
+void hiddev_report_event(struct hid_device *hid, struct hid_report *report);
 int __init hiddev_init(void);
 void __exit hiddev_exit(void);
 #else
-static inline void *hiddev_connect(struct hid_device *hid) { return NULL; }
+static inline int hiddev_connect(struct hid_device *hid) { return -1; }
 static inline void hiddev_disconnect(struct hid_device *hid) { }
-static inline void hiddev_event(struct hid_device *hid, unsigned int usage, int value) { }
+static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
+		      struct hid_usage *usage, __s32 value) { }
+static inline void hiddev_report_event(struct hid_device *hid, struct hid_report *report) { }
 static inline int hiddev_init(void) { return 0; }
 static inline void hiddev_exit(void) { }
 #endif
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Tue Jul 16 16:49:41 2002
+++ b/include/linux/ide.h	Tue Jul 16 16:49:41 2002
@@ -372,16 +372,17 @@
  * Status returned by various functions.
  */
 typedef enum {
-	ide_stopped,	/* no drive operation was started */
-	ide_started,	/* a drive operation was started, and a handler was set */
-	ide_released	/* started and released bus */
+	ATA_OP_FINISHED,	/* no drive operation was started */
+	ATA_OP_CONTINUES,	/* a drive operation was started, and a handler was set */
+	ATA_OP_RELEASED,	/* started and released bus */
+	ATA_OP_READY,		/* indicate status poll finished fine */
 } ide_startstop_t;
 
 /*
  *  Interrupt and timeout handler type.
  */
 typedef ide_startstop_t (ata_handler_t)(struct ata_device *, struct request *);
-typedef int (ata_expiry_t)(struct ata_device *, struct request *);
+typedef ide_startstop_t (ata_expiry_t)(struct ata_device *, struct request *, unsigned long *);
 
 enum {
 	ATA_PRIMARY	= 0,
@@ -406,7 +407,7 @@
 
 	ide_startstop_t (*handler)(struct ata_device *, struct request *);	/* irq handler, if active */
 	struct timer_list timer;				/* failsafe timer */
-	int (*expiry)(struct ata_device *, struct request *);	/* irq handler, if active */
+	ide_startstop_t (*expiry)(struct ata_device *, struct request *, unsigned long *);	/* irq handler, if active */
 	unsigned long poll_timeout;				/* timeout value during polled operations */
 	struct ata_device *drive;				/* last serviced drive */
 
@@ -456,7 +457,7 @@
 	void (*atapi_read)(struct ata_device *, void *, unsigned int);
 	void (*atapi_write)(struct ata_device *, void *, unsigned int);
 
-	int (*udma_setup)(struct ata_device *);
+	int (*udma_setup)(struct ata_device *, int);
 
 	void (*udma_enable)(struct ata_device *, int, int);
 	void (*udma_start) (struct ata_device *, struct request *);
@@ -496,7 +497,9 @@
 	unsigned unmask		: 1;	/* flag: okay to unmask other irqs */
 	unsigned slow		: 1;	/* flag: slow data port */
 	unsigned io_32bit	: 1;	/* 0=16-bit, 1=32-bit */
+	unsigned no_atapi_autodma : 1;	/* flag: use auto DMA only for disks */
 	unsigned char bus_state;	/* power state of the IDE bus */
+	int modes_map;			/* map of supported transfer modes */
 };
 
 /*
@@ -602,9 +605,7 @@
 #define DEVICE_NR(device)	(minor(device) >> PARTN_BITS)
 #include <linux/blk.h>
 
-/* Not locking and locking variant: */
 extern int __ata_end_request(struct ata_device *, struct request *, int, unsigned int);
-extern int ata_end_request(struct ata_device *drive, struct request *, int);
 
 extern void ata_set_handler(struct ata_device *drive, ata_handler_t handler,
 		unsigned long timeout, ata_expiry_t expiry);
@@ -626,12 +627,6 @@
 struct ata_device *get_info_ptr(kdev_t i_rdev);
 
 /*
- * Re-Start an operation for an IDE interface.
- * The caller should return immediately after invoking this.
- */
-ide_startstop_t restart_request(struct ata_device *);
-
-/*
  * "action" parameter type for ide_do_drive_cmd() below.
  */
 typedef enum {
@@ -658,31 +653,7 @@
 extern void ata_read(struct ata_device *, void *, unsigned int);
 extern void ata_write(struct ata_device *, void *, unsigned int);
 
-/*
- * Special Flagged Register Validation Caller
- */
-
-/*
- * for now, taskfile requests are special :/
- */
-static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
-{
-	if (rq->bio)
-		return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
-	else
-		return rq->buffer + ((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE;
-}
-
-static inline void ide_unmap_rq(struct request *rq, char *to,
-				unsigned long *flags)
-{
-	if (rq->bio)
-		bio_kunmap_irq(to, flags);
-}
-
-extern ide_startstop_t ata_special_intr(struct ata_device *, struct request *);
-extern int ide_raw_taskfile(struct ata_device *, struct ata_taskfile *);
-
+extern int ide_raw_taskfile(struct ata_device *, struct ata_taskfile *, char *);
 extern void ide_fix_driveid(struct hd_driveid *id);
 extern int ide_config_drive_speed(struct ata_device *, byte);
 extern byte eighty_ninty_three(struct ata_device *);
@@ -756,9 +727,12 @@
 
 static inline int udma_stop(struct ata_device *drive)
 {
+	int ret;
+
+	ret = drive->channel->udma_stop(drive);
 	clear_bit(IDE_DMA, drive->channel->active);
 
-	return drive->channel->udma_stop(drive);
+	return ret;
 }
 
 /*
@@ -766,9 +740,12 @@
  */
 static inline ide_startstop_t udma_init(struct ata_device *drive, struct request *rq)
 {
-	int ret = drive->channel->udma_init(drive, rq);
-	if (ret == ide_started)
-		set_bit(IDE_DMA, drive->channel->active);
+	int ret;
+
+	set_bit(IDE_DMA, drive->channel->active);
+	ret = drive->channel->udma_init(drive, rq);
+	if (ret != ATA_OP_CONTINUES)
+		clear_bit(IDE_DMA, drive->channel->active);
 
 	return ret;
 }
@@ -797,7 +774,9 @@
 extern int udma_pci_irq_status(struct ata_device *drive);
 extern void udma_pci_timeout(struct ata_device *drive);
 extern void udma_pci_irq_lost(struct ata_device *);
-extern int udma_pci_setup(struct ata_device *);
+extern int udma_pci_setup(struct ata_device *, int);
+
+extern int udma_generic_setup(struct ata_device *, int);
 
 extern int udma_new_table(struct ata_device *, struct request *);
 extern void udma_destroy_table(struct ata_channel *);
@@ -830,10 +809,9 @@
 
 extern void ata_select(struct ata_device *, unsigned long);
 extern void ata_mask(struct ata_device *);
-extern int ata_busy_poll(struct ata_device *, unsigned long);
 extern int ata_status(struct ata_device *, u8, u8);
 extern int ata_status_poll( struct ata_device *, u8, u8,
-		unsigned long, struct request *rq, ide_startstop_t *);
+		unsigned long, struct request *rq);
 
 extern int ata_irq_enable(struct ata_device *, int);
 extern void ata_reset(struct ata_channel *);
diff -Nru a/include/linux/if_vlan.h b/include/linux/if_vlan.h
--- a/include/linux/if_vlan.h	Tue Jul 16 16:49:41 2002
+++ b/include/linux/if_vlan.h	Tue Jul 16 16:49:41 2002
@@ -141,9 +141,10 @@
 	(VLAN_TX_SKB_CB(__skb)->magic == VLAN_TX_COOKIE_MAGIC)
 #define vlan_tx_tag_get(__skb)	(VLAN_TX_SKB_CB(__skb)->vlan_tag)
 
-/* VLAN rx hw acceleration helper.  This acts like netif_rx().  */
-static inline int vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
-				  unsigned short vlan_tag)
+/* VLAN rx hw acceleration helper.  This acts like netif_{rx,receive_skb}(). */
+static inline int __vlan_hwaccel_rx(struct sk_buff *skb,
+				    struct vlan_group *grp,
+				    unsigned short vlan_tag, int polling)
 {
 	struct net_device_stats *stats;
 
@@ -182,9 +183,22 @@
 		break;
 	};
 
-	return netif_rx(skb);
+	return (polling ? netif_receive_skb(skb) : netif_rx(skb));
 }
 
+static inline int vlan_hwaccel_rx(struct sk_buff *skb,
+				  struct vlan_group *grp,
+				  unsigned short vlan_tag)
+{
+	return __vlan_hwaccel_rx(skb, grp, vlan_tag, 0);
+}
+
+static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb,
+					   struct vlan_group *grp,
+					   unsigned short vlan_tag)
+{
+	return __vlan_hwaccel_rx(skb, grp, vlan_tag, 1);
+}
 #endif /* __KERNEL__ */
 
 /* VLAN IOCTLs are found in sockios.h */
diff -Nru a/include/linux/input.h b/include/linux/input.h
--- a/include/linux/input.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/input.h	Tue Jul 16 16:49:42 2002
@@ -399,6 +399,73 @@
 #define BTN_GEAR_DOWN		0x150
 #define BTN_GEAR_UP		0x151
 
+#define KEY_OK			0x160
+#define KEY_SELECT 		0x161
+#define KEY_GOTO		0x162
+#define KEY_CLEAR		0x163
+#define KEY_POWER2		0x164
+#define KEY_OPTION		0x165
+#define KEY_INFO		0x166
+#define KEY_TIME		0x167
+#define KEY_VENDOR		0x168
+#define KEY_ARCHIVE		0x169
+#define KEY_PROGRAM		0x16a
+#define KEY_CHANNEL		0x16b
+#define KEY_FAVORITES		0x16c
+#define KEY_EPG			0x16d
+#define KEY_PVR			0x16e
+#define KEY_MHP			0x16f
+#define KEY_LANGUAGE		0x170
+#define KEY_TITLE		0x171
+#define KEY_SUBTITLE		0x172
+#define KEY_ANGLE		0x173
+#define KEY_ZOOM		0x174
+#define KEY_MODE		0x175
+#define KEY_KEYBOARD		0x176
+#define KEY_SCREEN		0x177
+#define KEY_PC			0x178
+#define KEY_TV			0x179
+#define KEY_TV2			0x17a
+#define KEY_VCR			0x17b
+#define KEY_VCR2		0x17c
+#define KEY_SAT			0x17d
+#define KEY_SAT2		0x17e
+#define KEY_CD			0x17f
+#define KEY_TAPE		0x180
+#define KEY_RADIO		0x181
+#define KEY_TUNER		0x182
+#define KEY_PLAYER		0x183
+#define KEY_TEXT		0x184
+#define KEY_DVD			0x185
+#define KEY_AUX			0x186
+#define KEY_MP3			0x187
+#define KEY_AUDIO		0x188
+#define KEY_VIDEO		0x189
+#define KEY_DIRECTORY		0x18a
+#define KEY_LIST		0x18b
+#define KEY_MEMO		0x18c
+#define KEY_CALENDAR		0x18d
+#define KEY_RED			0x18e
+#define KEY_GREEN		0x18f
+#define KEY_YELLOW		0x190
+#define KEY_BLUE		0x191
+#define KEY_CHANNELUP		0x192
+#define KEY_CHANNELDOWN		0x193
+#define KEY_FIRST		0x194
+#define KEY_LAST		0x195
+#define KEY_AB			0x196
+#define KEY_PLAY		0x197
+#define KEY_RESTART		0x198
+#define KEY_SLOW		0x199
+#define KEY_SHUFFLE		0x19a
+#define KEY_FASTFORWARD		0x19b
+#define KEY_PREVIOUS		0x19c
+#define KEY_NEXT		0x19d
+#define KEY_DIGITS		0x19e
+#define KEY_TEEN		0x19f
+#define KEY_TWEN		0x1a0
+#define KEY_BREAK		0x1a1
+
 #define KEY_MAX			0x1ff
 
 /*
@@ -507,6 +574,7 @@
 #define BUS_AMIGA		0x16
 #define BUS_ADB			0x17
 #define BUS_I2C			0x18
+#define BUS_HOST		0x19
 
 /*
  * Values describing the status of an effect
diff -Nru a/include/linux/namespace.h b/include/linux/namespace.h
--- a/include/linux/namespace.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/namespace.h	Tue Jul 16 16:49:42 2002
@@ -14,6 +14,8 @@
 
 void umount_tree(struct vfsmount *mnt);
 
+extern void umount_tree(struct vfsmount *);
+
 static inline void put_namespace(struct namespace *namespace)
 {
 	if (atomic_dec_and_test(&namespace->count)) {
diff -Nru a/include/linux/netlink.h b/include/linux/netlink.h
--- a/include/linux/netlink.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/netlink.h	Tue Jul 16 16:49:42 2002
@@ -110,6 +110,8 @@
 extern void netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
 			      __u32 group, int allocation);
 extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);
+extern int netlink_register_notifier(struct notifier_block *nb);
+extern int netlink_unregister_notifier(struct notifier_block *nb);
 
 /*
  *	skb should fit one page. This choice is good for headerless malloc.
@@ -127,6 +129,12 @@
 	int		(*done)(struct netlink_callback *cb);
 	int		family;
 	long		args[4];
+};
+
+struct netlink_notify
+{
+	int pid;
+	int protocol;
 };
 
 static __inline__ struct nlmsghdr *
diff -Nru a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
--- a/include/linux/nfs_xdr.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/nfs_xdr.h	Tue Jul 16 16:49:42 2002
@@ -1,9 +1,6 @@
 #ifndef _LINUX_NFS_XDR_H
 #define _LINUX_NFS_XDR_H
 
-extern struct rpc_program	nfs_program;
-extern struct rpc_stat		nfs_rpcstat;
-
 struct nfs_fattr {
 	unsigned short		valid;		/* which fields are valid */
 	__u64			pre_size;	/* pre_op_attr.size	  */
@@ -354,5 +351,6 @@
 extern struct rpc_version	nfs_version2;
 extern struct rpc_version	nfs_version3;
 extern struct rpc_program	nfs_program;
+extern struct rpc_stat		nfs_rpcstat;
 
 #endif
diff -Nru a/include/linux/notifier.h b/include/linux/notifier.h
--- a/include/linux/notifier.h	Tue Jul 16 16:49:41 2002
+++ b/include/linux/notifier.h	Tue Jul 16 16:49:41 2002
@@ -58,5 +58,7 @@
 #define SYS_HALT	0x0002	/* Notify of system halt */
 #define SYS_POWER_OFF	0x0003	/* Notify of system power off */
 
+#define NETLINK_URELEASE	0x0001	/* Unicast netlink socket released */
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_NOTIFIER_H */
diff -Nru a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
--- a/include/linux/raid/md_k.h	Tue Jul 16 16:49:41 2002
+++ b/include/linux/raid/md_k.h	Tue Jul 16 16:49:41 2002
@@ -59,7 +59,7 @@
 typedef struct mdk_rdev_s mdk_rdev_t;
 
 #if (MINORBITS != 8)
-#error MD doesnt handle bigger kdev yet
+#error MD does not handle bigger kdev yet
 #endif
 
 #define MAX_MD_DEVS  (1<<MINORBITS)	/* Max number of md dev */
diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h	Tue Jul 16 16:49:43 2002
+++ b/include/linux/reiserfs_fs.h	Tue Jul 16 16:49:43 2002
@@ -1937,14 +1937,6 @@
 extern struct inode_operations reiserfs_file_inode_operations;
 extern struct file_operations reiserfs_file_operations;
 extern struct address_space_operations reiserfs_address_space_operations ;
-int get_new_buffer (struct reiserfs_transaction_handle *th, struct buffer_head *,
-		    struct buffer_head **, struct path *);
-
-
-/* buffer2.c */
-struct buffer_head * reiserfs_getblk (struct super_block *super, int n_block);
-void wait_buffer_until_released (const struct buffer_head * bh);
-struct buffer_head * reiserfs_bread (struct super_block *super, int n_block);
 
 /* fix_nodes.c */
 #ifdef CONFIG_REISERFS_CHECK
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Tue Jul 16 16:49:41 2002
+++ b/include/linux/sched.h	Tue Jul 16 16:49:41 2002
@@ -487,6 +487,7 @@
 extern unsigned long prof_shift;
 
 extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, int nr));
+extern void FASTCALL(__wake_up_locked(wait_queue_head_t *q, unsigned int mode));
 extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr));
 extern void FASTCALL(sleep_on(wait_queue_head_t *q));
 extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q,
@@ -504,6 +505,7 @@
 #define wake_up_interruptible(x)	__wake_up((x),TASK_INTERRUPTIBLE, 1)
 #define wake_up_interruptible_nr(x, nr)	__wake_up((x),TASK_INTERRUPTIBLE, nr)
 #define wake_up_interruptible_all(x)	__wake_up((x),TASK_INTERRUPTIBLE, 0)
+#define	wake_up_locked(x)		__wake_up_locked((x), TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
 #ifdef CONFIG_SMP
 #define wake_up_interruptible_sync(x)   __wake_up_sync((x),TASK_INTERRUPTIBLE, 1)
 #else
@@ -696,6 +698,25 @@
 	remove_wait_queue(&wq, &__wait);				\
 } while (0)
 	
+/*
+ * Must be called with the spinlock in the wait_queue_head_t held.
+ */
+static inline void add_wait_queue_exclusive_locked(wait_queue_head_t *q,
+						   wait_queue_t * wait)
+{
+	wait->flags |= WQ_FLAG_EXCLUSIVE;
+	__add_wait_queue_tail(q,  wait);
+}
+
+/*
+ * Must be called with the spinlock in the wait_queue_head_t held.
+ */
+static inline void remove_wait_queue_locked(wait_queue_head_t *q,
+					    wait_queue_t * wait)
+{
+	__remove_wait_queue(q,  wait);
+}
+
 #define wait_event_interruptible(wq, condition)				\
 ({									\
 	int __ret = 0;							\
diff -Nru a/include/linux/serio.h b/include/linux/serio.h
--- a/include/linux/serio.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/serio.h	Tue Jul 16 16:49:42 2002
@@ -50,6 +50,7 @@
 	unsigned short idversion;
 
 	unsigned long type;
+	unsigned long event;
 
 	int (*write)(struct serio *, unsigned char);
 	int (*open)(struct serio *);
@@ -75,6 +76,7 @@
 int serio_open(struct serio *serio, struct serio_dev *dev);
 void serio_close(struct serio *serio);
 void serio_rescan(struct serio *serio);
+void serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags);
 
 void serio_register_port(struct serio *serio);
 void serio_unregister_port(struct serio *serio);
@@ -88,9 +90,8 @@
 
 static __inline__ void serio_dev_write_wakeup(struct serio *serio)
 {
-	if (serio->dev && serio->dev->write_wakeup) {
+	if (serio->dev && serio->dev->write_wakeup)
 		serio->dev->write_wakeup(serio);
-	}
 }
 
 #define SERIO_TIMEOUT	1
diff -Nru a/include/linux/smb_fs_sb.h b/include/linux/smb_fs_sb.h
--- a/include/linux/smb_fs_sb.h	Tue Jul 16 16:49:43 2002
+++ b/include/linux/smb_fs_sb.h	Tue Jul 16 16:49:43 2002
@@ -14,17 +14,42 @@
 #include <linux/types.h>
 #include <linux/smb.h>
 
+/*
+ * Upper limit on the total number of active smb_request structs.
+ */
+#define MAX_REQUEST_HARD       256
+
+enum smb_receive_state {
+	SMB_RECV_START,		/* No data read, looking for length + sig */
+	SMB_RECV_HEADER,	/* Reading the header data */
+	SMB_RECV_HCOMPLETE,	/* Done with the header */
+	SMB_RECV_PARAM,		/* Reading parameter words */
+	SMB_RECV_DATA,		/* Reading data bytes */
+	SMB_RECV_END,		/* End of request */
+	SMB_RECV_DROP,		/* Dropping this SMB */
+	SMB_RECV_REQUEST,	/* Received a request and not a reply */
+};
+
 /* structure access macros */
 #define server_from_inode(inode) SMB_SB((inode)->i_sb)
 #define server_from_dentry(dentry) SMB_SB((dentry)->d_sb)
 #define SB_of(server) ((server)->super_block)
 
 struct smb_sb_info {
+	/* List of all smbfs superblocks */
+	struct list_head entry;
+
         enum smb_conn_state state;
 	struct file * sock_file;
+	int conn_error;
+	enum smb_receive_state rstate;
+
+	atomic_t nr_requests;
+	struct list_head xmitq;
+	struct list_head recvq;
+	u16 mid;
 
         struct smb_mount_data_kernel *mnt;
-        unsigned char *temp_buf;
 
 	/* Connections are counted. Each time a new socket arrives,
 	 * generation is incremented.
@@ -34,13 +59,15 @@
 	struct smb_conn_opt opt;
 
 	struct semaphore sem;
-	wait_queue_head_t wait;
 
-	__u32              packet_size;
-	unsigned char *    packet;
         unsigned short     rcls; /* The error codes we received */
         unsigned short     err;
 
+	unsigned char      header[SMB_HEADER_LEN + 20*2 + 2];
+	u32                header_len;
+	u32                smb_len;
+	u32                smb_read;
+
         /* We use our own data_ready callback, but need the original one */
         void *data_ready;
 
@@ -48,15 +75,16 @@
 	struct nls_table *remote_nls;
 	struct nls_table *local_nls;
 
-	/* utf8 can make strings longer so we can't do in-place conversion.
-	   This is a buffer for temporary stuff. We only need one so no need
-	   to put it on the stack. This points to temp_buf space. */
-	char *name_buf;
-
 	struct smb_ops *ops;
+
 	struct super_block *super_block;
 };
 
+static inline int
+smb_lock_server_interruptible(struct smb_sb_info *server)
+{
+	return down_interruptible(&(server->sem));
+}
 
 static inline void
 smb_lock_server(struct smb_sb_info *server)
diff -Nru a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
--- a/include/linux/sunrpc/clnt.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/sunrpc/clnt.h	Tue Jul 16 16:49:42 2002
@@ -15,6 +15,7 @@
 #include <linux/sunrpc/auth.h>
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/timer.h>
 #include <asm/signal.h>
 
 /*
@@ -52,6 +53,8 @@
 	unsigned int		cl_flags;	/* misc client flags */
 	unsigned long		cl_hardmax;	/* max hard timeout */
 
+	struct rpc_rtt		cl_rtt;		/* RTO estimator data */
+
 	struct rpc_portmap	cl_pmap;	/* port mapping */
 	struct rpc_wait_queue	cl_bindwait;	/* waiting on getport() */
 
@@ -91,6 +94,7 @@
 	kxdrproc_t		p_decode;	/* XDR decode function */
 	unsigned int		p_bufsiz;	/* req. buffer size */
 	unsigned int		p_count;	/* call count */
+	unsigned int		p_timer;	/* Which RTT timer to use */
 };
 
 #define rpcproc_bufsiz(clnt, proc)	((clnt)->cl_procinfo[proc].p_bufsiz)
@@ -98,6 +102,7 @@
 #define rpcproc_decode(clnt, proc)	((clnt)->cl_procinfo[proc].p_decode)
 #define rpcproc_name(clnt, proc)	((clnt)->cl_procinfo[proc].p_procname)
 #define rpcproc_count(clnt, proc)	((clnt)->cl_procinfo[proc].p_count)
+#define rpcproc_timer(clnt, proc)	((clnt)->cl_procinfo[proc].p_timer)
 
 #define RPC_CONGESTED(clnt)	(RPCXPRT_CONGESTED((clnt)->cl_xprt))
 #define RPC_PEERADDR(clnt)	(&(clnt)->cl_xprt->addr)
diff -Nru a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
--- a/include/linux/sunrpc/sched.h	Tue Jul 16 16:49:41 2002
+++ b/include/linux/sunrpc/sched.h	Tue Jul 16 16:49:41 2002
@@ -75,9 +75,7 @@
 	wait_queue_head_t	tk_wait;	/* sync: sleep on this q */
 	unsigned long		tk_timeout;	/* timeout for rpc_sleep() */
 	unsigned short		tk_flags;	/* misc flags */
-	unsigned short		tk_lock;	/* Task lock counter */
-	unsigned char		tk_active   : 1,/* Task has been activated */
-				tk_wakeup   : 1;/* Task waiting to wake up */
+	unsigned char		tk_active   : 1;/* Task has been activated */
 	unsigned long		tk_runstate;	/* Task run status */
 #ifdef RPC_DEBUG
 	unsigned short		tk_pid;		/* debugging aid */
@@ -181,15 +179,11 @@
 void		rpc_remove_wait_queue(struct rpc_task *);
 void		rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
 					rpc_action action, rpc_action timer);
-void		rpc_sleep_locked(struct rpc_wait_queue *, struct rpc_task *,
-				 rpc_action action, rpc_action timer);
 void		rpc_add_timer(struct rpc_task *, rpc_action);
 void		rpc_wake_up_task(struct rpc_task *);
 void		rpc_wake_up(struct rpc_wait_queue *);
 struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
 void		rpc_wake_up_status(struct rpc_wait_queue *, int);
-int		__rpc_lock_task(struct rpc_task *);
-void		rpc_unlock_task(struct rpc_task *);
 void		rpc_delay(struct rpc_task *, unsigned long);
 void *		rpc_allocate(unsigned int flags, unsigned int);
 void		rpc_free(void *);
diff -Nru a/include/linux/sunrpc/timer.h b/include/linux/sunrpc/timer.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/sunrpc/timer.h	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,41 @@
+/*
+ *  linux/include/linux/sunrpc/timer.h
+ *
+ *  Declarations for the RPC transport timer.
+ *
+ *  Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
+ */
+
+#ifndef _LINUX_SUNRPC_TIMER_H
+#define _LINUX_SUNRPC_TIMER_H
+
+#include <asm/atomic.h>
+
+struct rpc_rtt {
+	long timeo;		/* default timeout value */
+	long srtt[5];		/* smoothed round trip time << 3 */
+	long sdrtt[5];		/* soothed medium deviation of RTT */
+	atomic_t  ntimeouts;	/* Global count of the number of timeouts */
+};
+
+
+extern void rpc_init_rtt(struct rpc_rtt *rt, long timeo);
+extern void rpc_update_rtt(struct rpc_rtt *rt, int timer, long m);
+extern long rpc_calc_rto(struct rpc_rtt *rt, int timer);
+
+static inline void rpc_inc_timeo(struct rpc_rtt *rt)
+{
+	atomic_inc(&rt->ntimeouts);
+}
+
+static inline void rpc_clear_timeo(struct rpc_rtt *rt)
+{
+	atomic_set(&rt->ntimeouts, 0);
+}
+
+static inline int rpc_ntimeo(struct rpc_rtt *rt)
+{
+	return atomic_read(&rt->ntimeouts);
+}
+
+#endif /* _LINUX_SUNRPC_TIMER_H */
diff -Nru a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
--- a/include/linux/sunrpc/xprt.h	Tue Jul 16 16:49:43 2002
+++ b/include/linux/sunrpc/xprt.h	Tue Jul 16 16:49:43 2002
@@ -19,7 +19,7 @@
  * The transport code maintains an estimate on the maximum number of out-
  * standing RPC requests, using a smoothed version of the congestion
  * avoidance implemented in 44BSD. This is basically the Van Jacobson
- * slow start algorithm: If a retransmit occurs, the congestion window is
+ * congestion algorithm: If a retransmit occurs, the congestion window is
  * halved; otherwise, it is incremented by 1/cwnd when
  *
  *	-	a reply is received and
@@ -32,15 +32,13 @@
  * Note: on machines with low memory we should probably use a smaller
  * MAXREQS value: At 32 outstanding reqs with 8 megs of RAM, fragment
  * reassembly will frequently run out of memory.
- * Come Linux 2.3, we'll handle fragments directly.
  */
-#define RPC_MAXCONG		16
-#define RPC_MAXREQS		(RPC_MAXCONG + 1)
-#define RPC_CWNDSCALE		256
+#define RPC_MAXCONG		(16)
+#define RPC_MAXREQS		RPC_MAXCONG
+#define RPC_CWNDSCALE		(256)
 #define RPC_MAXCWND		(RPC_MAXCONG * RPC_CWNDSCALE)
-#define RPC_INITCWND		RPC_CWNDSCALE
-#define RPCXPRT_CONGESTED(xprt) \
-	((xprt)->cong >= (xprt)->cwnd)
+#define RPC_INITCWND		(RPC_MAXCWND >> 1)
+#define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd)
 
 /* Default timeout values */
 #define RPC_MAX_UDP_TIMEOUT	(60*HZ)
@@ -83,7 +81,10 @@
 	struct rpc_task *	rq_task;	/* RPC task data */
 	__u32			rq_xid;		/* request XID */
 	struct rpc_rqst *	rq_next;	/* free list */
-	volatile unsigned char	rq_received : 1;/* receive completed */
+	int			rq_cong;	/* has incremented xprt->cong */
+	int			rq_received;	/* receive completed */
+
+	struct list_head	rq_list;
 
 	/*
 	 * For authentication (e.g. auth_des)
@@ -96,9 +97,9 @@
 	
 	u32			rq_bytes_sent;	/* Bytes we have sent */
 
-#ifdef RPC_PROFILE
-	unsigned long		rq_xtime;	/* when transmitted */
-#endif
+	long			rq_xtime;	/* when transmitted */
+	int			rq_ntimeo;
+	int			rq_nresend;
 };
 #define rq_svec			rq_snd_buf.head
 #define rq_slen			rq_snd_buf.len
@@ -120,9 +121,9 @@
 
 	unsigned long		cong;		/* current congestion */
 	unsigned long		cwnd;		/* congestion window */
-	unsigned long		congtime;	/* hold cwnd until then */
 
 	struct rpc_wait_queue	sending;	/* requests waiting to send */
+	struct rpc_wait_queue	resend;		/* requests waiting to resend */
 	struct rpc_wait_queue	pending;	/* requests in flight */
 	struct rpc_wait_queue	backlog;	/* waiting for slot */
 	struct rpc_rqst *	free;		/* free slots */
@@ -148,6 +149,8 @@
 	spinlock_t		sock_lock;	/* lock socket info */
 	spinlock_t		xprt_lock;	/* lock xprt info */
 	struct rpc_task *	snd_task;	/* Task blocked in send */
+
+	struct list_head	recv;
 
 
 	void			(*old_data_ready)(struct sock *, int);
diff -Nru a/include/linux/suspend.h b/include/linux/suspend.h
--- a/include/linux/suspend.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/suspend.h	Tue Jul 16 16:49:42 2002
@@ -56,9 +56,22 @@
 extern int unregister_suspend_notifier(struct notifier_block *);
 extern void refrigerator(unsigned long);
 
+extern int freeze_processes(void);
+extern void thaw_processes(void);
+
 extern unsigned int nr_copy_pages __nosavedata;
 extern suspend_pagedir_t *pagedir_nosave __nosavedata;
 
+/* Communication between kernel/suspend.c and arch/i386/suspend.c */
+
+extern void do_magic_resume_1(void);
+extern void do_magic_resume_2(void);
+extern void do_magic_suspend_1(void);
+extern void do_magic_suspend_2(void);
+
+/* Communication between acpi and arch/i386/suspend.c */
+
+extern void do_suspend_lowlevel(int resume);
 
 #else
 #define software_suspend()		do { } while(0)
diff -Nru a/include/linux/sysrq.h b/include/linux/sysrq.h
--- a/include/linux/sysrq.h	Tue Jul 16 16:49:41 2002
+++ b/include/linux/sysrq.h	Tue Jul 16 16:49:41 2002
@@ -14,12 +14,10 @@
 #include <linux/config.h>
 
 struct pt_regs;
-struct kbd_struct;
 struct tty_struct;
 
 struct sysrq_key_op {
-	void (*handler)(int, struct pt_regs *,
-			struct kbd_struct *, struct tty_struct *);
+	void (*handler)(int, struct pt_regs *, struct tty_struct *);
 	char *help_msg;
 	char *action_msg;
 };
@@ -31,19 +29,14 @@
  * are available -- else NULL's).
  */
 
-void handle_sysrq(int, struct pt_regs *,
-		struct kbd_struct *, struct tty_struct *);
-
+void handle_sysrq(int, struct pt_regs *, struct tty_struct *);
 
 /* 
  * Nonlocking version of handle sysrq, used by sysrq handlers that need to
  * call sysrq handlers
  */
 
-void __handle_sysrq_nolock(int, struct pt_regs *,
-                struct kbd_struct *, struct tty_struct *);
-
-
+void __handle_sysrq_nolock(int, struct pt_regs *, struct tty_struct *);
 
 /*
  * Sysrq registration manipulation functions
diff -Nru a/include/linux/uinput.h b/include/linux/uinput.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/uinput.h	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,78 @@
+#ifndef __UINPUT_H_
+#define __UINPUT_H_
+/*
+ *  User level driver support for input subsystem
+ *
+ * Heavily based on evdev.c by Vojtech Pavlik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
+ * 
+ * Changes/Revisions:
+ *	0.1	20/06/2002
+ *		- first public version
+ */
+#ifdef __KERNEL__
+#define UINPUT_MINOR		223
+#define UINPUT_NAME		"uinput"
+#define UINPUT_BUFFER_SIZE	16
+#define U_MAX_NAME_SIZE		50
+
+#define UIST_CREATED		1
+
+struct uinput_device {
+	struct input_dev	*dev;
+	unsigned long		state;
+	wait_queue_head_t	waitq;
+	unsigned char		ready,
+				head,
+				tail;
+	struct input_event	buff[UINPUT_BUFFER_SIZE];
+};
+#endif	/* __KERNEL__ */
+
+/* ioctl */
+#define UINPUT_IOCTL_BASE	'U'
+#define UI_DEV_CREATE		_IO(UINPUT_IOCTL_BASE, 1)
+#define UI_DEV_DESTROY		_IO(UINPUT_IOCTL_BASE, 2)
+#define UI_SET_EVBIT		_IOW(UINPUT_IOCTL_BASE, 100, int)
+#define UI_SET_KEYBIT		_IOW(UINPUT_IOCTL_BASE, 101, int)
+#define UI_SET_RELBIT		_IOW(UINPUT_IOCTL_BASE, 102, int)
+#define UI_SET_ABSBIT		_IOW(UINPUT_IOCTL_BASE, 103, int)
+#define UI_SET_MSCBIT		_IOW(UINPUT_IOCTL_BASE, 104, int)
+#define UI_SET_LEDBIT		_IOW(UINPUT_IOCTL_BASE, 105, int)
+#define UI_SET_SNDBIT		_IOW(UINPUT_IOCTL_BASE, 106, int)
+#define UI_SET_FFBIT		_IOW(UINPUT_IOCTL_BASE, 107, int)
+
+#ifndef NBITS
+#define NBITS(x) ((((x)-1)/(sizeof(long)*8))+1)
+#endif	/* NBITS */
+
+#define UINPUT_MAX_NAME_SIZE	80
+struct uinput_user_dev {
+	char name[UINPUT_MAX_NAME_SIZE];
+	unsigned short idbus;
+        unsigned short idvendor;
+        unsigned short idproduct;
+        unsigned short idversion;
+        int ff_effects_max;
+        int absmax[ABS_MAX + 1];
+        int absmin[ABS_MAX + 1];
+        int absfuzz[ABS_MAX + 1];
+        int absflat[ABS_MAX + 1];
+};
+#endif	/* __UINPUT_H_ */
+
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	Tue Jul 16 16:49:42 2002
+++ b/include/linux/usb.h	Tue Jul 16 16:49:42 2002
@@ -466,7 +466,7 @@
  * than changeable ("unstable") ones like bus numbers or device addresses.
  *
  * With a partial exception for devices connected to USB 2.0 root hubs, these
- * identifiers are also predictable:  so long as the device tree isn't changed,
+ * identifiers are also predictable.  So long as the device tree isn't changed,
  * plugging any USB device into a given hub port always gives it the same path.
  * Because of the use of "companion" controllers, devices connected to ports on
  * USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are
@@ -722,16 +722,14 @@
 /*
  * urb->transfer_flags:
  *
- * FIXME should be URB_* flags
+ * FIXME should _all_ be URB_* flags
  */
-#define USB_DISABLE_SPD		0x0001
-#define USB_ISO_ASAP		0x0002
-#define USB_ASYNC_UNLINK	0x0008
-#define USB_QUEUE_BULK		0x0010
-#define USB_NO_FSBR		0x0020
+#define URB_SHORT_NOT_OK	0x0001	/* report short reads as errors */
+#define USB_ISO_ASAP		0x0002	/* iso-only, urb->start_frame ignored */
+#define USB_ASYNC_UNLINK	0x0008	/* usb_unlink_urb() returns asap */
+#define USB_NO_FSBR		0x0020	/* UHCI-specific */
 #define USB_ZERO_PACKET		0x0040	/* Finish bulk OUTs with short packet */
 #define URB_NO_INTERRUPT	0x0080	/* HINT: no non-error interrupt needed */
-					/* ... less overhead for QUEUE_BULK */
 #define USB_TIMEOUT_KILLED	0x1000	/* only set by HCD! */
 
 struct usb_iso_packet_descriptor {
@@ -777,9 +775,9 @@
  * @actual_length: This is read in non-iso completion functions, and
  *	it tells how many bytes (out of transfer_buffer_length) were
  *	transferred.  It will normally be the same as requested, unless
- *	either an error was reported or a short read was performed and
- *	the USB_DISABLE_SPD transfer flag was used to say that such
- *	short reads are not errors. 
+ *	either an error was reported or a short read was performed.
+ *	The URB_SHORT_NOT_OK transfer flag may be used to make such
+ *	short reads be reported as errors. 
  * @setup_packet: Only used for control transfers, this points to eight bytes
  *	of setup data.  Control transfers always start by sending this data
  *	to the device.  Then transfer_buffer is read or written, if needed.
@@ -814,14 +812,10 @@
  *
  * All non-isochronous URBs must also initialize 
  * transfer_buffer and transfer_buffer_length.  They may provide the
- * USB_DISABLE_SPD transfer flag, indicating that short reads are
- * not to be treated as errors.
+ * URB_SHORT_NOT_OK transfer flag, indicating that short reads are
+ * to be treated as errors.
  *
- * Bulk URBs may pass the USB_QUEUE_BULK transfer flag, telling the host
- * controller driver never to report an error if several bulk requests get
- * queued to the same endpoint.  Such queueing supports more efficient use
- * of bus bandwidth, minimizing delays due to interrupts and scheduling,
- * if the host controller hardware is smart enough.  Bulk URBs can also
+ * Bulk URBs may
  * use the USB_ZERO_PACKET transfer flag, indicating that bulk OUT transfers
  * should always terminate with a short packet, even if it means adding an
  * extra zero length packet.
@@ -853,7 +847,7 @@
  * the quality of service is only "best effort".  Callers provide specially
  * allocated URBs, with number_of_packets worth of iso_frame_desc structures
  * at the end.  Each such packet is an individual ISO transfer.  Isochronous
- * URBs are normally queued (no flag like USB_BULK_QUEUE is needed) so that
+ * URBs are normally queued, submitted by drivers to arrange that
  * transfers are at least double buffered, and then explicitly resubmitted
  * in completion handlers, so
  * that data (such as audio or video) streams at as constant a rate as the
@@ -892,7 +886,7 @@
 	struct usb_device *dev; 	/* (in) pointer to associated device */
 	unsigned int pipe;		/* (in) pipe information */
 	int status;			/* (return) non-ISO status */
-	unsigned int transfer_flags;	/* (in) USB_DISABLE_SPD | ...*/
+	unsigned int transfer_flags;	/* (in) URB_SHORT_NOT_OK | ...*/
 	void *transfer_buffer;		/* (in) associated data buffer */
 	int transfer_buffer_length;	/* (in) data buffer length */
 	int actual_length;		/* (return) actual transfer length */
diff -Nru a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
--- a/include/linux/usbdevice_fs.h	Tue Jul 16 16:49:41 2002
+++ b/include/linux/usbdevice_fs.h	Tue Jul 16 16:49:41 2002
@@ -78,9 +78,8 @@
 	unsigned char slow;
 };
 
-#define USBDEVFS_URB_DISABLE_SPD           1
+#define USBDEVFS_URB_SHORT_NOT_OK          1
 #define USBDEVFS_URB_ISO_ASAP              2
-#define USBDEVFS_URB_QUEUE_BULK            0x10
 
 #define USBDEVFS_URB_TYPE_ISO		   0
 #define USBDEVFS_URB_TYPE_INTERRUPT	   1
diff -Nru a/include/linux/vt_kern.h b/include/linux/vt_kern.h
--- a/include/linux/vt_kern.h	Tue Jul 16 16:49:43 2002
+++ b/include/linux/vt_kern.h	Tue Jul 16 16:49:43 2002
@@ -91,6 +91,5 @@
 int vt_waitactive(int vt);
 void change_console(unsigned int);
 void reset_vc(unsigned int new_console);
-int vt_waitactive(int vt);
 
 #endif /* _VT_KERN_H */
diff -Nru a/include/net/dsfield.h b/include/net/dsfield.h
--- a/include/net/dsfield.h	Tue Jul 16 16:49:43 2002
+++ b/include/net/dsfield.h	Tue Jul 16 16:49:43 2002
@@ -51,29 +51,4 @@
 }
 
 
-#if 0 /* put this later into asm-i386 or such ... */
-
-static inline void ip_change_dsfield(struct iphdr *iph,__u16 dsfield)
-{
-	__u16 check;
-
-	__asm__ __volatile__("
-		movw	10(%1),%0
-		xchg	%b0,%h0
-		addb	1(%1),%b0
-		adcb	$0,%h0
-		adcw	$1,%0
-		cmc
-		sbbw	%2,%0
-		sbbw	$0,%0
-		movb	%b2,1(%1)
-		xchg	%b0,%h0
-		movw	%0,10(%1)"
-	    : "=&r" (check)
-	    : "r" (iph), "r" (dsfield)
-	    : "cc");
-}
-
-#endif
-
 #endif
diff -Nru a/include/net/tcp.h b/include/net/tcp.h
--- a/include/net/tcp.h	Tue Jul 16 16:49:41 2002
+++ b/include/net/tcp.h	Tue Jul 16 16:49:41 2002
@@ -456,7 +456,6 @@
 extern int sysctl_tcp_retrans_collapse;
 extern int sysctl_tcp_stdurg;
 extern int sysctl_tcp_rfc1337;
-extern int sysctl_tcp_tw_recycle;
 extern int sysctl_tcp_abort_on_overflow;
 extern int sysctl_tcp_max_orphans;
 extern int sysctl_tcp_max_tw_buckets;
diff -Nru a/include/scsi/sg.h b/include/scsi/sg.h
--- a/include/scsi/sg.h	Tue Jul 16 16:49:42 2002
+++ b/include/scsi/sg.h	Tue Jul 16 16:49:42 2002
@@ -11,24 +11,15 @@
 Version 2 and 3 extensions to driver:
 *       Copyright (C) 1998 - 2002 Douglas Gilbert
 
-    Version: 3.5.25 (20020504)
+    Version: 3.5.26 (20020708)
     This version is for 2.5 series kernels.
 
-    Changes since 3.5.24 (20020319)
-	- off by one fix for last scatter gather element
-	- if possible compact kiobuf_map into scatter gather list
-	- use Scsi_Request::upper_private_data
-	- zero buffers for non-root users
-    Changes since 3.5.23 (20011231)
-	- change EACCES to EPERM when O_RDONLY is insufficient
-	- suppress newlines in host string
-	- fix xfer direction, old interface, short reply_len [Travers Carter]
-    Changes since 3.1.22 (20011208)
-    	- branch sg driver for lk 2.5 series
-    	- remove lock_kernel() from sg_close()
-    	- remove code based on scsi mid level dma pool
-    	- change scatterlist 'address' to use page + offset
-    	- add SG_INTERFACE_ID_ORIG
+    Changes since 3.5.25 (20020504)
+	- driverfs additions
+	- copy_to/from_user() fixes [William Stinson]
+	- disable kiobufs support
+
+    For a full changelog see http://www.torque.net/sg
 
 Map of SG verions to the Linux kernels in which they appear:
        ----------        ----------------------------------
diff -Nru a/ipc/msg.c b/ipc/msg.c
--- a/ipc/msg.c	Tue Jul 16 16:49:41 2002
+++ b/ipc/msg.c	Tue Jul 16 16:49:41 2002
@@ -597,7 +597,7 @@
 	return 0;
 }
 
-int inline pipelined_send(struct msg_queue* msq, struct msg_msg* msg)
+static int inline pipelined_send(struct msg_queue* msq, struct msg_msg* msg)
 {
 	struct list_head* tmp;
 
@@ -706,7 +706,7 @@
 	return err;
 }
 
-int inline convert_mode(long* msgtyp, int msgflg)
+static int inline convert_mode(long* msgtyp, int msgflg)
 {
 	/* 
 	 *  find message of correct type.
diff -Nru a/ipc/sem.c b/ipc/sem.c
--- a/ipc/sem.c	Tue Jul 16 16:49:42 2002
+++ b/ipc/sem.c	Tue Jul 16 16:49:42 2002
@@ -441,7 +441,7 @@
 	}
 }
 
-int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg)
+static int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg)
 {
 	int err = -EINVAL;
 
@@ -513,7 +513,7 @@
 	return err;
 }
 
-int semctl_main(int semid, int semnum, int cmd, int version, union semun arg)
+static int semctl_main(int semid, int semnum, int cmd, int version, union semun arg)
 {
 	struct sem_array *sma;
 	struct sem* curr;
@@ -700,7 +700,7 @@
 	}
 }
 
-int semctl_down(int semid, int semnum, int cmd, int version, union semun arg)
+static int semctl_down(int semid, int semnum, int cmd, int version, union semun arg)
 {
 	struct sem_array *sma;
 	int err;
diff -Nru a/kernel/futex.c b/kernel/futex.c
--- a/kernel/futex.c	Tue Jul 16 16:49:42 2002
+++ b/kernel/futex.c	Tue Jul 16 16:49:42 2002
@@ -48,7 +48,7 @@
 extern void send_sigio(struct fown_struct *fown, int fd, int band);
 
 /* Everyone needs a dentry and inode */
-static struct dentry *futex_dentry;
+static struct vfsmount *futex_mnt;
 
 /* We use this instead of a normal wait_queue_t, so we can wake only
    the relevent ones (hashed queues may be shared) */
@@ -272,10 +272,11 @@
 		return -ENFILE;
 	}
 	filp->f_op = &futex_fops;
-	filp->f_dentry = dget(futex_dentry);
+	filp->f_vfsmnt = mntget(futex_mnt);
+	filp->f_dentry = dget(futex_mnt->mnt_root);
 
 	if (signal) {
-		filp->f_owner.pid = current->pid;
+		filp->f_owner.pid = current->tgid;
 		filp->f_owner.uid = current->uid;
 		filp->f_owner.euid = current->euid;
 		filp->f_owner.signum = signal;
@@ -348,46 +349,16 @@
 	return ret;
 }
 
-/* FIXME: Oh yeah, makes sense to write a filesystem... */
-static struct super_operations futexfs_ops = { statfs: simple_statfs };
-
-/* Don't check error returns: we're dead if they happen */
-static int futexfs_fill_super(struct super_block *sb, void *data, int silent)
-{
-	struct inode *root;
-
-	sb->s_blocksize = 1024;
-	sb->s_blocksize_bits = 10;
-	sb->s_magic = 0xBAD1DEA;
-	sb->s_op = &futexfs_ops;
-
-	root = new_inode(sb);
-	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
-	root->i_uid = root->i_gid = 0;
-	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
-
-	sb->s_root = d_alloc(NULL, &(const struct qstr) { "futex", 5, 0 });
-	sb->s_root->d_sb = sb;
-	sb->s_root->d_parent = sb->s_root;
-	d_instantiate(sb->s_root, root);
-
-	/* We never let this drop to zero. */
-	futex_dentry = dget(sb->s_root);
-
-	return 0;
-}
-
 static struct super_block *
 futexfs_get_sb(struct file_system_type *fs_type,
 	       int flags, char *dev_name, void *data)
 {
-	return get_sb_nodev(fs_type, flags, data, futexfs_fill_super);
+	return get_sb_pseudo(fs_type, "futex", NULL, 0xBAD1DEA);
 }
 
 static struct file_system_type futex_fs_type = {
 	name:		"futexfs",
 	get_sb:		futexfs_get_sb,
-	kill_sb:	kill_anon_super,
 };
 
 static int __init init(void)
@@ -395,7 +366,7 @@
 	unsigned int i;
 
 	register_filesystem(&futex_fs_type);
-	kern_mount(&futex_fs_type);
+	futex_mnt = kern_mount(&futex_fs_type);
 
 	for (i = 0; i < ARRAY_SIZE(futex_queues); i++)
 		INIT_LIST_HEAD(&futex_queues[i]);
diff -Nru a/kernel/panic.c b/kernel/panic.c
--- a/kernel/panic.c	Tue Jul 16 16:49:42 2002
+++ b/kernel/panic.c	Tue Jul 16 16:49:42 2002
@@ -66,7 +66,7 @@
 	smp_send_stop();
 #endif
 
-	notifier_call_chain(&panic_notifier_list, 0, NULL);
+       notifier_call_chain(&panic_notifier_list, 0, buf);
 
 	if (panic_timeout > 0)
 	{
diff -Nru a/kernel/platform.c b/kernel/platform.c
--- a/kernel/platform.c	Tue Jul 16 16:49:43 2002
+++ b/kernel/platform.c	Tue Jul 16 16:49:43 2002
@@ -6,10 +6,6 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 
-static struct platform_t default_platform;
-
-struct platform_t * platform = &default_platform;
-static spinlock_t platform_lock = SPIN_LOCK_UNLOCKED;
 
 void default_reboot(char * cmd)
 {
@@ -35,6 +31,9 @@
 	suspend:	default_suspend,
 	idle:		default_idle,
 };
+
+struct platform_t * platform = &default_platform;
+static spinlock_t platform_lock = SPIN_LOCK_UNLOCKED;
 
 /**
  * set_platform_driver - set the platform driver.
diff -Nru a/kernel/pm.c b/kernel/pm.c
--- a/kernel/pm.c	Tue Jul 16 16:49:41 2002
+++ b/kernel/pm.c	Tue Jul 16 16:49:41 2002
@@ -31,7 +31,7 @@
  *	Locking notes:
  *		pm_devs_lock can be a semaphore providing pm ops are not called
  *	from an interrupt handler (already a bad idea so no change here). Each
- *	change must be protected so that an unlink of an entry doesnt clash
+ *	change must be protected so that an unlink of an entry doesn't clash
  *	with a pm send - which is permitted to sleep in the current architecture
  *
  *	Module unloads clashing with pm events now work out safely, the module 
diff -Nru a/kernel/printk.c b/kernel/printk.c
--- a/kernel/printk.c	Tue Jul 16 16:49:42 2002
+++ b/kernel/printk.c	Tue Jul 16 16:49:42 2002
@@ -31,6 +31,8 @@
 
 #if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64)
 #define LOG_BUF_LEN	(65536)
+#elif defined(CONFIG_ARCH_S390)
+#define LOG_BUF_LEN	(131072)
 #elif defined(CONFIG_SMP)
 #define LOG_BUF_LEN	(32768)
 #else	
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Tue Jul 16 16:49:42 2002
+++ b/kernel/sched.c	Tue Jul 16 16:49:42 2002
@@ -928,7 +928,7 @@
  * started to run but is not in state TASK_RUNNING.  try_to_wake_up() returns
  * zero in this (rare) case, and we handle it by continuing to scan the queue.
  */
-static inline void __wake_up_common(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, int sync)
+static void __wake_up_common(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, int sync)
 {
 	struct list_head *tmp, *next;
 
@@ -956,6 +956,14 @@
 	spin_unlock_irqrestore(&q->lock, flags);
 }
 
+/*
+ * Same as __wake_up but called with the spinlock in wait_queue_head_t held.
+ */
+void __wake_up_locked(wait_queue_head_t *q, unsigned int mode)
+{
+	__wake_up_common(q, mode, 1, 0);
+}
+
 #if CONFIG_SMP
 
 void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
@@ -1430,8 +1438,7 @@
 		} else
 			current->time_slice--;
 	} else if (unlikely(rt_task(current))) {
-		list_del(&current->run_list);
-		list_add_tail(&current->run_list, array->queue + current->prio);
+		list_move_tail(&current->run_list, array->queue + current->prio);
 	} else {
 		list_del(&current->run_list);
 		if (list_empty(array->queue + current->prio))
@@ -1699,6 +1706,7 @@
 	rq = this_rq();
 	rq->curr = current;
 	rq->idle = current;
+	set_task_cpu(current, smp_processor_id());
 	wake_up_process(current);
 
 	init_timervecs();
diff -Nru a/kernel/softirq.c b/kernel/softirq.c
--- a/kernel/softirq.c	Tue Jul 16 16:49:42 2002
+++ b/kernel/softirq.c	Tue Jul 16 16:49:42 2002
@@ -61,7 +61,7 @@
 
 asmlinkage void do_softirq()
 {
-	unsigned long cpu;
+	int cpu;
 	__u32 pending;
 	long flags;
 	__u32 mask;
diff -Nru a/kernel/suspend.c b/kernel/suspend.c
--- a/kernel/suspend.c	Tue Jul 16 16:49:42 2002
+++ b/kernel/suspend.c	Tue Jul 16 16:49:42 2002
@@ -69,7 +69,7 @@
 
 unsigned char software_suspend_enabled = 0;
 
-/* #define SUSPEND_CONSOLE	(MAX_NR_CONSOLES-1) */
+#define SUSPEND_CONSOLE	(MAX_NR_CONSOLES-1)
 /* With SUSPEND_CONSOLE defined, it suspend looks *really* cool, but
    we probably do not take enough locks for switching consoles, etc,
    so bad things might happen.
@@ -97,7 +97,7 @@
 /* Variables to be preserved over suspend */
 static int new_loglevel = 7;
 static int orig_loglevel = 0;
-static int orig_fgconsole;
+static int orig_fgconsole, orig_kmsg;
 static int pagedir_order_check;
 static int nr_copy_pages_check;
 
@@ -139,32 +139,23 @@
  */
 #define PAGES_FOR_IO	512
 
-static const char *name_suspend = "Suspend Machine: ";
-static const char *name_resume = "Resume Machine: ";
+static const char name_suspend[] = "Suspend Machine: ";
+static const char name_resume[] = "Resume Machine: ";
 
 /*
  * Debug
  */
-#define	DEBUG_DEFAULT	1
+#undef	DEBUG_DEFAULT
 #undef	DEBUG_PROCESS
 #undef	DEBUG_SLOW
 #define TEST_SWSUSP 1		/* Set to 1 to reboot instead of halt machine after suspension */
 
 #ifdef DEBUG_DEFAULT
-#define PRINTD(func, f, a...)	\
-	do { \
-		printk("%s", func); \
-		printk(f, ## a); \
-	} while(0)
-#define PRINTS(f, a...)	PRINTD(name_suspend, f, ## a)
-#define PRINTR(f, a...)	PRINTD(name_resume, f, ## a)
-#define PRINTK(f, a...)	printk(f, ## a)
+# define PRINTK(f, a...)       printk(f, ## a)
 #else
-#define PRINTD(func, f, a...)
-#define PRINTS(f, a...)
-#define PRINTR(f, a...)
-#define PRINTK(f, a...)
+# define PRINTK(f, a...)
 #endif
+
 #ifdef DEBUG_SLOW
 #define MDELAY(a) mdelay(a)
 #else
@@ -195,8 +186,8 @@
 	long save;
 	save = current->state;
 	current->state = TASK_STOPPED;
-//	PRINTK("%s entered refrigerator\n", current->comm);
-	printk(":");
+	PRINTK("%s entered refrigerator\n", current->comm);
+	printk("=");
 	current->flags &= ~PF_FREEZE;
 	if (flag)
 		flush_signals(current); /* We have signaled a kernel thread, which isn't normal behaviour
@@ -205,8 +196,7 @@
 	current->flags |= PF_FROZEN;
 	while (current->flags & PF_FROZEN)
 		schedule();
-//	PRINTK("%s left refrigerator\n", current->comm);
-	printk(":");
+	PRINTK("%s left refrigerator\n", current->comm);
 	current->state = save;
 }
 
@@ -216,8 +206,7 @@
 	int todo, start_time;
 	struct task_struct *p;
 	
-	PRINTS( "Waiting for tasks to stop... " );
-	
+	printk( "Stopping tasks: " );
 	start_time = jiffies;
 	do {
 		todo = 0;
@@ -239,13 +228,13 @@
 		read_unlock(&tasklist_lock);
 		yield();
 		if (time_after(jiffies, start_time + TIMEOUT)) {
-			PRINTK( "\n" );
+			printk( "\n" );
 			printk(KERN_ERR " stopping tasks failed (%d tasks remaining)\n", todo );
 			return todo;
 		}
 	} while(todo);
 	
-	PRINTK( " ok\n" );
+	printk( "|\n" );
 	return 0;
 }
 
@@ -253,7 +242,7 @@
 {
 	struct task_struct *p;
 
-	PRINTR( "Restarting tasks..." );
+	printk( "Restarting tasks..." );
 	read_lock(&tasklist_lock);
 	for_each_task(p) {
 		INTERESTING(p);
@@ -264,7 +253,7 @@
 		wake_up_process(p);
 	}
 	read_unlock(&tasklist_lock);
-	PRINTK( " done\n" );
+	printk( " done\n" );
 	MDELAY(500);
 }
 
@@ -284,8 +273,7 @@
 	sh->num_cpus = num_online_cpus();
 	sh->page_size = PAGE_SIZE;
 	sh->suspend_pagedir = pagedir_nosave;
-	if (pagedir_save != pagedir_nosave)
-		panic("Must not happen");
+	BUG_ON (pagedir_save != pagedir_nosave);
 	sh->num_pbes = nr_copy_pages;
 	/* TODO: needed? mounted fs' last mounted date comparison
 	 * [so they haven't been mounted since last suspend.
@@ -376,7 +364,7 @@
 					root_swap = i;
 				} else {
 #if 0
-					PRINTS( "device %s (%x != %x) ignored\n", swap_info[i].swap_file->d_name.name, swap_info[i].swap_device, resume_device );				  
+					printk( "Resume: device %s (%x != %x) ignored\n", swap_info[i].swap_file->d_name.name, swap_info[i].swap_device, resume_device );				  
 #endif
 				  	swapfile_used[i] = SWAPFILE_IGNORED;
 				}
@@ -409,14 +397,14 @@
 	unsigned long address;
 	struct page *page;
 
-	PRINTS( "Writing data to swap (%d pages): ", nr_copy_pages );
+	printk( "Writing data to swap (%d pages): ", nr_copy_pages );
 	for (i=0; i<nr_copy_pages; i++) {
 		if (!(i%100))
-			PRINTK( "." );
+			printk( "." );
 		if (!(entry = get_swap_page()).val)
 			panic("\nNot enough swapspace when writing data" );
 		
-		if(swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
+		if (swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
 			panic("\nPage %d: not enough swapspace on suspend device", i );
 	    
 		address = (pagedir_nosave+i)->address;
@@ -424,13 +412,12 @@
 		rw_swap_page_sync(WRITE, entry, page);
 		(pagedir_nosave+i)->swap_address = entry;
 	}
-	PRINTK(" done\n");
-	PRINTS( "Writing pagedir (%d pages): ", nr_pgdir_pages);
+	printk( "|\n" );
+	printk( "Writing pagedir (%d pages): ", nr_pgdir_pages);
 	for (i=0; i<nr_pgdir_pages; i++) {
 		cur = (union diskpage *)((char *) pagedir_nosave)+i;
-		if ((char *) cur != (((char *) pagedir_nosave) + i*PAGE_SIZE))
-			panic("Something is of wrong size");
-		PRINTK( "." );
+		BUG_ON ((char *) cur != (((char *) pagedir_nosave) + i*PAGE_SIZE));
+		printk( "." );
 		if (!(entry = get_swap_page()).val) {
 			printk(KERN_CRIT "Not enough swapspace when writing pgdir\n" );
 			panic("Don't know how to recover");
@@ -439,30 +426,26 @@
 		}
 
 		if(swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
-		  panic("\nNot enough swapspace for pagedir on suspend device" );
+			panic("\nNot enough swapspace for pagedir on suspend device" );
+
+		BUG_ON (sizeof(swp_entry_t) != sizeof(long));
+		BUG_ON (PAGE_SIZE % sizeof(struct pbe));
 
-		if (sizeof(swp_entry_t) != sizeof(long))
-			panic("I need swp_entry_t to be sizeof long, otherwise next assignment could damage pagedir");
-		if (PAGE_SIZE % sizeof(struct pbe))
-			panic("I need PAGE_SIZE to be integer multiple of struct pbe, otherwise next assignment could damage pagedir");
 		cur->link.next = prev;				
 		page = virt_to_page((unsigned long)cur);
 		rw_swap_page_sync(WRITE, entry, page);
 		prev = entry;
 	}
-	PRINTK(", header");
-	if (sizeof(struct suspend_header) > PAGE_SIZE-sizeof(swp_entry_t))
-		panic("sizeof(struct suspend_header) too big: %d",
-				sizeof(struct suspend_header));
-	if (sizeof(union diskpage) != PAGE_SIZE)
-		panic("union diskpage has bad size");
+	printk("H");
+	BUG_ON (sizeof(struct suspend_header) > PAGE_SIZE-sizeof(swp_entry_t));
+	BUG_ON (sizeof(union diskpage) != PAGE_SIZE);
 	if (!(entry = get_swap_page()).val)
 		panic( "\nNot enough swapspace when writing header" );
-	if(swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
-	  panic("\nNot enough swapspace for header on suspend device" );
+	if (swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
+		panic("\nNot enough swapspace for header on suspend device" );
 
 	cur = (void *) buffer;
-	if(fill_suspend_header(&cur->sh))
+	if (fill_suspend_header(&cur->sh))
 		panic("\nOut of memory while writing header");
 		
 	cur->link.next = prev;
@@ -471,13 +454,9 @@
 	rw_swap_page_sync(WRITE, entry, page);
 	prev = entry;
 
-	PRINTK( ", signature" );
-#if 0
-	if (swp_type(entry) != 0)
-		panic("Need just one swapfile");
-#endif
+	printk( "S" );
 	mark_swapfiles(prev, MARK_SWAP_SUSPEND);
-	PRINTK( ", done\n" );
+	printk( "|\n" );
 
 	MDELAY(1000);
 	free_page((unsigned long) buffer);
@@ -493,20 +472,19 @@
 	
 	if (max_mapnr != num_physpages)
 		panic("mapnr is not expected");
-	for(loop = 0; loop < max_mapnr; loop++) {
-		if(PageHighMem(mem_map+loop))
-			panic("No highmem for me, sorry.");
-		if(!PageReserved(mem_map+loop)) {
-			if(PageNosave(mem_map+loop))
+	for (loop = 0; loop < max_mapnr; loop++) {
+		if (PageHighMem(mem_map+loop))
+			panic("Swsusp not supported on highmem boxes. Send 1GB of RAM to <pavel@ucw.cz> and try again ;-).");
+		if (!PageReserved(mem_map+loop)) {
+			if (PageNosave(mem_map+loop))
 				continue;
 
-			if((chunk_size=is_head_of_free_region(mem_map+loop))!=0) {
+			if ((chunk_size=is_head_of_free_region(mem_map+loop))!=0) {
 				loop += chunk_size - 1;
 				continue;
 			}
-		} else if(PageReserved(mem_map+loop)) {
-			if(PageNosave(mem_map+loop))
-				panic("What?");
+		} else if (PageReserved(mem_map+loop)) {
+			BUG_ON (PageNosave(mem_map+loop));
 
 			/*
 			 * Just copy whole code segment. Hopefully it is not that big.
@@ -514,15 +492,15 @@
 			if (ADDRESS(loop) >= (unsigned long)
 				&__nosave_begin && ADDRESS(loop) < 
 				(unsigned long)&__nosave_end) {
-				printk("[nosave]");
+				PRINTK("[nosave %x]", ADDRESS(loop));
 				continue;
 			}
 			/* Hmm, perhaps copying all reserved pages is not too healthy as they may contain 
 			   critical bios data? */
-		} else panic("No third thing should be possible");
+		} else	BUG();
 
 		nr_copy_pages++;
-		if(pagedir_p) {
+		if (pagedir_p) {
 			pagedir_p->orig_address = ADDRESS(loop);
 			copy_page(pagedir_p->address, pagedir_p->orig_address);
 			pagedir_p++;
@@ -539,10 +517,10 @@
 		(PAGE_SIZE << pagedir_order);
 
 	for(i=0; i < num_physpages; i++, page++) {
-		if(!TestClearPageNosave(page))
+		if (!TestClearPageNosave(page))
 			continue;
 
-		if(ADDRESS(i) >= this_pagedir && ADDRESS(i) < this_pagedir_end)
+		if (ADDRESS(i) >= this_pagedir && ADDRESS(i) < this_pagedir_end)
 			continue; /* old pagedir gets freed in one */
 		
 		free_page(ADDRESS(i));
@@ -570,7 +548,6 @@
 	while(nr_copy_pages--) {
 		p->address = get_free_page(GFP_ATOMIC);
 		if(!p->address) {
-			panic("oom");
 			free_suspend_pagedir((unsigned long) pagedir);
 			return NULL;
 		}
@@ -596,9 +573,11 @@
 
 	set_console (SUSPEND_CONSOLE);
 	if(vt_waitactive(SUSPEND_CONSOLE)) {
-		PRINTS("Bummer. Can't switch VCs.");
+		PRINTK("Bummer. Can't switch VCs.");
 		return 1;
 	}
+	orig_kmsg = kmsg_redirect;
+	kmsg_redirect = SUSPEND_CONSOLE;
 #endif
 #endif
 	return 0;
@@ -615,14 +594,12 @@
 
 static int prepare_suspend_processes(void)
 {
-	PRINTS( "Stopping processes\n" );
-	MDELAY(1000);
 	if (freeze_processes()) {
-		PRINTS( "Not all processes stopped!\n" );
+		printk( KERN_ERR "Suspend failed: Not all processes stopped!\n" );
 		thaw_processes();
 		return 1;
 	}
-	do_suspend_sync();
+	sys_sync();
 	return 0;
 }
 
@@ -633,10 +610,10 @@
  */
 static void free_some_memory(void)
 {
-	PRINTS("Freeing memory: ");
+	printk("Freeing memory: ");
 	while (try_to_free_pages(&contig_page_data.node_zones[ZONE_HIGHMEM], GFP_KSWAPD, 0))
 		printk(".");
-	printk("\n");
+	printk("|\n");
 }
 
 /* Make disk drivers accept operations, again */
@@ -669,9 +646,11 @@
 #define RESUME_ALL_PHASES (RESUME_PHASE1 | RESUME_PHASE2)
 static void drivers_resume(int flags)
 {
-	device_resume(RESUME_ENABLE);
-	device_resume(RESUME_RESTORE_STATE);
-  	if(flags & RESUME_PHASE2) {
+	if (flags & RESUME_PHASE1) {
+		device_resume(RESUME_ENABLE);
+		device_resume(RESUME_RESTORE_STATE);
+	}
+  	if (flags & RESUME_PHASE2) {
 		if(pm_suspend_state) {
 			if(pm_send_all(PM_RESUME,(void *)0))
 				printk(KERN_WARNING "Problem while sending resume event\n");
@@ -691,11 +670,11 @@
 	unsigned int nr_needed_pages = 0;
 
 	pagedir_nosave = NULL;
-	PRINTS( "/critical section: Counting pages to copy" );
+	printk( "/critical section: Counting pages to copy" );
 	nr_copy_pages = count_and_copy_data_pages(NULL);
 	nr_needed_pages = nr_copy_pages + PAGES_FOR_IO;
 	
-	PRINTK(" (pages needed: %d+%d=%d free: %d)\n",nr_copy_pages,PAGES_FOR_IO,nr_needed_pages,nr_free_pages());
+	printk(" (pages needed: %d+%d=%d free: %d)\n",nr_copy_pages,PAGES_FOR_IO,nr_needed_pages,nr_free_pages());
 	if(nr_free_pages() < nr_needed_pages) {
 		printk(KERN_CRIT "%sCouldn't get enough free pages, on %d pages short\n",
 		       name_suspend, nr_needed_pages-nr_free_pages());
@@ -724,7 +703,7 @@
 	pagedir_order_check = pagedir_order;
 
 	if (nr_copy_pages != count_and_copy_data_pages(pagedir_nosave))	/* copy */
-		panic("Count and copy returned another count than when counting?\n");
+		BUG();
 
 	/*
 	 * End of critical section. From now on, we can write to memory,
@@ -735,14 +714,12 @@
 	 */
 	drivers_unsuspend();
 	spin_unlock_irq(&suspend_pagedir_lock);
-	PRINTS( "critical section/: done (%d pages copied)\n", nr_copy_pages );
+	printk( "critical section/: done (%d pages copied)\n", nr_copy_pages );
 
 	lock_swapdevices();
 	write_suspend_image();
 	lock_swapdevices();	/* This will unlock ignored swap devices since writing is finished */
 
-	/* Image is saved, call sync & restart machine */
-	PRINTS( "Syncing disks\n" );
 	/* It is important _NOT_ to umount filesystems at this point. We want
 	 * them synced (in case something goes wrong) but we DO not want to mark
 	 * filesystem clean: it is not. (And it does not matter, if we resume
@@ -754,9 +731,9 @@
 void suspend_power_down(void)
 {
 	C_A_D = 0;
-	printk(KERN_EMERG "%sTrying to power down.\n", name_suspend);
+	printk(KERN_EMERG "%s%s Trying to power down.\n", name_suspend, TEST_SWSUSP ? "Disable TEST_SWSUSP. NOT ": "");
 #ifdef CONFIG_VT
-	printk(KERN_EMERG "shift_state: %04x\n", shift_state);
+	PRINTK(KERN_EMERG "shift_state: %04x\n", shift_state);
 	mdelay(1000);
 	if (TEST_SWSUSP ^ (!!(shift_state & (1 << KG_CTRL))))
 		machine_restart(NULL);
@@ -783,7 +760,7 @@
 	mb();
 	spin_lock_irq(&suspend_pagedir_lock);	/* Done to disable interrupts */ 
 
-	printk( "Waiting for DMAs to settle down...\n");
+	PRINTK( "Waiting for DMAs to settle down...\n");
 	mdelay(1000);	/* We do not want some readahead with DMA to corrupt our memory, right?
 			   Do it with disabled interrupts for best effect. That way, if some
 			   driver scheduled DMA, we have good chance for DMA to finish ;-). */
@@ -791,12 +768,10 @@
 
 void do_magic_resume_2(void)
 {
-	if (nr_copy_pages_check != nr_copy_pages)
-		panic("nr_copy_pages changed?!");
-	if (pagedir_order_check != pagedir_order)
-		panic("pagedir_order changed?!");
+	BUG_ON (nr_copy_pages_check != nr_copy_pages);
+	BUG_ON (pagedir_order_check != pagedir_order);
 
-	PRINTR( "Freeing prev allocated pagedir\n" );
+	PRINTK( "Freeing prev allocated pagedir\n" );
 	free_suspend_pagedir((unsigned long) pagedir_save);
 	__flush_tlb_global();		/* Even mappings of "global" things (vmalloc) need to be fixed */
 	drivers_resume(RESUME_ALL_PHASES);
@@ -824,7 +799,7 @@
 	if (!suspend_save_image())
 		suspend_power_down();	/* FIXME: if suspend_power_down is commented out, console is lost after few suspends ?! */
 
-	printk(KERN_WARNING "%sSuspend failed, trying to recover...\n", name_suspend);
+	printk(KERN_EMERG "%sSuspend failed, trying to recover...\n", name_suspend);
 	MDELAY(1000); /* So user can wait and report us messages if armageddon comes :-) */
 
 	barrier();
@@ -837,7 +812,7 @@
 	drivers_resume(RESUME_PHASE1);
 	spin_unlock_irq(&suspend_pagedir_lock);
 	mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
-	printk(KERN_WARNING "%sLeaving do_magic_suspend_2...\n", name_suspend);	
+	PRINTK(KERN_WARNING "%sLeaving do_magic_suspend_2...\n", name_suspend);	
 }
 
 /*
@@ -849,7 +824,7 @@
 {
 	arch_prepare_suspend();
 	if (prepare_suspend_console())
-		printk( "Can't allocate a console... proceeding\n");
+		printk( "%sCan't allocate a console... proceeding\n", name_suspend);
 	if (!prepare_suspend_processes()) {
 		free_some_memory();
 		
@@ -858,11 +833,11 @@
 		 * We sync here -- so you have consistent filesystem state when things go wrong.
 		 * -- so that noone writes to disk after we do atomic copy of data.
 		 */
-		PRINTS("Syncing disks before copy\n");
+		PRINTK("Syncing disks before copy\n");
 		do_suspend_sync();
 		if(drivers_suspend()==0)
 			do_magic(0);			/* This function returns after machine woken up from resume */
-		PRINTR("Restarting processes...\n");
+		PRINTK("Restarting processes...\n");
 		thaw_processes();
 	}
 	software_suspend_enabled = 1;
@@ -950,6 +925,8 @@
 	void **eaten_memory = NULL;
 	void **c = eaten_memory, *m, *f;
 
+	printk("Relocating pagedir");
+
 	if(!does_collide_order(old_pagedir, (unsigned long)old_pagedir, pagedir_order)) {
 		printk("not neccessary\n");
 		return 0;
@@ -979,7 +956,7 @@
 		if (f)
 			free_pages((unsigned long)f, pagedir_order);
 	}
-	printk("okay\n");
+	printk("|\n");
 	return 0;
 }
 
@@ -1011,19 +988,10 @@
 	return 0;
 }
 
-static int bdev_read_page(kdev_t dev, long pos, void *buf)
+static int bdev_read_page(struct block_device *bdev, long pos, void *buf)
 {
 	struct buffer_head *bh;
-	struct block_device *bdev;
-
-	if (pos%PAGE_SIZE) panic("Sorry, dave, I can't let you do that!\n");
-	bdev = bdget(kdev_t_to_nr(dev));
-	blkdev_get(bdev, FMODE_READ, O_RDONLY, BDEV_RAW);
-	if (!bdev) {
-		printk("No block device for %s\n", __bdevname(dev));
-		BUG();
-	}
-	set_blocksize(bdev, PAGE_SIZE);
+	BUG_ON (pos%PAGE_SIZE);
 	bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE);
 	if (!bh || (!bh->b_data)) {
 		return -1;
@@ -1031,44 +999,48 @@
 	memcpy(buf, bh->b_data, PAGE_SIZE);	/* FIXME: may need kmap() */
 	BUG_ON(!buffer_uptodate(bh));
 	brelse(bh);
-	blkdev_put(bdev, BDEV_RAW);
 	return 0;
 } 
 
+static int bdev_write_page(struct block_device *bdev, long pos, void *buf)
+{
+	struct buffer_head *bh;
+#if 0
+	BUG_ON (pos%PAGE_SIZE);
+	bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE);
+	if (!bh || (!bh->b_data)) {
+		return -1;
+	}
+	memcpy(bh->b_data, buf, PAGE_SIZE);	/* FIXME: may need kmap() */
+	BUG_ON(!buffer_uptodate(bh));
+	generic_make_request(WRITE, bh);
+	if (!buffer_uptodate(bh))
+		printk(KERN_CRIT "%sWarning %s: Fixing swap signatures unsuccessful...\n", name_resume, resume_file);
+	wait_on_buffer(bh);
+	brelse(bh);
+	return 0;
+#endif
+	printk(KERN_CRIT "%sWarning %s: Fixing swap signatures unimplemented...\n", name_resume, resume_file);
+}
+
 extern kdev_t __init name_to_kdev_t(const char *line);
 
-static int resume_try_to_read(const char * specialfile, int noresume)
+static int __read_suspend_image(struct block_device *bdev, union diskpage *cur, int noresume)
 {
-	union diskpage *cur;
 	swp_entry_t next;
-	int i, nr_pgdir_pages, error;
-	int blksize = 0;
-
-	resume_device = name_to_kdev_t(specialfile);
-	cur = (void *) get_free_page(GFP_ATOMIC);
-	if (!cur) {
-		printk( "%sNot enough memory?\n", name_resume );
-		error = -ENOMEM;
-		goto resume_read_error;
-	}
-
-	printk("Resuming from device %x\n", kdev_t_to_nr(resume_device));
+	int i, nr_pgdir_pages;
 
-#define READTO(pos, ptr) \
-	if (bdev_read_page(resume_device, pos, ptr)) { error = -EIO; goto resume_read_error; }
 #define PREPARENEXT \
 	{	next = cur->link.next; \
 		next.val = swp_offset(next) * PAGE_SIZE; \
         }
 
-	error = -EIO;
-	READTO(0, cur);
+	if (bdev_read_page(bdev, 0, cur)) return -EIO;
 
 	if ((!memcmp("SWAP-SPACE",cur->swh.magic.magic,10)) ||
 	    (!memcmp("SWAPSPACE2",cur->swh.magic.magic,10))) {
 		printk(KERN_ERR "%sThis is normal swap space\n", name_resume );
-		error = -EINVAL;
-		goto resume_read_error;
+		return -EINVAL;
 	}
 
 	PREPARENEXT; /* We have to read next position before we overwrite it */
@@ -1080,18 +1052,26 @@
 	else {
 		panic("%sUnable to find suspended-data signature (%.10s - misspelled?\n", 
 			name_resume, cur->swh.magic.magic);
+		/* We want to panic even with noresume -- we certainly don't want to add
+		   out signature into your ext2 filesystem ;-) */
 	}
+	if(noresume) {
+		/* We don't do a sanity check here: we want to restore the swap
+		   whatever version of kernel made the suspend image;
+		   We need to write swap, but swap is *not* enabled so
+		   we must write the device directly */
+		printk("%s: Fixing swap signatures %s...\n", name_resume, resume_file);
+		bdev_write_page(bdev, 0, cur);
+	}
+
+	if (prepare_suspend_console())
+		printk("%sCan't allocate a console... proceeding\n", name_resume);
 	printk( "%sSignature found, resuming\n", name_resume );
 	MDELAY(1000);
 
-	READTO(next.val, cur);
-
-	error = -EPERM;
-	if (sanity_check(&cur->sh))
-		goto resume_read_error;
-
-	/* Probably this is the same machine */	
-
+	if (bdev_read_page(bdev, next.val, cur)) return -EIO;
+	if (sanity_check(&cur->sh)) 	/* Is this same machine? */	
+		return -EPERM;
 	PREPARENEXT;
 
 	pagedir_save = cur->sh.suspend_pagedir;
@@ -1099,64 +1079,82 @@
 	nr_pgdir_pages = SUSPEND_PD_PAGES(nr_copy_pages);
 	pagedir_order = get_bitmask_order(nr_pgdir_pages);
 
-	error = -ENOMEM;
-	free_page((unsigned long) cur);
 	pagedir_nosave = (suspend_pagedir_t *)__get_free_pages(GFP_ATOMIC, pagedir_order);
-	if(!pagedir_nosave)
-		goto resume_read_error;
+	if (!pagedir_nosave)
+		return -ENOMEM;
 
-	PRINTR( "%sReading pagedir, ", name_resume );
+	PRINTK( "%sReading pagedir, ", name_resume );
 
 	/* We get pages in reverse order of saving! */
-	error=-EIO;
 	for (i=nr_pgdir_pages-1; i>=0; i--) {
-		if (!next.val)
-			panic( "Preliminary end of suspended data?" );
+		BUG_ON (!next.val);
 		cur = (union diskpage *)((char *) pagedir_nosave)+i;
-		READTO(next.val, cur);
+		if (bdev_read_page(bdev, next.val, cur)) return -EIO;
 		PREPARENEXT;
 	}
-	if (next.val)
-		panic( "Suspended data too long?" );
+	BUG_ON (next.val);
 
-	printk("Relocating pagedir");
-	if((error=relocate_pagedir())!=0)
-		goto resume_read_error;
-	if((error=check_pagedir())!=0)
-		goto resume_read_error;
+	if (relocate_pagedir())
+		return -ENOMEM;
+	if (check_pagedir())
+		return -ENOMEM;
 
-	PRINTK( "image data (%d pages): ", nr_copy_pages );
-	error = -EIO;
+	printk( "Reading image data (%d pages): ", nr_copy_pages );
 	for(i=0; i < nr_copy_pages; i++) {
 		swp_entry_t swap_address = (pagedir_nosave+i)->swap_address;
 		if (!(i%100))
-			PRINTK( "." );
-		next.val = swp_offset(swap_address) * PAGE_SIZE;
+			printk( "." );
 		/* You do not need to check for overlaps...
 		   ... check_pagedir already did this work */
-		READTO(next.val, (char *)((pagedir_nosave+i)->address));
+		if (bdev_read_page(bdev, swp_offset(swap_address) * PAGE_SIZE, (char *)((pagedir_nosave+i)->address)))
+			return -EIO;
 	}
-	PRINTK( " done\n" );
-	error = 0;
+	printk( "|\n" );
+	return 0;
+}
 
-resume_read_error:
+static int read_suspend_image(const char * specialfile, int noresume)
+{
+	union diskpage *cur;
+	unsigned long scratch_page = 0;
+	int error;
+
+	resume_device = name_to_kdev_t(specialfile);
+	scratch_page = get_free_page(GFP_ATOMIC);
+	cur = (void *) scratch_page;
+	if (cur) {
+		struct block_device *bdev;
+		printk("Resuming from device %s\n", __bdevname(resume_device));
+		bdev = bdget(kdev_t_to_nr(resume_device));
+		if (!bdev) {
+			printk("No such block device ?!\n");
+			BUG();
+		}
+		blkdev_get(bdev, FMODE_READ, O_RDONLY, BDEV_RAW);
+		set_blocksize(bdev, PAGE_SIZE);
+		error = __read_suspend_image(bdev, cur, noresume);
+		blkdev_put(bdev, BDEV_RAW);
+	} else error = -ENOMEM;
+
+	if (scratch_page)
+		free_page(scratch_page);
 	switch (error) {
 		case 0:
-			PRINTR("Reading resume file was successful\n");
+			PRINTK("Reading resume file was successful\n");
 			break;
 		case -EINVAL:
 			break;
 		case -EIO:
 			printk( "%sI/O error\n", name_resume);
-			panic("Wanted to resume but it did not work\n");
 			break;
 		case -ENOENT:
 			printk( "%s%s: No such file or directory\n", name_resume, specialfile);
-			panic("Wanted to resume but it did not work\n");
+			break;
+		case -ENOMEM:
+			printk( "%sNot enough memory\n", name_resume);
 			break;
 		default:
 			printk( "%sError %d resuming\n", name_resume, error );
-			panic("Wanted to resume but it did not work\n");
 	}
 	MDELAY(1000);
 	return error;
@@ -1180,7 +1178,8 @@
 
 	printk( "%s", name_resume );
 	if(resume_status == NORESUME) {
-		/* FIXME: Signature should be restored here */
+		if(resume_file[0])
+			read_suspend_image(resume_file, 1);
 		printk( "disabled\n" );
 		return;
 	}
@@ -1190,12 +1189,12 @@
 	console_loglevel = new_loglevel;
 
 	if(!resume_file[0] && resume_status == RESUME_SPECIFIED) {
-		printk( "nowhere to resume from\n" );
+		printk( "suspension device unspecified\n" );
 		return;
 	}
 
 	printk( "resuming from %s\n", resume_file);
-	if(resume_try_to_read(resume_file, 0))
+	if(read_suspend_image(resume_file, 0))
 		goto read_failure;
 	do_magic(1);
 	panic("This never returns");
diff -Nru a/lib/vsprintf.c b/lib/vsprintf.c
--- a/lib/vsprintf.c	Tue Jul 16 16:49:43 2002
+++ b/lib/vsprintf.c	Tue Jul 16 16:49:43 2002
@@ -131,8 +131,8 @@
 {
 	char c,sign,tmp[66];
 	const char *digits;
-	const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-	const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+	static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 	int i;
 
 	digits = (type & LARGE) ? large_digits : small_digits;
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Tue Jul 16 16:49:42 2002
+++ b/mm/filemap.c	Tue Jul 16 16:49:42 2002
@@ -414,7 +414,7 @@
  * free the pages because they're mapped.
  * @mapping: the address_space which pages we want to invalidate
  */
-void invalidate_inode_pages2(struct address_space * mapping)
+void invalidate_inode_pages2(struct address_space *mapping)
 {
 	int unlocked;
 
@@ -1102,6 +1102,7 @@
 	UPDATE_ATIME(inode);
 }
 
+#if 0
 static ssize_t generic_file_direct_IO(int rw, struct file * filp, char * buf, size_t count, loff_t offset)
 {
 	ssize_t retval;
@@ -1182,6 +1183,7 @@
  out:	
 	return retval;
 }
+#endif
 
 int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
 {
@@ -1209,15 +1211,36 @@
  * This is the "read()" routine for all filesystems
  * that can use the page cache directly.
  */
-ssize_t generic_file_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
+ssize_t
+generic_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
 {
 	ssize_t retval;
 
 	if ((ssize_t) count < 0)
 		return -EINVAL;
 
-	if (filp->f_flags & O_DIRECT)
-		goto o_direct;
+	if (filp->f_flags & O_DIRECT) {
+		loff_t pos = *ppos, size;
+		struct address_space *mapping;
+		struct inode *inode;
+
+		mapping = filp->f_dentry->d_inode->i_mapping;
+		inode = mapping->host;
+		retval = 0;
+		if (!count)
+			goto out; /* skip atime */
+		size = inode->i_size;
+		if (pos < size) {
+			if (pos + count > size)
+				count = size - pos;
+			retval = generic_file_direct_IO(READ, inode,
+							buf, pos, count);
+			if (retval > 0)
+				*ppos = pos + retval;
+		}
+		UPDATE_ATIME(filp->f_dentry->d_inode);
+		goto out;
+	}
 
 	retval = -EFAULT;
 	if (access_ok(VERIFY_WRITE, buf, count)) {
@@ -1230,39 +1253,17 @@
 			desc.count = count;
 			desc.buf = buf;
 			desc.error = 0;
-			do_generic_file_read(filp, ppos, &desc, file_read_actor);
-
+			do_generic_file_read(filp,ppos,&desc,file_read_actor);
 			retval = desc.written;
 			if (!retval)
 				retval = desc.error;
 		}
 	}
- out:
+out:
 	return retval;
-
- o_direct:
-	{
-		loff_t pos = *ppos, size;
-		struct address_space *mapping = filp->f_dentry->d_inode->i_mapping;
-		struct inode *inode = mapping->host;
-
-		retval = 0;
-		if (!count)
-			goto out; /* skip atime */
-		size = inode->i_size;
-		if (pos < size) {
-			if (pos + count > size)
-				count = size - pos;
-			retval = generic_file_direct_IO(READ, filp, buf, count, pos);
-			if (retval > 0)
-				*ppos = pos + retval;
-		}
-		UPDATE_ATIME(filp->f_dentry->d_inode);
-		goto out;
-	}
 }
 
-static int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset , unsigned long size)
+static int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
 {
 	ssize_t written;
 	unsigned long count = desc->count;
@@ -1271,22 +1272,8 @@
 	if (size > count)
 		size = count;
 
- 	if (file->f_op->sendpage) {
- 		written = file->f_op->sendpage(file, page, offset,
-					       size, &file->f_pos, size<count);
-	} else {
-		char *kaddr;
-		mm_segment_t old_fs;
-
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-
-		kaddr = kmap(page);
-		written = file->f_op->write(file, kaddr + offset, size, &file->f_pos);
-		kunmap(page);
-
-		set_fs(old_fs);
-	}
+	written = file->f_op->sendpage(file, page, offset,
+				       size, &file->f_pos, size<count);
 	if (written < 0) {
 		desc->error = written;
 		written = 0;
@@ -1331,7 +1318,7 @@
 	if (!(out_file->f_mode & FMODE_WRITE))
 		goto fput_out;
 	retval = -EINVAL;
-	if (!out_file->f_op || !out_file->f_op->write)
+	if (!out_file->f_op || !out_file->f_op->sendpage)
 		goto fput_out;
 	out_inode = out_file->f_dentry->d_inode;
 	retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count);
@@ -2200,8 +2187,8 @@
 	}
 
 	if (unlikely(file->f_flags & O_DIRECT)) {
-		written = generic_file_direct_IO(WRITE, file,
-						(char *) buf, count, pos);
+		written = generic_file_direct_IO(WRITE, inode,
+						(char *)buf, pos, count);
 		if (written > 0) {
 			loff_t end = pos + written;
 			if (end > inode->i_size && !S_ISBLK(inode->i_mode)) {
@@ -2209,7 +2196,8 @@
 				mark_inode_dirty(inode);
 			}
 			*ppos = end;
-			invalidate_inode_pages2(mapping);
+			if (mapping->nrpages)
+				invalidate_inode_pages2(mapping);
 		}
 		/*
 		 * Sync the fs metadata but not the minor inode changes and
diff -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c	Tue Jul 16 16:49:41 2002
+++ b/mm/mmap.c	Tue Jul 16 16:49:41 2002
@@ -1121,7 +1121,6 @@
 		unsigned long end = mpnt->vm_end;
 
 		mm->map_count--;
-		remove_shared_vm_struct(mpnt);
 		unmap_page_range(tlb, mpnt, start, end);
 		mpnt = mpnt->vm_next;
 	}
@@ -1148,6 +1147,7 @@
 	 */
 	while (mpnt) {
 		struct vm_area_struct * next = mpnt->vm_next;
+		remove_shared_vm_struct(mpnt);
 		if (mpnt->vm_ops) {
 			if (mpnt->vm_ops->close)
 				mpnt->vm_ops->close(mpnt);
diff -Nru a/mm/mprotect.c b/mm/mprotect.c
--- a/mm/mprotect.c	Tue Jul 16 16:49:42 2002
+++ b/mm/mprotect.c	Tue Jul 16 16:49:42 2002
@@ -290,7 +290,7 @@
 	down_write(&current->mm->mmap_sem);
 
 	vma = find_vma_prev(current->mm, start, &prev);
-	error = -EFAULT;
+	error = -ENOMEM;
 	if (!vma || vma->vm_start > start)
 		goto out;
 
@@ -323,7 +323,7 @@
 		nstart = tmp;
 		vma = next;
 		if (!vma || vma->vm_start != nstart) {
-			error = -EFAULT;
+			error = -ENOMEM;
 			goto out;
 		}
 	}
diff -Nru a/mm/msync.c b/mm/msync.c
--- a/mm/msync.c	Tue Jul 16 16:49:42 2002
+++ b/mm/msync.c	Tue Jul 16 16:49:42 2002
@@ -169,16 +169,17 @@
 {
 	unsigned long end;
 	struct vm_area_struct * vma;
-	int unmapped_error, error = -ENOMEM;
+	int unmapped_error, error = -EINVAL;
 
 	down_read(&current->mm->mmap_sem);
+	if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
+		goto out;
 	if (start & ~PAGE_MASK)
 		goto out;
+	error = -ENOMEM;
 	len = (len + ~PAGE_MASK) & PAGE_MASK;
 	end = start + len;
 	if (end < start)
-		goto out;
-	if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
 		goto out;
 	error = 0;
 	if (end == start)
diff -Nru a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c	Tue Jul 16 16:49:43 2002
+++ b/mm/slab.c	Tue Jul 16 16:49:43 2002
@@ -2019,7 +2019,7 @@
 	return 0;
 }
 
-/**
+/*
  * slabinfo_op - iterator that generates /proc/slabinfo
  *
  * Output layout:
diff -Nru a/net/core/dst.c b/net/core/dst.c
--- a/net/core/dst.c	Tue Jul 16 16:49:43 2002
+++ b/net/core/dst.c	Tue Jul 16 16:49:43 2002
@@ -29,7 +29,9 @@
  * 4) All operations modify state, so a spinlock is used.
  */
 static struct dst_entry 	*dst_garbage_list;
+#if RT_CACHE_DEBUG >= 2 
 static atomic_t			 dst_total = ATOMIC_INIT(0);
+#endif
 static spinlock_t		 dst_lock = SPIN_LOCK_UNLOCKED;
 
 static unsigned long dst_gc_timer_expires;
@@ -108,7 +110,9 @@
 	dst->lastuse = jiffies;
 	dst->input = dst_discard;
 	dst->output = dst_blackhole;
+#if RT_CACHE_DEBUG >= 2 
 	atomic_inc(&dst_total);
+#endif
 	atomic_inc(&ops->entries);
 	return dst;
 }
@@ -158,7 +162,9 @@
 		dst->ops->destroy(dst);
 	if (dst->dev)
 		dev_put(dst->dev);
+#if RT_CACHE_DEBUG >= 2 
 	atomic_dec(&dst_total);
+#endif
 	kmem_cache_free(dst->ops->kmem_cachep, dst);
 }
 
diff -Nru a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
--- a/net/ipv4/netfilter/ip_tables.c	Tue Jul 16 16:49:42 2002
+++ b/net/ipv4/netfilter/ip_tables.c	Tue Jul 16 16:49:42 2002
@@ -9,6 +9,7 @@
  * 	  a table
  */
 #include <linux/config.h>
+#include <linux/cache.h>
 #include <linux/skbuff.h>
 #include <linux/kmod.h>
 #include <linux/vmalloc.h>
@@ -97,7 +98,7 @@
 	unsigned int underflow[NF_IP_NUMHOOKS];
 
 	/* ipt_entry tables: one per CPU */
-	char entries[0] __attribute__((aligned(SMP_CACHE_BYTES)));
+	char entries[0] ____cacheline_aligned;
 };
 
 static LIST_HEAD(ipt_target);
diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c
--- a/net/ipv4/tcp.c	Tue Jul 16 16:49:42 2002
+++ b/net/ipv4/tcp.c	Tue Jul 16 16:49:42 2002
@@ -1519,7 +1519,7 @@
 			break;
 
 		/* We need to check signals first, to get correct SIGURG
-		 * handling. FIXME: Need to check this doesnt impact 1003.1g
+		 * handling. FIXME: Need to check this doesn't impact 1003.1g
 		 * and move it down to the bottom of the loop
 		 */
 		if (signal_pending(current)) {
diff -Nru a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
--- a/net/netlink/af_netlink.c	Tue Jul 16 16:49:42 2002
+++ b/net/netlink/af_netlink.c	Tue Jul 16 16:49:42 2002
@@ -41,6 +41,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
+#include <linux/notifier.h>
 #include <net/sock.h>
 #include <net/scm.h>
 
@@ -81,6 +82,8 @@
 static rwlock_t nl_table_lock = RW_LOCK_UNLOCKED;
 static atomic_t nl_table_users = ATOMIC_INIT(0);
 
+static struct notifier_block *netlink_chain;
+
 static void netlink_sock_destruct(struct sock *sk)
 {
 	skb_queue_purge(&sk->receive_queue);
@@ -276,6 +279,12 @@
 
 	skb_queue_purge(&sk->write_queue);
 
+	if (nlk->pid && !nlk->groups) {
+		struct netlink_notify n = { protocol:sk->protocol,
+		                            pid:nlk->pid };
+		notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n);
+	}	
+	
 	sock_put(sk);
 	return 0;
 }
@@ -967,6 +976,16 @@
 }
 #endif
 
+int netlink_register_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_register(&netlink_chain, nb);
+}
+
+int netlink_unregister_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_unregister(&netlink_chain, nb);
+}
+                
 struct proto_ops netlink_ops = {
 	family:		PF_NETLINK,
 
diff -Nru a/net/netsyms.c b/net/netsyms.c
--- a/net/netsyms.c	Tue Jul 16 16:49:42 2002
+++ b/net/netsyms.c	Tue Jul 16 16:49:42 2002
@@ -402,6 +402,8 @@
 EXPORT_SYMBOL(netlink_kernel_create);
 EXPORT_SYMBOL(netlink_dump_start);
 EXPORT_SYMBOL(netlink_ack);
+EXPORT_SYMBOL(netlink_register_notifier);
+EXPORT_SYMBOL(netlink_unregister_notifier);
 #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
 EXPORT_SYMBOL(netlink_attach);
 EXPORT_SYMBOL(netlink_detach);
diff -Nru a/net/sunrpc/Makefile b/net/sunrpc/Makefile
--- a/net/sunrpc/Makefile	Tue Jul 16 16:49:41 2002
+++ b/net/sunrpc/Makefile	Tue Jul 16 16:49:41 2002
@@ -9,7 +9,8 @@
 sunrpc-y := clnt.o xprt.o sched.o \
 	    auth.o auth_null.o auth_unix.o \
 	    svc.o svcsock.o svcauth.o \
-	    pmap_clnt.o xdr.o sunrpc_syms.o
+	    pmap_clnt.o timer.o xdr.o \
+	    sunrpc_syms.o
 sunrpc-$(CONFIG_PROC_FS) += stats.o
 sunrpc-$(CONFIG_SYSCTL) += sysctl.o
 sunrpc-objs := $(sunrpc-y)
diff -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
--- a/net/sunrpc/clnt.c	Tue Jul 16 16:49:42 2002
+++ b/net/sunrpc/clnt.c	Tue Jul 16 16:49:42 2002
@@ -104,6 +104,8 @@
 	if (!clnt->cl_port)
 		clnt->cl_autobind = 1;
 
+	rpc_init_rtt(&clnt->cl_rtt, xprt->timeout.to_initval);
+
 	if (!rpcauth_create(flavor, clnt))
 		goto out_no_auth;
 
@@ -595,13 +597,16 @@
 	dprintk("RPC: %4d call_status (status %d)\n", 
 				task->tk_pid, task->tk_status);
 
+	req = task->tk_rqstp;
+	if (req->rq_received != 0)
+		status = req->rq_received;
 	if (status >= 0) {
+		req->rq_received = 0;
 		task->tk_action = call_decode;
 		return;
 	}
 
 	task->tk_status = 0;
-	req = task->tk_rqstp;
 	switch(status) {
 	case -ETIMEDOUT:
 		task->tk_action = call_timeout;
@@ -666,7 +671,7 @@
 		rpc_exit(task, -EIO);
 		return;
 	}
-	if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN)) {
+	if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN) && rpc_ntimeo(&clnt->cl_rtt) > 7) {
 		task->tk_flags |= RPC_CALL_MAJORSEEN;
 		if (req)
 			printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
diff -Nru a/net/sunrpc/sched.c b/net/sunrpc/sched.c
--- a/net/sunrpc/sched.c	Tue Jul 16 16:49:42 2002
+++ b/net/sunrpc/sched.c	Tue Jul 16 16:49:42 2002
@@ -73,7 +73,7 @@
  * Spinlock for wait queues. Access to the latter also has to be
  * interrupt-safe in order to allow timers to wake up sleeping tasks.
  */
-spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED;
 /*
  * Spinlock for other critical sections of code.
  */
@@ -157,7 +157,7 @@
 void rpc_add_timer(struct rpc_task *task, rpc_action timer)
 {
 	spin_lock_bh(&rpc_queue_lock);
-	if (!(RPC_IS_RUNNING(task) || task->tk_wakeup))
+	if (!RPC_IS_RUNNING(task))
 		__rpc_add_timer(task, timer);
 	spin_unlock_bh(&rpc_queue_lock);
 }
@@ -358,27 +358,10 @@
 	spin_unlock_bh(&rpc_queue_lock);
 }
 
-void
-rpc_sleep_locked(struct rpc_wait_queue *q, struct rpc_task *task,
-		 rpc_action action, rpc_action timer)
-{
-	/*
-	 * Protect the queue operations.
-	 */
-	spin_lock_bh(&rpc_queue_lock);
-	__rpc_sleep_on(q, task, action, timer);
-	__rpc_lock_task(task);
-	spin_unlock_bh(&rpc_queue_lock);
-}
-
 /**
  * __rpc_wake_up_task - wake up a single rpc_task
  * @task: task to be woken up
  *
- * If the task is locked, it is merely removed from the queue, and
- * 'task->tk_wakeup' is set. rpc_unlock_task() will then ensure
- * that it is woken up as soon as the lock count goes to zero.
- *
  * Caller must hold rpc_queue_lock
  */
 static void
@@ -407,14 +390,6 @@
 	if (task->tk_rpcwait != &schedq)
 		__rpc_remove_wait_queue(task);
 
-	/* If the task has been locked, then set tk_wakeup so that
-	 * rpc_unlock_task() wakes us up... */
-	if (task->tk_lock) {
-		task->tk_wakeup = 1;
-		return;
-	} else
-		task->tk_wakeup = 0;
-
 	rpc_make_runnable(task);
 
 	dprintk("RPC:      __rpc_wake_up_task done\n");
@@ -502,30 +477,6 @@
 }
 
 /*
- * Lock down a sleeping task to prevent it from waking up
- * and disappearing from beneath us.
- *
- * This function should always be called with the
- * rpc_queue_lock held.
- */
-int
-__rpc_lock_task(struct rpc_task *task)
-{
-	if (!RPC_IS_RUNNING(task))
-		return ++task->tk_lock;
-	return 0;
-}
-
-void
-rpc_unlock_task(struct rpc_task *task)
-{
-	spin_lock_bh(&rpc_queue_lock);
-	if (task->tk_lock && !--task->tk_lock && task->tk_wakeup)
-		__rpc_wake_up_task(task);
-	spin_unlock_bh(&rpc_queue_lock);
-}
-
-/*
  * Run a task at a later time
  */
 static void	__rpc_atrun(struct rpc_task *);
@@ -707,15 +658,6 @@
 		spin_lock_bh(&rpc_queue_lock);
 
 		task_for_first(task, &schedq.tasks) {
-			if (task->tk_lock) {
-				spin_unlock_bh(&rpc_queue_lock);
-				printk(KERN_ERR "RPC: Locked task was scheduled !!!!\n");
-#ifdef RPC_DEBUG			
-				rpc_debug = ~0;
-				rpc_show_tasks();
-#endif			
-				break;
-			}
 			__rpc_remove_wait_queue(task);
 			spin_unlock_bh(&rpc_queue_lock);
 
diff -Nru a/net/sunrpc/timer.c b/net/sunrpc/timer.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/sunrpc/timer.c	Tue Jul 16 16:49:43 2002
@@ -0,0 +1,74 @@
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/unistd.h>
+
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprt.h>
+#include <linux/sunrpc/timer.h>
+
+#define RPC_RTO_MAX (60*HZ)
+#define RPC_RTO_INIT (HZ/5)
+#define RPC_RTO_MIN (2)
+
+void
+rpc_init_rtt(struct rpc_rtt *rt, long timeo)
+{
+	long t = (timeo - RPC_RTO_INIT) << 3;
+	int i;
+	rt->timeo = timeo;
+	if (t < 0)
+		t = 0;
+	for (i = 0; i < 5; i++) {
+		rt->srtt[i] = t;
+		rt->sdrtt[i] = RPC_RTO_INIT;
+	}
+	atomic_set(&rt->ntimeouts, 0);
+}
+
+void
+rpc_update_rtt(struct rpc_rtt *rt, int timer, long m)
+{
+	long *srtt, *sdrtt;
+
+	if (timer-- == 0)
+		return;
+
+	if (m == 0)
+		m = 1;
+	srtt = &rt->srtt[timer];
+	m -= *srtt >> 3;
+	*srtt += m;
+	if (m < 0)
+		m = -m;
+	sdrtt = &rt->sdrtt[timer];
+	m -= *sdrtt >> 2;
+	*sdrtt += m;
+	/* Set lower bound on the variance */
+	if (*sdrtt < RPC_RTO_MIN)
+		*sdrtt = RPC_RTO_MIN;
+}
+
+/*
+ * Estimate rto for an nfs rpc sent via. an unreliable datagram.
+ * Use the mean and mean deviation of rtt for the appropriate type of rpc
+ * for the frequent rpcs and a default for the others.
+ * The justification for doing "other" this way is that these rpcs
+ * happen so infrequently that timer est. would probably be stale.
+ * Also, since many of these rpcs are
+ * non-idempotent, a conservative timeout is desired.
+ * getattr, lookup,
+ * read, write, commit     - A+4D
+ * other                   - timeo
+ */
+
+long
+rpc_calc_rto(struct rpc_rtt *rt, int timer)
+{
+	long res;
+	if (timer-- == 0)
+		return rt->timeo;
+	res = (rt->srtt[timer] >> 3) + rt->sdrtt[timer];
+	if (res > RPC_RTO_MAX)
+		res = RPC_RTO_MAX;
+	return res;
+}
diff -Nru a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
--- a/net/sunrpc/xdr.c	Tue Jul 16 16:49:43 2002
+++ b/net/sunrpc/xdr.c	Tue Jul 16 16:49:43 2002
@@ -242,11 +242,11 @@
 		return;
 	if (base || xdr->page_base) {
 		pglen -= base;
+		base  += xdr->page_base;
 		ppage += base >> PAGE_CACHE_SHIFT;
 	}
 	for (;;) {
 		flush_dcache_page(*ppage);
-		flush_page_to_ram(*ppage);
 		kunmap(*ppage);
 		if (pglen <= PAGE_CACHE_SIZE)
 			break;
diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
--- a/net/sunrpc/xprt.c	Tue Jul 16 16:49:41 2002
+++ b/net/sunrpc/xprt.c	Tue Jul 16 16:49:41 2002
@@ -68,8 +68,6 @@
 
 #include <asm/uaccess.h>
 
-extern spinlock_t rpc_queue_lock;
-
 /*
  * Local variables
  */
@@ -79,6 +77,8 @@
 # define RPCDBG_FACILITY	RPCDBG_XPRT
 #endif
 
+#define XPRT_MAX_BACKOFF	(8)
+
 /*
  * Local functions
  */
@@ -89,6 +89,7 @@
 static void	xprt_reconn_status(struct rpc_task *task);
 static struct socket *xprt_create_socket(int, struct rpc_timeout *);
 static int	xprt_bind_socket(struct rpc_xprt *, struct socket *);
+static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
 
 #ifdef RPC_DEBUG_DATA
 /*
@@ -140,31 +141,60 @@
 {
 	int retval;
 	spin_lock_bh(&xprt->sock_lock);
-	if (!xprt->snd_task)
-		xprt->snd_task = task;
-	else if (xprt->snd_task != task) {
+	if (!xprt->snd_task) {
+		if (xprt->nocong || __xprt_get_cong(xprt, task))
+			xprt->snd_task = task;
+	}
+	if (xprt->snd_task != task) {
 		dprintk("RPC: %4d TCP write queue full (task %d)\n",
 			task->tk_pid, xprt->snd_task->tk_pid);
 		task->tk_timeout = 0;
 		task->tk_status = -EAGAIN;
-		rpc_sleep_on(&xprt->sending, task, NULL, NULL);
+		if (task->tk_rqstp->rq_nresend)
+			rpc_sleep_on(&xprt->resend, task, NULL, NULL);
+		else
+			rpc_sleep_on(&xprt->sending, task, NULL, NULL);
 	}
 	retval = xprt->snd_task == task;
 	spin_unlock_bh(&xprt->sock_lock);
 	return retval;
 }
 
+static void
+__xprt_lock_write_next(struct rpc_xprt *xprt)
+{
+	struct rpc_task *task;
+
+	if (xprt->snd_task)
+		return;
+	if (!xprt->nocong && RPCXPRT_CONGESTED(xprt))
+		return;
+	task = rpc_wake_up_next(&xprt->resend);
+	if (!task) {
+		task = rpc_wake_up_next(&xprt->sending);
+		if (!task)
+			return;
+	}
+	if (xprt->nocong || __xprt_get_cong(xprt, task))
+		xprt->snd_task = task;
+}
+
 /*
  * Releases the socket for use by other requests.
  */
 static void
+__xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
+{
+	if (xprt->snd_task == task)
+		xprt->snd_task = NULL;
+	__xprt_lock_write_next(xprt);
+}
+
+static inline void
 xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
 {
 	spin_lock_bh(&xprt->sock_lock);
-	if (xprt->snd_task == task) {
-		xprt->snd_task = NULL;
-		rpc_wake_up_next(&xprt->sending);
-	}
+	__xprt_release_write(xprt, task);
 	spin_unlock_bh(&xprt->sock_lock);
 }
 
@@ -236,6 +266,40 @@
 }
 
 /*
+ * Van Jacobson congestion avoidance. Check if the congestion window
+ * overflowed. Put the task to sleep if this is the case.
+ */
+static int
+__xprt_get_cong(struct rpc_xprt *xprt, struct rpc_task *task)
+{
+	struct rpc_rqst *req = task->tk_rqstp;
+
+	if (req->rq_cong)
+		return 1;
+	dprintk("RPC: %4d xprt_cwnd_limited cong = %ld cwnd = %ld\n",
+			task->tk_pid, xprt->cong, xprt->cwnd);
+	if (RPCXPRT_CONGESTED(xprt))
+		return 0;
+	req->rq_cong = 1;
+	xprt->cong += RPC_CWNDSCALE;
+	return 1;
+}
+
+/*
+ * Adjust the congestion window, and wake up the next task
+ * that has been sleeping due to congestion
+ */
+static void
+__xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
+{
+	if (!req->rq_cong)
+		return;
+	req->rq_cong = 0;
+	xprt->cong -= RPC_CWNDSCALE;
+	__xprt_lock_write_next(xprt);
+}
+
+/*
  * Adjust RPC congestion window
  * We use a time-smoothed congestion estimator to avoid heavy oscillation.
  */
@@ -244,40 +308,22 @@
 {
 	unsigned long	cwnd;
 
-	if (xprt->nocong)
-		return;
-	/*
-	 * Note: we're in a BH context
-	 */
-	spin_lock(&xprt->xprt_lock);
 	cwnd = xprt->cwnd;
-	if (result >= 0) {
-		if (xprt->cong < cwnd || time_before(jiffies, xprt->congtime))
-			goto out;
+	if (result >= 0 && xprt->cong <= cwnd) {
 		/* The (cwnd >> 1) term makes sure
 		 * the result gets rounded properly. */
 		cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd;
 		if (cwnd > RPC_MAXCWND)
 			cwnd = RPC_MAXCWND;
-		else
-			pprintk("RPC: %lu %ld cwnd\n", jiffies, cwnd);
-		xprt->congtime = jiffies + ((cwnd * HZ) << 2) / RPC_CWNDSCALE;
-		dprintk("RPC:      cong %08lx, cwnd was %08lx, now %08lx, "
-			"time %ld ms\n", xprt->cong, xprt->cwnd, cwnd,
-			(xprt->congtime-jiffies)*1000/HZ);
+		__xprt_lock_write_next(xprt);
 	} else if (result == -ETIMEDOUT) {
-		if ((cwnd >>= 1) < RPC_CWNDSCALE)
+		cwnd >>= 1;
+		if (cwnd < RPC_CWNDSCALE)
 			cwnd = RPC_CWNDSCALE;
-		xprt->congtime = jiffies + ((cwnd * HZ) << 3) / RPC_CWNDSCALE;
-		dprintk("RPC:      cong %ld, cwnd was %ld, now %ld, "
-			"time %ld ms\n", xprt->cong, xprt->cwnd, cwnd,
-			(xprt->congtime-jiffies)*1000/HZ);
-		pprintk("RPC: %lu %ld cwnd\n", jiffies, cwnd);
 	}
-
+	dprintk("RPC:      cong %ld, cwnd was %ld, now %ld\n",
+			xprt->cong, xprt->cwnd, cwnd);
 	xprt->cwnd = cwnd;
- out:
-	spin_unlock(&xprt->xprt_lock);
 }
 
 /*
@@ -337,7 +383,7 @@
 
 	sock_release(sock);
 	/*
-	 *	TCP doesnt require the rpciod now - other things may
+	 *	TCP doesn't require the rpciod now - other things may
 	 *	but rpciod handles that not us.
 	 */
 	if(xprt->stream)
@@ -429,7 +475,7 @@
 			/* if the socket is already closing, delay 5 secs */
 			if ((1<<inet->state) & ~(TCP_SYN_SENT|TCP_SYN_RECV))
 				task->tk_timeout = 5*HZ;
-			rpc_sleep_on(&xprt->sending, task, xprt_reconn_status, NULL);
+			rpc_sleep_on(&xprt->pending, task, xprt_reconn_status, NULL);
 			release_sock(inet);
 			return;
 		}
@@ -465,20 +511,16 @@
 static inline struct rpc_rqst *
 xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
 {
-	struct rpc_rqst	*req;
-	struct list_head *le;
-	struct rpc_task *task;
+	struct list_head *pos;
+	struct rpc_rqst	*req = NULL;
 
-	spin_lock_bh(&rpc_queue_lock);
-	task_for_each(task, le, &xprt->pending.tasks)
-		if ((req = task->tk_rqstp) && req->rq_xid == xid)
-			goto out;
-	dprintk("RPC:      unknown XID %08x in reply.\n", xid);
-	req = NULL;
- out:
-	if (req && !__rpc_lock_task(req->rq_task))
-		req = NULL;
-	spin_unlock_bh(&rpc_queue_lock);
+	list_for_each(pos, &xprt->recv) {
+		struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list);
+		if (entry->rq_xid == xid) {
+			req = entry;
+			break;
+		}
+	}
 	return req;
 }
 
@@ -486,13 +528,23 @@
  * Complete reply received.
  * The TCP code relies on us to remove the request from xprt->pending.
  */
-static inline void
+static void
 xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied)
 {
 	struct rpc_task	*task = req->rq_task;
+	struct rpc_clnt *clnt = task->tk_client;
 
 	/* Adjust congestion window */
-	xprt_adjust_cwnd(xprt, copied);
+	if (!xprt->nocong) {
+		xprt_adjust_cwnd(xprt, copied);
+		__xprt_put_cong(xprt, req);
+	       	if (!req->rq_nresend) {
+			int timer = rpcproc_timer(clnt, task->tk_msg.rpc_proc);
+			if (timer)
+				rpc_update_rtt(&clnt->cl_rtt, timer, (long)jiffies - req->rq_xtime);
+		}
+		rpc_clear_timeo(&clnt->cl_rtt);
+	}
 
 #ifdef RPC_PROFILE
 	/* Profile only reads for now */
@@ -515,7 +567,7 @@
 
 	dprintk("RPC: %4d has input (%d bytes)\n", task->tk_pid, copied);
 	task->tk_status = copied;
-	req->rq_received = 1;
+	req->rq_received = copied;
 
 	/* ... and wake up the process. */
 	rpc_wake_up_task(task);
@@ -613,9 +665,10 @@
 	}
 
 	/* Look up and lock the request corresponding to the given XID */
+	spin_lock(&xprt->sock_lock);
 	rovr = xprt_lookup_rqst(xprt, *(u32 *) (skb->h.raw + sizeof(struct udphdr)));
 	if (!rovr)
-		goto dropit;
+		goto out_unlock;
 	task = rovr->rq_task;
 
 	dprintk("RPC: %4d received reply\n", task->tk_pid);
@@ -635,8 +688,7 @@
 	xprt_complete_rqst(xprt, rovr, copied);
 
  out_unlock:
-	rpc_unlock_task(task);
-
+	spin_unlock(&xprt->sock_lock);
  dropit:
 	skb_free_datagram(sk, skb);
  out:
@@ -738,11 +790,13 @@
 	size_t len;
 
 	/* Find and lock the request corresponding to this xid */
+	spin_lock(&xprt->sock_lock);
 	req = xprt_lookup_rqst(xprt, xprt->tcp_xid);
 	if (!req) {
 		xprt->tcp_flags &= ~XPRT_COPY_DATA;
 		dprintk("RPC:      XID %08x request not found!\n",
 				xprt->tcp_xid);
+		spin_unlock(&xprt->sock_lock);
 		return;
 	}
 
@@ -776,7 +830,7 @@
 				req->rq_task->tk_pid);
 		xprt_complete_rqst(xprt, req, xprt->tcp_copied);
 	}
-	rpc_unlock_task(req->rq_task); 
+	spin_unlock(&xprt->sock_lock);
 	tcp_check_recm(xprt);
 }
 
@@ -876,7 +930,7 @@
 		xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID;
 
 		spin_lock(&xprt->sock_lock);
-		if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
+		if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending)
 			rpc_wake_up_task(xprt->snd_task);
 		spin_unlock(&xprt->sock_lock);
 		break;
@@ -913,7 +967,7 @@
 
 	if (!xprt_test_and_set_wspace(xprt)) {
 		spin_lock(&xprt->sock_lock);
-		if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
+		if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending)
 			rpc_wake_up_task(xprt->snd_task);
 		spin_unlock(&xprt->sock_lock);
 	}
@@ -927,22 +981,53 @@
 }
 
 /*
+ * Exponential backoff for UDP retries
+ */
+static inline int
+xprt_expbackoff(struct rpc_task *task, struct rpc_rqst *req)
+{
+	int backoff;
+
+	req->rq_ntimeo++;
+	backoff = min(rpc_ntimeo(&task->tk_client->cl_rtt), XPRT_MAX_BACKOFF);
+	if (req->rq_ntimeo < (1 << backoff))
+		return 1;
+	return 0;
+}
+
+/*
  * RPC receive timeout handler.
  */
 static void
 xprt_timer(struct rpc_task *task)
 {
 	struct rpc_rqst	*req = task->tk_rqstp;
+	struct rpc_xprt *xprt = req->rq_xprt;
+
+	spin_lock(&xprt->sock_lock);
+	if (req->rq_received)
+		goto out;
 
-	if (req)
-		xprt_adjust_cwnd(task->tk_xprt, -ETIMEDOUT);
+	if (!xprt->nocong) {
+		if (xprt_expbackoff(task, req)) {
+			rpc_add_timer(task, xprt_timer);
+			goto out_unlock;
+		}
+		rpc_inc_timeo(&task->tk_client->cl_rtt);
+		xprt_adjust_cwnd(req->rq_xprt, -ETIMEDOUT);
+		__xprt_put_cong(xprt, req);
+	}
+	req->rq_nresend++;
 
 	dprintk("RPC: %4d xprt_timer (%s request)\n",
 		task->tk_pid, req ? "pending" : "backlogged");
 
 	task->tk_status  = -ETIMEDOUT;
+out:
 	task->tk_timeout = 0;
 	rpc_wake_up_task(task);
+out_unlock:
+	spin_unlock(&xprt->sock_lock);
 }
 
 /*
@@ -981,34 +1066,25 @@
 	if (!xprt_lock_write(xprt, task))
 		return;
 
-#ifdef RPC_PROFILE
-	req->rq_xtime = jiffies;
-#endif
 	do_xprt_transmit(task);
 }
 
 static void
 do_xprt_transmit(struct rpc_task *task)
 {
+	struct rpc_clnt *clnt = task->tk_client;
 	struct rpc_rqst	*req = task->tk_rqstp;
 	struct rpc_xprt	*xprt = req->rq_xprt;
 	int status, retry = 0;
 
 
-	/* For fast networks/servers we have to put the request on
-	 * the pending list now:
-	 * Note that we don't want the task timing out during the
-	 * call to xprt_sendmsg(), so we initially disable the timeout,
-	 * and then reset it later...
-	 */
-	xprt_receive(task);
-
 	/* Continue transmitting the packet/record. We must be careful
 	 * to cope with writespace callbacks arriving _after_ we have
 	 * called xprt_sendmsg().
 	 */
 	while (1) {
 		xprt_clear_wspace(xprt);
+		req->rq_xtime = jiffies;
 		status = xprt_sendmsg(xprt, req);
 
 		if (status < 0)
@@ -1034,15 +1110,11 @@
 		if (retry++ > 50)
 			break;
 	}
-	rpc_unlock_task(task);
 
 	/* Note: at this point, task->tk_sleeping has not yet been set,
 	 *	 hence there is no danger of the waking up task being put on
 	 *	 schedq, and being picked up by a parallel run of rpciod().
 	 */
-	rpc_wake_up_task(task);
-	if (!RPC_IS_RUNNING(task))
-		goto out_release;
 	if (req->rq_received)
 		goto out_release;
 
@@ -1054,7 +1126,7 @@
 		spin_lock_bh(&xprt->sock_lock);
 		if (!xprt_wspace(xprt)) {
 			task->tk_timeout = req->rq_timeout.to_current;
-			rpc_sleep_on(&xprt->sending, task, NULL, NULL);
+			rpc_sleep_on(&xprt->pending, task, NULL, NULL);
 		}
 		spin_unlock_bh(&xprt->sock_lock);
 		return;
@@ -1070,35 +1142,29 @@
 		if (xprt->stream)
 			xprt_disconnect(xprt);
 		req->rq_bytes_sent = 0;
-		goto out_release;
 	}
-
+ out_release:
+	spin_lock_bh(&xprt->sock_lock);
+	__xprt_release_write(xprt, task);
+	__xprt_put_cong(xprt, req);
+	spin_unlock_bh(&xprt->sock_lock);
+	return;
  out_receive:
 	dprintk("RPC: %4d xmit complete\n", task->tk_pid);
 	/* Set the task's receive timeout value */
-	task->tk_timeout = req->rq_timeout.to_current;
-	rpc_add_timer(task, xprt_timer);
-	rpc_unlock_task(task);
- out_release:
-	xprt_release_write(xprt, task);
-}
-
-/*
- * Queue the task for a reply to our call.
- * When the callback is invoked, the congestion window should have
- * been updated already.
- */
-void
-xprt_receive(struct rpc_task *task)
-{
-	struct rpc_rqst	*req = task->tk_rqstp;
-	struct rpc_xprt	*xprt = req->rq_xprt;
-
-	dprintk("RPC: %4d xprt_receive\n", task->tk_pid);
-
-	req->rq_received = 0;
-	task->tk_timeout = 0;
-	rpc_sleep_locked(&xprt->pending, task, NULL, NULL);
+	if (!xprt->nocong) {
+		task->tk_timeout = rpc_calc_rto(&clnt->cl_rtt,
+				rpcproc_timer(clnt, task->tk_msg.rpc_proc));
+		req->rq_ntimeo = 0;
+		if (task->tk_timeout > req->rq_timeout.to_maxval)
+			task->tk_timeout = req->rq_timeout.to_maxval;
+	} else
+		task->tk_timeout = req->rq_timeout.to_current;
+	spin_lock_bh(&xprt->sock_lock);
+	if (!req->rq_received)
+		rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
+	__xprt_release_write(xprt, task);
+	spin_unlock_bh(&xprt->sock_lock);
 }
 
 /*
@@ -1113,9 +1179,7 @@
 	if (task->tk_rqstp)
 		return 0;
 
-	dprintk("RPC: %4d xprt_reserve cong = %ld cwnd = %ld\n",
-				task->tk_pid, xprt->cong, xprt->cwnd);
-	spin_lock_bh(&xprt->xprt_lock);
+	spin_lock(&xprt->xprt_lock);
 	xprt_reserve_status(task);
 	if (task->tk_rqstp) {
 		task->tk_timeout = 0;
@@ -1126,7 +1190,7 @@
 		task->tk_status = -EAGAIN;
 		rpc_sleep_on(&xprt->backlog, task, NULL, NULL);
 	}
-	spin_unlock_bh(&xprt->xprt_lock);
+	spin_unlock(&xprt->xprt_lock);
 	dprintk("RPC: %4d xprt_reserve returns %d\n",
 				task->tk_pid, task->tk_status);
 	return task->tk_status;
@@ -1148,18 +1212,13 @@
 	} else if (task->tk_rqstp) {
 		/* We've already been given a request slot: NOP */
 	} else {
-		if (RPCXPRT_CONGESTED(xprt) || !(req = xprt->free))
+		if (!(req = xprt->free))
 			goto out_nofree;
-		/* OK: There's room for us. Grab a free slot and bump
-		 * congestion value */
+		/* OK: There's room for us. Grab a free slot */
 		xprt->free     = req->rq_next;
 		req->rq_next   = NULL;
-		xprt->cong    += RPC_CWNDSCALE;
 		task->tk_rqstp = req;
 		xprt_request_init(task, xprt);
-
-		if (xprt->free)
-			xprt_clear_backlog(xprt);
 	}
 
 	return;
@@ -1188,6 +1247,10 @@
 	req->rq_xid     = xid++;
 	if (!xid)
 		xid++;
+	INIT_LIST_HEAD(&req->rq_list);
+	spin_lock_bh(&xprt->sock_lock);
+	list_add_tail(&req->rq_list, &xprt->recv);
+	spin_unlock_bh(&xprt->sock_lock);
 }
 
 /*
@@ -1199,27 +1262,25 @@
 	struct rpc_xprt	*xprt = task->tk_xprt;
 	struct rpc_rqst	*req;
 
-	if (xprt->snd_task == task) {
-		if (xprt->stream)
-			xprt_disconnect(xprt);
-		xprt_release_write(xprt, task);
-	}
 	if (!(req = task->tk_rqstp))
 		return;
+	spin_lock_bh(&xprt->sock_lock);
+	__xprt_release_write(xprt, task);
+	__xprt_put_cong(xprt, req);
+	if (!list_empty(&req->rq_list))
+		list_del(&req->rq_list);
+	spin_unlock_bh(&xprt->sock_lock);
 	task->tk_rqstp = NULL;
 	memset(req, 0, sizeof(*req));	/* mark unused */
 
 	dprintk("RPC: %4d release request %p\n", task->tk_pid, req);
 
-	spin_lock_bh(&xprt->xprt_lock);
+	spin_lock(&xprt->xprt_lock);
 	req->rq_next = xprt->free;
 	xprt->free   = req;
 
-	/* Decrease congestion value. */
-	xprt->cong -= RPC_CWNDSCALE;
-
 	xprt_clear_backlog(xprt);
-	spin_unlock_bh(&xprt->xprt_lock);
+	spin_unlock(&xprt->xprt_lock);
 }
 
 /*
@@ -1275,11 +1336,12 @@
 		xprt->nocong = 1;
 	} else
 		xprt->cwnd = RPC_INITCWND;
-	xprt->congtime = jiffies;
 	spin_lock_init(&xprt->sock_lock);
 	spin_lock_init(&xprt->xprt_lock);
 	init_waitqueue_head(&xprt->cong_wait);
 
+	INIT_LIST_HEAD(&xprt->recv);
+
 	/* Set timeout parameters */
 	if (to) {
 		xprt->timeout = *to;
@@ -1290,6 +1352,7 @@
 
 	INIT_RPC_WAITQ(&xprt->pending, "xprt_pending");
 	INIT_RPC_WAITQ(&xprt->sending, "xprt_sending");
+	INIT_RPC_WAITQ(&xprt->resend, "xprt_resend");
 	INIT_RPC_WAITQ(&xprt->backlog, "xprt_backlog");
 
 	/* initialize free list */
@@ -1421,6 +1484,7 @@
 {
 	xprt->shutdown = 1;
 	rpc_wake_up(&xprt->sending);
+	rpc_wake_up(&xprt->resend);
 	rpc_wake_up(&xprt->pending);
 	rpc_wake_up(&xprt->backlog);
 	if (waitqueue_active(&xprt->cong_wait))
@@ -1432,8 +1496,6 @@
  */
 int
 xprt_clear_backlog(struct rpc_xprt *xprt) {
-	if (RPCXPRT_CONGESTED(xprt))
-		return 0;
 	rpc_wake_up_next(&xprt->backlog);
 	if (waitqueue_active(&xprt->cong_wait))
 		wake_up(&xprt->cong_wait);
diff -Nru a/net/unix/af_unix.c b/net/unix/af_unix.c
--- a/net/unix/af_unix.c	Tue Jul 16 16:49:43 2002
+++ b/net/unix/af_unix.c	Tue Jul 16 16:49:43 2002
@@ -185,7 +185,7 @@
 		/*
 		 *	This may look like an off by one error but it is
 		 *	a bit more subtle. 108 is the longest valid AF_UNIX
-		 *	path for a binding. sun_path[108] doesnt as such
+		 *	path for a binding. sun_path[108] doesn't as such
 		 *	exist. However in kernel space we are guaranteed that
 		 *	it is a valid memory location in our kernel
 		 *	address buffer.
diff -Nru a/sound/oss/Config.in b/sound/oss/Config.in
--- a/sound/oss/Config.in	Tue Jul 16 16:49:43 2002
+++ b/sound/oss/Config.in	Tue Jul 16 16:49:43 2002
@@ -48,7 +48,7 @@
 if [ "$CONFIG_DDB5477" = "y" ]; then
     dep_tristate '  NEC Vrc5477 AC97 sound' CONFIG_SOUND_VRC5477 $CONFIG_SOUND
 fi
-dep_tristate '  Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core' CONFIG_SOUND_TRIDENT $CONFIG_SOUND
+dep_tristate '  Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core' CONFIG_SOUND_TRIDENT $CONFIG_SOUND $CONFIG_SOUND_GAMEPORT
 
 dep_tristate '  Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
 if [ "$CONFIG_SOUND_MSNDCLAS" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then
@@ -134,7 +134,7 @@
    dep_tristate '    Microsoft Sound System support' CONFIG_SOUND_MSS $CONFIG_SOUND_OSS
    dep_tristate '    MPU-401 support (NOT for SB16)' CONFIG_SOUND_MPU401 $CONFIG_SOUND_OSS
    dep_tristate '    NM256AV/NM256ZX audio support' CONFIG_SOUND_NM256 $CONFIG_SOUND_OSS
-   dep_tristate '    OPTi MAD16 and/or Mozart based cards' CONFIG_SOUND_MAD16 $CONFIG_SOUND_OSS
+   dep_tristate '    OPTi MAD16 and/or Mozart based cards' CONFIG_SOUND_MAD16 $CONFIG_SOUND_OSS $CONFIG_SOUND_GAMEPORT
    if [ "$CONFIG_SOUND_MAD16" = "y" -o "$CONFIG_SOUND_MAD16" = "m" ]; then
      bool '      Support MIDI in older MAD16 based cards (requires SB)' CONFIG_MAD16_OLDCARD
    fi
diff -Nru a/sound/oss/ad1848.c b/sound/oss/ad1848.c
--- a/sound/oss/ad1848.c	Tue Jul 16 16:49:41 2002
+++ b/sound/oss/ad1848.c	Tue Jul 16 16:49:41 2002
@@ -1996,7 +1996,8 @@
 		sprintf(dev_name,
 			"Generic audio codec (%s)", devc->chip_name);
 
-	request_region(devc->base, 4, devc->name);
+	if (!request_region(devc->base, 4, devc->name))
+		return -1;
 
 	conf_printf2(dev_name, devc->base, devc->irq, dma_playback, dma_capture);
 
@@ -2012,8 +2013,10 @@
 	}
 
 	portc = (ad1848_port_info *) kmalloc(sizeof(ad1848_port_info), GFP_KERNEL);
-	if(portc==NULL)
+	if(portc==NULL) {
+		release_region(devc->base, 4);
 		return -1;
+	}
 
 	if ((my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
 					     dev_name,
@@ -2025,8 +2028,8 @@
 					     dma_playback,
 					     dma_capture)) < 0)
 	{
+		release_region(devc->base, 4);
 		kfree(portc);
-		portc=NULL;
 		return -1;
 	}
 	
diff -Nru a/sound/oss/btaudio.c b/sound/oss/btaudio.c
--- a/sound/oss/btaudio.c	Tue Jul 16 16:49:42 2002
+++ b/sound/oss/btaudio.c	Tue Jul 16 16:49:42 2002
@@ -144,18 +144,17 @@
 	int sampleshift;
 	int channels;
 	int analog;
+	int rate;
+};
+
+struct cardinfo {
+	char *name;
+	int rate;
 };
 
 static struct btaudio *btaudios = NULL;
-static unsigned int dsp1 = -1;
-static unsigned int dsp2 = -1;
-static unsigned int mixer = -1;
 static unsigned int debug = 0;
 static unsigned int irq_debug = 0;
-static int latency = -1;
-static int digital = 1;
-static int analog = 1;
-static int rate = 32000;
 
 /* -------------------------------------------------------------- */
 
@@ -658,7 +657,7 @@
 		if (bta->analog) {
 			return put_user(HWBASE_AD*4/bta->decimation>>bta->sampleshift, (int*)arg);
 		} else {
-			return put_user(rate, (int*)arg);
+			return put_user(bta->rate, (int*)arg);
 		}
 
         case SNDCTL_DSP_STEREO:
@@ -871,10 +870,32 @@
 
 /* -------------------------------------------------------------- */
 
+static unsigned int dsp1 = -1;
+static unsigned int dsp2 = -1;
+static unsigned int mixer = -1;
+static int latency = -1;
+static int digital = 1;
+static int analog = 1;
+static int rate = 0;
+
+#define BTA_OSPREY200 1
+
+static struct cardinfo cards[] = {
+	[0] = {
+		name: "default",
+		rate: 32000,
+	},
+	[BTA_OSPREY200] = {
+		name: "Osprey 200",
+		rate: 44100,
+	},
+};
+
 static int __devinit btaudio_probe(struct pci_dev *pci_dev,
 				   const struct pci_device_id *pci_id)
 {
 	struct btaudio *bta;
+	struct cardinfo *card = &cards[pci_id->driver_data];
 	unsigned char revision,lat;
 	int rc = -EBUSY;
 
@@ -909,6 +930,11 @@
 		bta->sampleshift = 1;
 	}
 
+	/* sample rate */
+	bta->rate = card->rate;
+	if (rate)
+		bta->rate = rate;
+	
 	init_MUTEX(&bta->lock);
         init_waitqueue_head(&bta->readq);
 
@@ -924,6 +950,7 @@
 	       PCI_SLOT(pci_dev->devfn),PCI_FUNC(pci_dev->devfn));
         printk("irq: %d, latency: %d, mmio: 0x%lx\n",
 	       bta->irq, lat, bta->mem);
+	printk("btaudio: using card config \"%s\"\n", card->name);
 
 	/* init hw */
         btwrite(0, REG_GPIO_DMA_CTL);
@@ -932,7 +959,7 @@
 	pci_set_master(pci_dev);
 
 	if ((rc = request_irq(bta->irq, btaudio_irq, SA_SHIRQ|SA_INTERRUPT,
-			       "btaudio",(void *)bta)) < 0) {
+			      "btaudio",(void *)bta)) < 0) {
 		printk(KERN_WARNING
 		       "btaudio: can't request irq (rc=%d)\n",rc);
 		goto fail1;
@@ -1034,11 +1061,25 @@
 /* -------------------------------------------------------------- */
 
 static struct pci_device_id btaudio_pci_tbl[] __devinitdata = {
-        { PCI_VENDOR_ID_BROOKTREE, 0x0878,
-          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-        { PCI_VENDOR_ID_BROOKTREE, 0x0879,
-          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-        {0,}
+        {
+		vendor:       PCI_VENDOR_ID_BROOKTREE,
+		device:       0x0878,
+		subvendor:    0x0070,
+		subdevice:    0xff01,
+		driver_data:  BTA_OSPREY200,
+	},{
+		vendor:       PCI_VENDOR_ID_BROOKTREE,
+		device:       0x0878,
+		subvendor:    PCI_ANY_ID,
+		subdevice:    PCI_ANY_ID,
+	},{
+		vendor:       PCI_VENDOR_ID_BROOKTREE,
+		device:       0x0878,
+		subvendor:    PCI_ANY_ID,
+		subdevice:    PCI_ANY_ID,
+        },{
+		/* --- end of list --- */
+	}
 };
 
 static struct pci_driver btaudio_pci_driver = {
@@ -1050,7 +1091,7 @@
 
 static int btaudio_init_module(void)
 {
-	printk(KERN_INFO "btaudio: driver version 0.6 loaded [%s%s%s]\n",
+	printk(KERN_INFO "btaudio: driver version 0.7 loaded [%s%s%s]\n",
 	       digital ? "digital" : "",
 	       analog && digital ? "+" : "",
 	       analog ? "analog" : "");
diff -Nru a/sound/oss/es1370.c b/sound/oss/es1370.c
--- a/sound/oss/es1370.c	Tue Jul 16 16:49:42 2002
+++ b/sound/oss/es1370.c	Tue Jul 16 16:49:42 2002
@@ -23,11 +23,6 @@
  *
  *
  * Module command line parameters:
- *   joystick if 1 enables the joystick interface on the card; but it still
- *            needs a driver for joysticks connected to a standard IBM-PC
- *	      joyport. It is tested with the joy-analog driver. This 
- *	      module must be loaded before the joystick driver. Kmod will
- *	      not ensure that.
  *   lineout  if 1 the LINE jack is used as an output instead of an input.
  *            LINE then contains the unmixed dsp output. This can be used
  *            to make the card a four channel one: use dsp to output two
@@ -2529,14 +2524,11 @@
 /* maximum number of devices; only used for command line params */
 #define NR_DEVICE 5
 
-static int joystick[NR_DEVICE] = { 0, };
 static int lineout[NR_DEVICE] = { 0, };
 static int micbias[NR_DEVICE] = { 0, };
 
 static unsigned int devindex = 0;
 
-MODULE_PARM(joystick, "1-" __MODULE_STRING(NR_DEVICE) "i");
-MODULE_PARM_DESC(joystick, "if 1 enables joystick interface (still need separate driver)");
 MODULE_PARM(lineout, "1-" __MODULE_STRING(NR_DEVICE) "i");
 MODULE_PARM_DESC(lineout, "if 1 the LINE input is converted to LINE out");
 MODULE_PARM(micbias, "1-" __MODULE_STRING(NR_DEVICE) "i");
@@ -2617,13 +2609,11 @@
 	 * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
 	s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
 	s->gameport.io = 0;
-	if (joystick[devindex]) {
-		if (!request_region(0x200, JOY_EXTENT, "es1370"))
-			printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
-		else {
-			s->ctrl |= CTRL_JYSTK_EN;
-			s->gameport.io = 0x200;
-		}
+	if (!request_region(0x200, JOY_EXTENT, "es1370"))
+		printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
+	else {
+		s->ctrl |= CTRL_JYSTK_EN;
+		s->gameport.io = 0x200;
 	}
 	if (lineout[devindex])
 		s->ctrl |= CTRL_XCTL0;
@@ -2765,7 +2755,7 @@
 
 #ifndef MODULE
 
-/* format is: es1370=[joystick[,lineout[,micbias]]] */
+/* format is: es1370=lineout[,micbias]] */
 
 static int __init es1370_setup(char *str)
 {
@@ -2775,9 +2765,8 @@
 		return 0;
 
 	(void)
-	(   (get_option(&str,&joystick[nr_dev]) == 2)
-	 && (get_option(&str,&lineout [nr_dev]) == 2)
-	 &&  get_option(&str,&micbias [nr_dev])
+	((get_option(&str,&lineout [nr_dev]) == 2)
+	 && get_option(&str,&micbias [nr_dev])
 	);
 
 	nr_dev++;
diff -Nru a/sound/oss/es1371.c b/sound/oss/es1371.c
--- a/sound/oss/es1371.c	Tue Jul 16 16:49:41 2002
+++ b/sound/oss/es1371.c	Tue Jul 16 16:49:41 2002
@@ -21,12 +21,6 @@
  *
  * Special thanks to Ensoniq
  *
- *
- * Module command line parameters:
- *   joystick must be set to the base I/O-Port to be used for
- *   the gameport. Legal values are 0x200, 0x208, 0x210 and 0x218.         
- *   The gameport is mirrored eight times.
- *        
  *  Supported devices:
  *  /dev/dsp    standard /dev/dsp device, (mostly) OSS compatible
  *  /dev/mixer  standard /dev/mixer device, (mostly) OSS compatible
@@ -2744,20 +2738,17 @@
 /* maximum number of devices; only used for command line params */
 #define NR_DEVICE 5
 
-static int joystick[NR_DEVICE] = { 0, };
 static int spdif[NR_DEVICE] = { 0, };
 static int nomix[NR_DEVICE] = { 0, };
+static int amplifier[NR_DEVICE] = { 0, };
 
 static unsigned int devindex = 0;
-static int amplifier = 0;
 
-MODULE_PARM(joystick, "1-" __MODULE_STRING(NR_DEVICE) "i");
-MODULE_PARM_DESC(joystick, "sets address and enables joystick interface (still need separate driver)");
 MODULE_PARM(spdif, "1-" __MODULE_STRING(NR_DEVICE) "i");
 MODULE_PARM_DESC(spdif, "if 1 the output is in S/PDIF digital mode");
 MODULE_PARM(nomix, "1-" __MODULE_STRING(NR_DEVICE) "i");
 MODULE_PARM_DESC(nomix, "if 1 no analog audio is mixed to the digital output");
-MODULE_PARM(amplifier, "i");
+MODULE_PARM(amplifier, "1-" __MODULE_STRING(NR_DEVICE) "i");
 MODULE_PARM_DESC(amplifier, "Set to 1 if the machine needs the amp control enabling (many laptops)");
 
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
@@ -2856,8 +2847,8 @@
 		printk(KERN_ERR PFX "irq %u in use\n", s->irq);
 		goto err_irq;
 	}
-	printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n"
-	       KERN_INFO PFX "features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]);
+	printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u joystick %#x\n",
+	       s->rev, s->io, s->irq, s->gameport.io);
 	/* register devices */
 	if ((res=(s->dev_audio = register_sound_dsp(&es1371_audio_fops,-1))<0))
 		goto err_dev1;
@@ -2877,7 +2868,7 @@
 
 	/* Check amplifier requirements */
 	
-	if(amplifier)
+	if (amplifier[devindex])
 		s->ctrl |= CTRL_GPIO_OUT0;
 	else for(idx = 0; amplifier_needed[idx].svid != PCI_ANY_ID; idx++)
 	{
@@ -2889,24 +2880,16 @@
 		}
 	}
 	s->gameport.io = 0;
-	if ((joystick[devindex] & ~0x18) == 0x200) {
-		if (!request_region(joystick[devindex], JOY_EXTENT, "es1371"))
-			printk(KERN_ERR PFX "joystick address 0x%x already in use\n", joystick[devindex]);
-		else {
-			s->ctrl |= CTRL_JYSTK_EN | (((joystick[devindex] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
-			s->gameport.io = joystick[devindex];
-		}
-	} else if (joystick[devindex] == 1) {
-		for (i = 0x218; i >= 0x200; i -= 0x08) {
-			if (request_region(i, JOY_EXTENT, "es1371")) {
-				s->ctrl |= CTRL_JYSTK_EN | (((i >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
-				s->gameport.io = i;
-				break;
-			}
+	for (i = 0x218; i >= 0x200; i -= 0x08) {
+		if (request_region(i, JOY_EXTENT, "es1371")) {
+			s->ctrl |= CTRL_JYSTK_EN | (((i >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
+			s->gameport.io = i;
+			break;
 		}
-		if (!s->gameport.io)
-			printk(KERN_ERR PFX "no free joystick address found\n");
 	}
+	if (!s->gameport.io)
+		printk(KERN_ERR PFX "no free joystick address found\n");
+
 	s->sctrl = 0;
 	cssr = 0;
 	s->spdif_volume = -1;
@@ -2926,7 +2909,7 @@
 	/* initialize the chips */
 	outl(s->ctrl, s->io+ES1371_REG_CONTROL);
 	outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
-	outl(0, s->io+ES1371_REG_LEGACY);
+	outl(LEGACY_JFAST, s->io+ES1371_REG_LEGACY);
 	pci_set_master(pcidev);  /* enable bus mastering */
 	/* if we are a 5880 turn on the AC97 */
 	if (s->vendor == PCI_VENDOR_ID_ENSONIQ &&
@@ -3070,7 +3053,7 @@
 
 #ifndef MODULE
 
-/* format is: es1371=[joystick] */
+/* format is: es1371=[spdif,[nomix,[amplifier]]] */
 
 static int __init es1371_setup(char *str)
 {
@@ -3078,8 +3061,12 @@
 
 	if (nr_dev >= NR_DEVICE)
 		return 0;
-	if (get_option(&str, &joystick[nr_dev]) == 2)
-		(void)get_option(&str, &spdif[nr_dev]);
+
+	(void)
+        ((get_option(&str, &spdif[nr_dev]) == 2)
+         && (get_option(&str, &nomix[nr_dev]) == 2)
+         && (get_option(&str, &amplifier[nr_dev])));
+
 	nr_dev++;
 	return 1;
 }
diff -Nru a/sound/oss/mad16.c b/sound/oss/mad16.c
--- a/sound/oss/mad16.c	Tue Jul 16 16:49:41 2002
+++ b/sound/oss/mad16.c	Tue Jul 16 16:49:41 2002
@@ -881,7 +881,7 @@
 static int __initdata cdport = 0x340;
 static int __initdata cddma = -1;
 static int __initdata opl4 = 0;
-static int __initdata joystick = 0;
+static int __initdata joystick = 1;
 
 MODULE_PARM(mpu_io, "i");
 MODULE_PARM(mpu_irq, "i");
diff -Nru a/sound/oss/sb_audio.c b/sound/oss/sb_audio.c
--- a/sound/oss/sb_audio.c	Tue Jul 16 16:49:42 2002
+++ b/sound/oss/sb_audio.c	Tue Jul 16 16:49:42 2002
@@ -851,7 +851,7 @@
 	{
 		if (copy_from_user(localbuf + localoffs,
 				   userbuf + useroffs, len))
-			return -EFAULT;
+			return;
 		*used = len;
 		*returned = len;
 	}
@@ -874,7 +874,7 @@
 			if (copy_from_user(lbuf16,
 					   userbuf + useroffs + (p << 1),
 					   locallen << 1))
-				return -EFAULT;
+				return;
 			for (i = 0; i < locallen; i++)
 			{
 				buf8[p+i] = ~((lbuf16[i] >> 8) & 0xff) ^ 0x80;
@@ -904,7 +904,7 @@
 			if (copy_from_user(lbuf8,
 					   userbuf+useroffs + p,
 					   locallen))
-				return -EFAULT;
+				return;
 			for (i = 0; i < locallen; i++)
 			{
 				buf16[p+i] = (~lbuf8[i] ^ 0x80) << 8;
diff -Nru a/sound/oss/trident.c b/sound/oss/trident.c
--- a/sound/oss/trident.c	Tue Jul 16 16:49:43 2002
+++ b/sound/oss/trident.c	Tue Jul 16 16:49:43 2002
@@ -36,6 +36,9 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  History
+ *  v0.14.9e
+ *      January 2 2002 Vojtech Pavlik <vojtech@ucw.cz> added gameport
+ *      support to avoid resource conflict with pcigame.c
  *  v0.14.9d
  *  	October 8 2001 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *	use set_current_state, properly release resources on failure in
@@ -171,6 +174,7 @@
 #include <linux/bitops.h>
 #include <linux/proc_fs.h>
 #include <linux/interrupt.h>
+#include <linux/gameport.h>
 
 #if defined CONFIG_ALPHA_NAUTILUS || CONFIG_ALPHA_GENERIC
 #include <asm/hwrpb.h>
@@ -180,7 +184,7 @@
 
 #include <linux/pm.h>
 
-#define DRIVER_VERSION "0.14.9d"
+#define DRIVER_VERSION "0.14.9e"
 
 /* magic numbers to protect our data structures */
 #define TRIDENT_CARD_MAGIC	0x5072696E /* "Prin" */
@@ -382,6 +386,9 @@
 	/* Added for hardware volume control */
 	int hwvolctl;
 	struct timer_list timer;
+
+	/* Game port support */
+	struct gameport gameport;
 };
 
 /* table to map from CHANNELMASK to channel attribute for SiS 7018 */
@@ -3938,6 +3945,55 @@
 	return num_ac97+1;
 }
 
+/* Gameport functions for the cards ADC gameport */
+
+static unsigned char trident_game_read(struct gameport *gameport)
+{
+	struct trident_card *card = gameport->driver;
+	return inb(TRID_REG(card, T4D_GAME_LEG));
+}
+
+static void trident_game_trigger(struct gameport *gameport)
+{
+	struct trident_card *card = gameport->driver;
+	outb(0xff, TRID_REG(card, T4D_GAME_LEG));
+}
+
+static int trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+        struct trident_card *card = gameport->driver;
+	int i;
+
+	*buttons = (~inb(TRID_REG(card, T4D_GAME_LEG)) >> 4) & 0xf;
+
+	for (i = 0; i < 4; i++) {
+		axes[i] = inw(TRID_REG(card, T4D_GAME_AXD) + i * sizeof(u16));
+		if (axes[i] == 0xffff) axes[i] = -1;
+	}
+        
+        return 0;
+}
+
+static int trident_game_open(struct gameport *gameport, int mode)
+{
+	struct trident_card *card = gameport->driver;
+
+	switch (mode) {
+		case GAMEPORT_MODE_COOKED:
+			outb(0x80, TRID_REG(card, T4D_GAME_CR));
+			wait_ms(20);
+			return 0;
+		case GAMEPORT_MODE_RAW:
+			outb(0x00, TRID_REG(card, T4D_GAME_CR));
+			return 0;
+		default:
+			return -1;
+	}
+
+	return 0;
+}
+
+
 /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
    until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
 static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
@@ -3998,6 +4054,13 @@
 	card->banks[BANK_B].addresses = &bank_b_addrs;
 	card->banks[BANK_B].bitmap = 0UL;
 
+	card->gameport.driver = card;
+	card->gameport.fuzz = 64;
+	card->gameport.read = trident_game_read;
+	card->gameport.trigger = trident_game_trigger;
+	card->gameport.cooked_read = trident_game_cooked_read;
+	card->gameport.open = trident_game_open;
+
 	init_MUTEX(&card->open_sem);
 	spin_lock_init(&card->lock);
 	init_timer(&card->timer);
@@ -4131,6 +4194,10 @@
 
 	/* Enable Address Engine Interrupts */
 	trident_enable_loop_interrupts(card);
+
+	/* Register gameport */
+	gameport_register_port(&card->gameport);
+
 out:	return rc;
 out_unregister_sound_dsp:
 	unregister_sound_dsp(card->dev_audio);
@@ -4171,6 +4238,9 @@
 		remove_proc_entry("ALi5451", NULL);
 #endif
 	}
+
+	/* Unregister gameport */
+	gameport_unregister_port(&card->gameport);
 
 	/* Kill interrupts, and SP/DIF */
 	trident_disable_loop_interrupts(card);
diff -Nru a/sound/oss/trident.h b/sound/oss/trident.h
--- a/sound/oss/trident.h	Tue Jul 16 16:49:41 2002
+++ b/sound/oss/trident.h	Tue Jul 16 16:49:41 2002
@@ -79,6 +79,8 @@
 
 /* operational registers common to DX, NX, 7018 */
 enum trident_op_registers {
+	T4D_GAME_CR	= 0x30, T4D_GAME_LEG	= 0x31,
+	T4D_GAME_AXD	= 0x34,
 	T4D_REC_CH	= 0x70,
 	T4D_START_A     = 0x80, T4D_STOP_A      = 0x84,
 	T4D_DLY_A       = 0x88, T4D_SIGN_CSO_A  = 0x8c,
@@ -333,7 +335,7 @@
 #define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC)
 #define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC)
 
-extern __inline__ unsigned ld2(unsigned int x)
+static inline unsigned ld2(unsigned int x)
 {
 	unsigned r = 0;
 	
diff -Nru a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
--- a/sound/pci/cs46xx/cs46xx.c	Tue Jul 16 16:49:43 2002
+++ b/sound/pci/cs46xx/cs46xx.c	Tue Jul 16 16:49:43 2002
@@ -28,6 +28,7 @@
 #include <sound/driver.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/init.h>
 #include <sound/core.h>
 #include <sound/cs46xx.h>
 #define SNDRV_GET_ID
