diff -u --recursive --new-file v2.3.36/linux/CREDITS linux/CREDITS
--- v2.3.36/linux/CREDITS	Wed Dec 29 13:13:11 1999
+++ linux/CREDITS	Thu Jan  6 10:23:46 2000
@@ -692,6 +692,9 @@
 S: Mountain View, California 94040
 S: USA
 
+N: Jeff Garzik
+E: jgarzik@mandrakesoft.com
+
 N: Jacques Gelinas
 E: jacques@solucorp.qc.ca
 D: Author of the Umsdos file system
diff -u --recursive --new-file v2.3.36/linux/Documentation/fb/clgenfb.txt linux/Documentation/fb/clgenfb.txt
--- v2.3.36/linux/Documentation/fb/clgenfb.txt	Mon Oct 11 15:38:14 1999
+++ linux/Documentation/fb/clgenfb.txt	Thu Jan  6 10:23:46 2000
@@ -1,6 +1,6 @@
 
 		Framebuffer driver for Cirrus Logic chipsets
-		Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+		Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
 
 
 
diff -u --recursive --new-file v2.3.36/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.3.36/linux/Documentation/networking/ip-sysctl.txt	Mon May 10 09:55:25 1999
+++ linux/Documentation/networking/ip-sysctl.txt	Thu Jan  6 10:14:36 2000
@@ -51,6 +51,36 @@
 ipfrag_time - INTEGER
 	Time in seconds to keep an IP fragment in memory.	
 
+INET peer storage:
+
+inet_peer_threshold - INTEGER
+	The approximate size of the storage.  Starting from this threshold	
+	entries will be thrown aggressively.  This threshold also determines
+	entries' time-to-live and time intervals between garbage collection
+	passes.  More entries, less time-to-live, less GC interval.
+
+inet_peer_minttl - INTEGER
+	Minimum time-to-live of entries.  Should be enough to cover fragment
+	time-to-live on the reassembling side.  This minimum time-to-live  is
+	guaranteed if the pool size is less than inet_peer_threshold.
+	Measured in jiffies.
+
+inet_peer_maxttl - INTEGER
+	Maximum time-to-live of entries.  Unused entries will expire after
+	this period of time if there is no memory pressure on the pool (i.e.
+	when the number of entries in the pool is very small).
+	Measured in jiffies.
+
+inet_peer_gc_mintime - INTEGER
+	Minimum interval between garbage collection passes.  This interval is
+	in effect under high memory pressure on the pool.
+	Measured in jiffies.
+
+inet_peer_gc_maxtime - INTEGER
+	Minimum interval between garbage collection passes.  This interval is
+	in effect under low (or absent) memory pressure on the pool.
+	Measured in jiffies.
+
 TCP variables: 
 
 tcp_syn_retries - INTEGER
@@ -211,4 +241,4 @@
 Updated by:
 Andi Kleen
 ak@muc.de
-$Id: ip-sysctl.txt,v 1.9 1999/05/08 02:58:44 davem Exp $
+$Id: ip-sysctl.txt,v 1.10 2000/01/06 00:41:42 davem Exp $
diff -u --recursive --new-file v2.3.36/linux/Documentation/pci.txt linux/Documentation/pci.txt
--- v2.3.36/linux/Documentation/pci.txt	Tue Dec  7 09:32:38 1999
+++ linux/Documentation/pci.txt	Thu Jan  6 09:54:06 2000
@@ -35,8 +35,13 @@
 VENDOR_ID or DEVICE_ID.  This allows searching for any device from a
 specific vendor, for example.
 
-   In case you want to do some complex matching, look at pci_devices -- it's
-a linked list of pci_dev structures for all PCI devices in the system.
+   In case you want to do some complex matching, you can walk the list of all
+known PCI devices:
+
+		struct pci_dev *dev;
+		pci_for_each_dev(dev) {
+			... do anything you want with dev ...
+		}
 
    The `struct pci_dev *' pointer serves as an identification of a PCI device
 and is passed to all other functions operating on PCI devices.
diff -u --recursive --new-file v2.3.36/linux/Documentation/proc_usb_info.txt linux/Documentation/proc_usb_info.txt
--- v2.3.36/linux/Documentation/proc_usb_info.txt	Wed Dec 29 13:13:12 1999
+++ linux/Documentation/proc_usb_info.txt	Wed Dec 31 16:00:00 1969
@@ -1,237 +0,0 @@
-/proc/bus/usb filesystem output
-===============================
-(version 19991218)
-
-
-The /proc filesystem for USB devices generates
-/proc/bus/usb/drivers and /proc/bus/usb/devices.
-
-/proc/bus/usb/drivers just lists the registered drivers,
-one per line.  Not very interesting or pretty.
-
-In /proc/bus/usb/devices, each device's output has multiple
-lines (except for a root hub) of ASCII output.
-I made it ASCII instead of binary on purpose, so that someone
-can obtain some useful data from it without the use of an
-auxiliary program.  However, with an auxiliary program, the numbers
-in the first 4 columns of each "T:" line (topology info:
-Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram.
-(I think.  I haven't proved this, but I have tested it with 3
-different topo/connections and it looked possible.)
-
-Each line is tagged with a one-character ID for that line:
-
-T = Topology (etc.)
-B = Bandwidth
-D = Device descriptor info.
-P = Product ID info. (from Device descriptor, but they won't fit
-    together on one line)
-S = String info
-C = Configuration descriptor info. (* = active configuration)
-I = Interface descriptor info.
-E = Endpoint descriptor info.
-
-=======================================================================
-
-/proc/bus/usb/devices output format:
-
-Legend:
-  d = decimal number (may have leading spaces or 0's)
-  x = hexadecimal number (may have leading spaces or 0's)
-  s = string
-
-
-Topology info:
-
-T:  Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd
-|   |      |      |       |       |      |        |       |__MaxChildren
-|   |      |      |       |       |      |        |__Device Speed in Mbps
-|   |      |      |       |       |      |__DeviceNumber
-|   |      |      |       |       |__Count of devices at this level
-|   |      |      |       |__Connector/Port on Parent for this device
-|   |      |      |__Parent DeviceNumber
-|   |      |__Level in topology for this bus
-|   |__Bus number
-|__Topology info tag
-
-
-Bandwidth info:
-B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
-|   |                       |         |__Number if isochronous requests
-|   |                       |__Number of interrupt requests
-|   |__Total Bandwidth allocated to this bus
-|__Bandwidth info tag
-
-
-Device descriptor info & Product ID info:
-
-D:  Ver=x.xx Cls=xx(s) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
-P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx
-
-where
-D:  Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
-|   |        |             |      |       |       |__NumberConfigurations
-|   |        |             |      |       |__MaxPacketSize of Default Endpoint
-|   |        |             |      |__DeviceProtocol
-|   |        |             |__DeviceSubClass
-|   |        |__DeviceClass
-|   |__Device USB version
-|__Device info tag #1
-
-where
-P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx
-|   |           |           |__Product revision number
-|   |           |__Product ID code
-|   |__Vendor ID code
-|__Device info tag #2
-
-
-String descriptor info:
-
-S:  Manufacturer=ssss
-|   |__Manufacturer of this device as read from the device.
-|__String info tag
-
-S:  Product=ssss
-|   |__Product description of this device as read from the device.
-|__String info tag
-
-
-Configuration descriptor info:
-
-C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
-|   |       |       |      |__MaxPower in mA
-|   |       |       |__Attributes
-|   |       |__ConfiguratioNumber
-|   |__NumberOfInterfaces
-|__Config info tag
-
-
-Interface descriptor info (can be multiple per Config):
-
-I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
-|   |      |      |       |             |      |       |__Driver name
-|   |      |      |       |             |      |__InterfaceProtocol
-|   |      |      |       |             |__InterfaceSubClass
-|   |      |      |       |__InterfaceClass
-|   |      |      |__NumberOfEndpoints
-|   |      |__AlternateSettingNumber
-|   |__InterfaceNumber
-|__Interface info tag
-
-
-Endpoint descriptor info (can be multiple per Interface):
-
-E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
-E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
-|   |        |            |         |__Interval
-|   |        |            |__EndpointMaxPacketSize
-|   |        |__Attributes(EndpointType)
-|   |__EndpointAddress(I=In,O=Out)
-|__Endpoint info tag
-
-=======================================================================
-
-
-If a user or script is interested only in Topology info, for
-example, use something like "grep ^T: /proc/bus/usb/devices"
-for only the Topology lines.  A command like
-"grep -i ^[tdp]: /proc/bus/usb/devices" can be used to list
-only the lines that begin with the characters in square brackets,
-where the valid characters are TDPCIE.  With a slightly more able
-script, it can display any selected lines (for example, only T, D,
-and P lines) and change their output format.  (The "procusb"
-Perl script is the beginning of this idea.  It will list only
-selected lines [selected from TDPCIE] or "All" lines from
-/proc/bus/usb/devices.)
-
-The Topology lines can be used to generate a graphic/pictorial
-of the USB devices on a system's root hub.  (See more below
-on how to do this.)
-
-The Interface lines can be used to determine what driver is
-being used for each device.
-
-The Configuration lines could be used to list maximum power
-(in milliamps) that a system's USB devices are using.
-For example, "grep ^C: /proc/bus/usb/devices".
-
-
-Here's an example, from a system which has a UHCI root hub,
-an external hub connected to the root hub, and a mouse and
-a serial converter connected to the external hub.
-
-T:  Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
-B:  Alloc= 28/900 us ( 3%), #Int=  2, #Iso=  0
-T:  Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 4
-D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
-P:  Vendor=0451 ProdID=1446 Rev= 1.00
-C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
-I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
-E:  Ad=81(I) Atr=03(Int.) MxPS=   1 Ivl=255ms
-T:  Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
-D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
-P:  Vendor=04b4 ProdID=0001 Rev= 0.00
-C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
-I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=mouse
-E:  Ad=81(I) Atr=03(Int.) MxPS=   3 Ivl= 10ms
-T:  Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12  MxCh= 0
-D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
-P:  Vendor=0565 ProdID=0001 Rev= 1.08
-S:  Manufacturer=Peracom Networks, Inc.
-S:  Product=Peracom USB to Serial Converter
-C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
-I:  If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
-E:  Ad=81(I) Atr=02(Bulk) MxPS=  64 Ivl= 16ms
-E:  Ad=01(O) Atr=02(Bulk) MxPS=  16 Ivl= 16ms
-E:  Ad=82(I) Atr=03(Int.) MxPS=   8 Ivl=  8ms
-
-
-Selecting only the "T:" and "I:" lines from this (for example, by using
-"procusb ti"), we have:
-
-T:  Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
-T:  Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 4
-I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
-T:  Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
-I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=mouse
-T:  Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12  MxCh= 0
-I:  If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
-
-
-Physically this looks like (or could be converted to):
-
-                      +------------------+
-                      |  PC/root_hub (12)|   Dev# = 1
-                      +------------------+   (nn) is Mbps.
-    Level 0           |  CN.0   |  CN.1  |   [CN = connector/port #]
-                      +------------------+
-                          /
-                         /
-            +-----------------------+
-  Level 1   | Dev#2: 4-port hub (12)|
-            +-----------------------+
-            |CN.0 |CN.1 |CN.2 |CN.3 |
-            +-----------------------+
-                \           \____________________
-                 \_____                          \
-                       \                          \
-               +--------------------+      +--------------------+
-  Level 2      | Dev# 3: mouse (1.5)|      | Dev# 4: serial (12)|
-               +--------------------+      +--------------------+
-
-
-
-Or, in a more tree-like structure (ports [Connectors] without
-connections could be omitted):
-
-PC:  Dev# 1, root hub, 2 ports, 12 Mbps
-|_ CN.0:  Dev# 2, hub, 4 ports, 12 Mbps
-     |_ CN.0:  Dev #3, mouse, 1.5 Mbps
-     |_ CN.1:
-     |_ CN.2:  Dev #4, serial, 12 Mbps
-     |_ CN.3:
-|_ CN.1:
-
-
-                         ### END ###
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/CREDITS linux/Documentation/usb/CREDITS
--- v2.3.36/linux/Documentation/usb/CREDITS	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/CREDITS	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,160 @@
+Credits for the Simple Linux USB Driver:
+
+The following people have contributed to this code (in alphabetical
+order by last name).  I'm sure this list should be longer, its
+difficult to maintain, add yourself with a patch if desired.
+
+  Alan Cox <alan@lxorguk.ukuu.org.uk>
+  Johannes Erdfelt <jerdfelt@sventech.com>
+  ham <ham@unsuave.com>
+  Bradley M Keryan <keryan@andrew.cmu.edu>
+  Paul Mackerras <paulus@cs.anu.edu.au>
+  David E. Nelson <dnelson@jump.net>
+  Vojtech Pavlik <vojtech@suse.cz>
+  Gregory P. Smith <greg@electricrain.com>
+  Linus Torvalds <torvalds@transmeta.com>
+  Roman Weissgaerber <weissg@vienna.at>
+  <Kazuki.Yasumatsu@fujixerox.co.jp>
+
+Special thanks to:
+
+  Inaky Perez Gonzalez <inaky@peloncho.fis.ucm.es> for starting the
+  Linux USB driver effort and writing much of the larger uusbd driver.
+  Much has been learned from that effort.
+
+  The NetBSD & FreeBSD USB developers.  For being on the Linux USB list
+  and offering suggestions and sharing implementation experiences.
+
+Additional thanks to the following companies and people for donations
+of hardware, support, time and development (this is from the original
+THANKS file in Inaky's driver):
+
+        The following corporations have helped us in the development
+        of Linux USB / UUSBD:
+
+	- 3Com GmbH for donating a ISDN Pro TA and supporting me
+	  in technical questions and with test equipment. I'd never 
+	  expect such a great help.
+
+        - USAR Systems provided us with one of their excellent USB
+          Evaluation Kits. It allows us to test the Linux-USB driver
+          for compilance with the latest USB specification. USAR
+          Systems recognized the importance of an up-to-date open
+          Operating System and supports this project with
+          Hardware. Thanks!.
+
+        - Thanks to Intel Corporation for their precious help.
+
+        - We teamed up with Cherry to make Linux the first OS with
+          built-in USB support. Cherry is one of the biggest keyboard
+          makers in the world.
+
+        - CMD Technology, Inc. sponsored us kindly donating a CSA-6700
+          PCI-to-USB Controller Board to test the OHCI implementation.
+
+        - Due to their support to us, Keytronic can be sure that they
+          will sell keyboards to some of the 3 million (at least)
+          Linux users.
+
+        - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
+          It was almost imposible to get a PC backplate USB connector
+          for the motherboard here at Europe (mine, home-made, was
+          quite lowsy :). Now I know where to adquire nice USB stuff!
+
+        - Genius Germany donated a USB mouse to test the mouse boot
+          protocol. They've also donated a F-23 digital joystick and a
+          NetMouse Pro. Thanks! 
+
+        - AVM GmbH Berlin is supporting the development of the Linux
+          USB driver for the AVM ISDN Controller B1 USB. AVM is a
+          leading manufacturer for active and passive ISDN Controllers
+          and CAPI 2.0-based software. The active design of the AVM B1
+          is open for all OS platforms, including Linux.
+
+        - Thanks to Y-E Data, Inc. for donating their FlashBuster-U
+          USB Floppy Disk Drive, so we could test the bulk transfer
+          code.
+
+        - Many thanks to Logitech for contributing a three axis USB
+          mouse. 
+
+          Logitech designs, manufactures and markets
+          Human Interface Devices, having a long history and
+          experience in making devices such as keyboards, mice,
+          trackballs, cameras, loudspeakers and control devices for
+          gaming and professional use.
+
+          Being a recognized vendor and seller for all these devices,
+          they have donated USB mice, a joystick and a scanner, as a
+          way to acknowledge the importance of Linux and to allow
+          Logitech customers to enjoy support in their favorite
+          operating systems and all Linux users to use Logitech and
+          other USB hardware.
+
+          Logitech is official sponsor of the Linux Conference on
+          Feb. 11th 1999 in Vienna, where we'll will present the
+          current state of the Linux USB effort.
+
+        - CATC has provided means to uncover dark corners of the UHCI
+          inner workings with a USB Inspector.
+
+        - Thanks to Entrega for providing PCI to USB cards, hubs and
+          converter products for development. 
+
+
+        And thanks go to (hey! in no particular order :)
+
+        - Oren Tirosh <orenti@hishome.net>, for standing so patiently
+          all my doubts'bout USB and giving lots of cool ideas.
+
+        - Jochen Karrer <karrer@wpfd25.physik.uni-wuerzburg.de>, for
+          pointing out mortal bugs and giving advice.
+
+        - Edmund Humemberger <ed@atnet.at>, for it's great work on
+          public relationships and general management stuff for the
+          Linux-USB effort.
+
+        - Alberto Menegazzi <flash@flash.iol.it> is starting the
+          documentation for the UUSBD. Go for it!
+
+        - Ric Klaren <ia_ric@cs.utwente.nl> for doing nice
+          introductory documents (compiting with Alberto's :).
+
+        - Christian Groessler <cpg@aladdin.de>, for it's help on those
+          itchy bits ... :)
+
+        - Paul MacKerras for polishing OHCI and pushing me harder for
+          the iMac support, giving improvements and enhancements.
+
+        - Fernando Herrera <fherrera@eurielec.etsit.upm.es> has taken
+          charge of composing, maintaining and feeding the
+          long-awaited, unique and marvelous UUSBD FAQ! Tadaaaa!!!
+
+        - Rasca Gmelch <thron@gmx.de> has revived the raw driver and
+          pointed bugs, as well as started the uusbd-utils package.
+
+        - Peter Dettori <dettori@ozy.dec.com> is unconvering bugs like
+          crazy, as well as making cool suggestions, great :)
+
+        - All the Free Software and Linux community, the FSF & the GNU
+          project, the MIT X consortium, the TeX people ... everyone!
+          You know who you are!
+
+        - Big thanks to Richard Stallman for creating Emacs!
+
+        - The people at the linux-usb mailing list, for reading so
+          many messages :) Ok, no more kidding; for all your advices!
+
+        - All the people at the USB Implementors Forum for their
+          help and assistance.
+
+        - Nathan Myers <ncm@cantrip.org>, for his advice! (hope you
+          liked Cibeles' party).
+
+        - Linus Torvalds, for starting, developing and managing Linux.
+
+        - Mike Smith, Craig Keithley, Thierry Giron and Janet Schank
+          for convincing me USB Standard hubs are not that standard
+          and that's good to allow for vendor specific quirks on the
+          standard hub driver.
+
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/URB.txt linux/Documentation/usb/URB.txt
--- v2.3.36/linux/Documentation/usb/URB.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/URB.txt	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,196 @@
+1. Specification of the API
+
+1.1. Basic concept or 'What is an URB?'
+
+The basic idea of the new driver is message passing, the message itself is 
+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. 
+
+- Execution of an URB is an inherently asynchronous operation, i.e. the 
+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
+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
+different, 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 continous streaming itself is transparently done by the 
+URB-machinery.
+
+1.2. The URB structure
+
+typedef struct urb
+{
+// 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 
+
+// This is used for urb linking
+	struct urb* next;               // pointer to next URB  
+	struct usb_device *dev;         // pointer to associated USB device
+
+// pipe is assembled by the various well known pipe-macros in usb.h
+	unsigned int pipe;              // pipe information
+
+// status after each completion
+	int status;                     // returned status
+	unsigned int transfer_flags;    // ASAP, SP_OK, EARLY_COMPLETE
+
+// for data stage (CTRL), BULK, INT and ISO
+	void *transfer_buffer;          // associated data buffer
+
+// expected length
+	int transfer_buffer_length;     // data buffer length
+	int actual_length;              // actual data buffer length    
+
+// setup stage for CTRL (always 8 bytes!)
+	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;
+
+1.3. How to get an URB?
+
+URBs are allocated with the following call
+
+	purb_t alloc_urb(int isoframes)
+
+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.
+
+To free an URB, use
+
+	void free_urb(purb_t purb)
+
+This call also may free internal (host controller specific) memory in the
+future.
+
+1.4. What has to be filled in?
+
+Depending on the type of transaction, there are some macros 
+(FILL_CONTROL_URB, FILL_BULK_URB, and FILL_INT_URB, defined in uhci.h)
+that simplify the URB creation. In general, all macros need the usb
+device pointer, the pipe (usual format), the transfer buffer, the 
+desired transfer length, the completion  handler, and its context. 
+Take a look at the uhci_control_msg-function that convert the old API 
+into an URB.
+
+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 
+transfer_flags.
+
+Usually, (to reduce restart time) the completion handler is called
+AFTER the URB re-submission. You can get the other way by setting
+USB_URB_EARLY_COMPLETE in transfer_flags. This is implicite for
+INT transfers.
+
+1.5. How to submit an URB?
+
+Just call
+
+	int submit_urb(purb_t purb)
+
+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)
+- Too many requested ISO frames (-EFBIG)
+- Invalid INT interval (-EINVAL)
+- More than one packet for INT (-EINVAL)
+
+After submission, urb->status is USB_ST_URB_PENDING.
+
+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 (implicitely ASAP).
+
+1.6. How to cancel an already running URB?
+
+Call
+	int unlink_urb(purb_t purb)
+
+It removes the urb from the internal list and frees all allocated
+HW descriptors. The status is changed to USB_ST_URB_KILLED. After 
+unlink_urb() returns, you can safely free the URB with free_urb(urb)
+and all other possibly associated data (urb->context etc.)
+
+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 *);
+
+i.e. it gets just the URB that caused the completion call.
+In the completion handler, you should have a look at urb->status to
+detect any USB errors. Since the context parameter is included in the URB,
+you can pass information to the completion handler. 
+
+
+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 alloc_urb(n)
+(recommended), the isoframe-parameter n can be used to allocate the
+structures for n frames.
+
+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 transfered length and 
+status contains the resulting USB-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 continous
+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 continous streaming you have to use URB
+linking. 
+
+1.9. How to start interrupt (INT) transfers?
+
+INT transfers are currently implemented with 8 different queues for intervals 
+for 1, 2, 4,... 128ms. Only one TD is allocated for each interrupt. After
+calling the completion handler, the TD is recycled.
+With the submission of one URB, the interrupt is scheduled until it is
+canceled by unlink_urb.
+
+The submit_urb()-call modifies urb->interval to the rounded value.
+
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/acm.txt linux/Documentation/usb/acm.txt
--- v2.3.36/linux/Documentation/usb/acm.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/acm.txt	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,94 @@
+The ACM driver works with modems and ISDN TAs that use the USB Abstract
+Control Model standard. 
+
+****************************
+Test it:
+Watch out, the driver is not stable and tested. Sync often, make backups,
+most importand: don't blame me...
+
+Create device files:
+mknod /dev/ttyACM0 c 166 0
+mknod /dev/ttyACM1 c 166 1
+mknod /dev/ttyACM2 c 166 2
+mknod /dev/ttyACM3 c 166 3
+Compile a kernel with support for your host controller (uhci only for now!)
+and support for ACM. Boot this kernel. If you connect your device to the
+USB bus you should see messages like the following:
+
+Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
+Jul 19 20:14:29 office kernel: Found 02:09
+Jul 19 20:14:29 office kernel: Found 04:09
+Jul 19 20:14:29 office kernel: Found 05:07
+Jul 19 20:14:29 office last message repeated 2 times
+Jul 19 20:14:29 office kernel: parsed = 39 len = 67
+Jul 19 20:14:29 office kernel: Expected descriptor 04/09, got 02/09 - skipping
+Jul 19 20:14:29 office kernel:    0 09
+Jul 19 20:14:29 office kernel:    1 02
+Jul 19 20:14:29 office kernel:    2 43
+Jul 19 20:14:29 office kernel:    3 00
+Jul 19 20:14:29 office kernel:    4 02
+Jul 19 20:14:29 office kernel:    5 02
+Jul 19 20:14:29 office kernel:    6 04
+Jul 19 20:14:29 office kernel:    7 60
+Jul 19 20:14:29 office kernel:    8 00
+Jul 19 20:14:29 office kernel: Found 04:09
+Jul 19 20:14:29 office kernel: Found 02:09
+Jul 19 20:14:29 office kernel: Found 04:09
+Jul 19 20:14:29 office kernel: Found 05:07
+Jul 19 20:14:29 office kernel: Found 04:09
+Jul 19 20:14:29 office kernel: Found 05:07
+Jul 19 20:14:29 office kernel: Found 05:07
+Jul 19 20:14:29 office kernel: parsed = 67 len = 0
+Jul 19 20:14:29 office kernel: getstringtable
+Jul 19 20:14:29 office kernel: acm_probe
+Jul 19 20:14:29 office kernel: USB ACM found
+
+Watch out for the line:
+Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
+and the line:
+Jul 19 20:14:29 office kernel: USB ACM found
+These two lines show that the device was seen by the usb host controller and
+then recognized by the acm driver as a valid device.
+
+If you use a terminal emulation software like minicom with /dev/ttyACM0 you
+should be able to send AT commands to your device and get responses. I've 
+been able to do zmodem downloads to another pc. However downloads from one
+ISDN TA to another ISDN TA connected to the same PC didn't work. Don't
+know why. Flow control is not finised after all and i'd guess there might
+be problems on heavily loades PCs. I also did some tests with ppp but i'm
+not finised with this. There might be a chance to get it working. However
+i'd like to know if your device is recognized as an ACM device. I'm also
+interested if the thing is stable or if it crashes.
+(should i say how it crases?)
+
+You should be able to add and remove devices from the bus. The driver will
+always try to fill up unused ttys. This means if you hotplug devices their
+order may have changed after reboot. This is not the behaviour Linus liked
+to see but it's ok for now. (I hope ;-)
+
+Please report your experiences to me:
+fuerst@in.tum.de
+
+***************************
+I've tested it with:
+3Com ISDN Pro TA.
+
+It should work with (That means i know these devices conform to ACM):
+3Com Office Connect Modem
+3Com Sportster USB (I think that's what it's called)
+
+***************************
+Many thanks to 3Com which did not only support me with hardware but also
+with technical support in USB questions. They also allowed me to do tests in
+their lab. Great!
+
+***************************
+Known bugs:
+Flow control not tested (likely not to work)
+Some tty function calls not implemented (putchar, etc...)
+Huge amounts of debug output (compile in [*] Magic SysRq key and press ALT+PRTSCR+0 )
+Not all mem is freed at close (need terminate irq in hcd)
+
+***************************
+Have fun,
+	Armin Fuerst
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/dc2xx.txt linux/Documentation/usb/dc2xx.txt
--- v2.3.36/linux/Documentation/usb/dc2xx.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/dc2xx.txt	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,110 @@
+13 November 1999
+david-b@pacbell.net
+
+This is an overview of how to use the "dc2xx" USB driver with certain
+digital still cameras from Kodak and other vendors.
+
+
+CAMERAS
+
+This driver will mostly be used with Kodak DC-2xx series digital still
+cameras, but it should be trivial to tell it about several non-Kodak
+USB-enabled cameras.
+
+You'll most likely want to hook it up to recent versions of "gPhoto"
+(www.gphoto.org), since version 0.4 and later know how to use it to talk
+to Kodak DC-240 and DC-280 cameras over USB.
+
+In addition the DC-260, DC-265, and DC-290 are currently recognized.
+However, like other cameras using the "Digita OS" (from www.flashpoint.com)
+there is no gPhoto support for this camera.  At this writing the best
+known support for these cameras is a Python script that supports image
+downloading from those cameras.  (See archives of the linux-usb mailing
+list.)  The DC-220 should also work with this driver, given information
+about the USB product IDs.  When it becomes available, the HP PhotoSmart
+C500 should also work ... it's another Digita OS camera with USB support.)
+
+It's likely that other digital still cameras can also use this USB driver,
+even if they're not from Kodak and don't use Digita.  The reason is that
+most currently known USB still camera protocols treat USB like a faster
+packet-carrying connection than a serial line, which is exactly how this
+driver looks to an application.
+
+
+USB HARDWARE
+
+This has been shown to work on x86 OHCI and UHCI (Intel) chipsets.  OHCI has
+been trouble free; not so with UHCI, which was first seen to be happy with
+2.3.24 kernels, and has not been as fast as OHCI.
+
+Note that in some cases changes in BIOS settings may be needed before
+your USB works.  At least one user has reported a need for SMP-related 
+settings as well.
+
+As yet, no reports have come from Linux users on non-Intel hardware.
+(You could color coordinate your iMac with a DC-240i ... :-)
+
+
+SETUP
+
+Configure in the DC2XX USB driver, and have it in your kernel.  Recently I
+compile it right in, but I've done it as a module in the past.
+
+Create a device, perhaps like this (both read and write):
+
+    # mknod -m 0666 /dev/kodak c 10 170
+
+That "170" is not formally assigned, and this command may change.  If you're
+using a non-Kodak camera, you may prefer another name.
+
+Don't plug in more than one compatible camera at this time.  One of them
+will be ignored, but I'd not be sure which one!
+
+
+SANITY TESTING
+
+First:  if you've got /proc support, make sure that the driver has hooked
+itself up correctly.
+
+    - you should see an entry in /proc/misc for the a Kodak DC-2xx
+      minor device number
+
+    - you should see an entry in /proc/bus/usb/drivers for "dc2xx",
+      if you also enabled USB /proc support.
+
+Second:  when you connect your camera to the computer, does it get recognized
+by the driver?
+
+    - if you've got /proc/bus/usb/devices, you should see an entry
+      something like this.  The "ProdID" may be different if you didn't
+      plug in a DC-240, but the "Driver=dc2xx" had better be there.
+
+	T:  Lev=01 Prnt=00 Port=00 Cnt=01 Dev#=  1 Spd=12  MxCh= 0
+	D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+	P:  Vendor=040a ProdID=0120 Rev= 1.08
+	C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=100mA
+	I:  If#= 0 Alt= 0 #EPs= 2 Cls=00(>ifc ) Sub=00 Prot=00 Driver=dc2xx
+	E:  Ad=01(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+	E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+
+    - if you don't have /proc support for USB, see if "dmesg" output
+      tells you that you plugged in your camera.
+
+	USB new device connect, assigned device number 1
+	Manufacturer: Eastman Kodak Company
+	Product: KODAK DC240 Zoom Digital Camera
+	USB Camera is connected
+	usbcore: dc2xx driver claimed interface c3a68600
+	ohci-control thread sleeping
+
+Third:  (optional) can you use gPhoto to talk to the camera?
+
+    - When you configure your camera, tell it to use "/dev/kodak" (or
+      whatever name you used).  Right now, gPhoto emits a diagnostic
+      message (non-GUI) saying that it since it didn't act like a TTY,
+      it's assuming it's got a USB connection.
+
+    - With the camera turned on, get the "camera summary".  It'll
+      talk to the camera -- and tell you you're using USB.
+
+If you got that far, you should be able to use everything fine.
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/error-codes.txt linux/Documentation/usb/error-codes.txt
--- v2.3.36/linux/Documentation/usb/error-codes.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/error-codes.txt	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,108 @@
+$Id: README.error-codes,v 1.1 1999/12/14 14:03:02 fliegl Exp $
+
+This is the documentation of (hopefully) all possible error codes (and
+their interpretation) that can be returned from the hostcontroller driver 
+and from usbcore.
+
+NOTE:
+The USB_ST_* codes are deferred and are only listed for compatibility, new
+software should use only -E* instead!
+
+
+
+**************************************************************************
+*                   Error codes returned by usb_submit_urb               *
+**************************************************************************
+
+Non-USB-specific:
+
+USB_ST_NOERROR
+0		URB submission went fine
+
+-ENOMEM		no memory for allocation of internal structures	
+
+USB-specific:
+
+-ENODEV		specified USB-device or bus doesn't exist
+
+-ENXIO		specified endpoint doesn't exist on the device
+
+USB_ST_URB_INVALID_ERROR
+-EINVAL		a) Invalid transfer type specified (or not supported)
+		b) Invalid interrupt interval (0<=n<256)
+		c) more than one interrupt packet requested
+
+-EAGAIN		a) specified ISO start frame too early
+		b) (using ISO-ASAP) too much scheduled for the future
+		   wait some time and try again.
+
+-EFBIG		too much ISO frames requested (currently uhci>900)
+
+-EPIPE		specified pipe-handle is already stalled
+
+-EMSGSIZE	endpoint message size is zero, do interface/alternate setting
+
+
+**************************************************************************
+*                   Error codes returned by in urb->status               *
+*                   or in iso_frame_desc[n].status (for ISO)             *
+**************************************************************************
+
+USB_ST_NOERROR
+0			Transfer completed successfully
+
+USB_ST_URB_KILLED
+-ENOENT			URB was canceled by unlink_urb
+
+USB_ST_URB_PENDING
+-EINPROGRESS		URB still pending, no results yet
+			(actually no error until now;-)
+
+USB_ST_BITSTUFF
+USB_ST_INTERNALERROR
+-EPROTO			a) bitstuff error
+			b) unknown USB error 
+
+USB_ST_CRC
+-EILSEQ			CRC mismatch
+
+-EPIPE			a) babble detect
+			b) endpoint stalled
+
+USB_ST_BUFFERUNDERRUN
+-ENOST			buffer error
+
+USB_ST_NORESPONSE
+USB_ST_TIMEOUT
+-ETIMEDOUT		transfer timed out, NAK
+
+USB_ST_REMOVED	
+-ENODEV			device was removed
+
+USB_ST_SHORT_PACKET
+-EREMOTEIO		short packet detected
+
+USB_ST_PARTIAL_ERROR
+-EXDEV			ISO transfer only partially completed
+			look at individual frame status for details
+
+USB_ST_URB_INVALID_ERROR
+-EINVAL			ISO madness, if this happens: Log off and go home
+
+**************************************************************************
+*              Error codes returned by usbcore-functions                 *
+*           (expect also other submit and transfer status codes)         *
+**************************************************************************
+
+usb_register():
+USB_ST_NOTSUPPORTED
+-EINVAL			error during registering new driver
+
+usb_terminate_bulk():
+USB_ST_REMOVED
+-ENODEV			urb already removed
+
+usb_get_*/usb_set_*():
+			All USB errors (submit/status) can occur
+
+
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/hid.txt linux/Documentation/usb/hid.txt
--- v2.3.36/linux/Documentation/usb/hid.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/hid.txt	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,162 @@
+			   Linux HID driver v0.8
+		 (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
+		    (c) 1999 Andreas Gal <agal@uwsp.edu>
+			     Sponsored by SuSE
+----------------------------------------------------------------------------
+
+0. Disclaimer
+~~~~~~~~~~~~~
+  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@suse.cz>, or by paper mail: Vojtech Pavlik,
+Ucitelska 1576, 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.
+
+1. Introduction
+~~~~~~~~~~~~~~~
+  This is a driver for USB devices conforming to the USB HID (Human Input
+Device) standard. These devices include namely keyboards, mice and
+joysticks.
+
+  However many other devices (monitors, speakers, UPSs ...) also communicate
+through the same protocol, which makes its specification somewhat bloated.
+This isn't a problem, though, because the driver doesn't need to know about
+all the possible devices it can control, and can just parse the protocol and
+leave the rest of the job (for example understanding what the UPS wants to
+say) to the userland.
+
+  Because of this, the USB HID driver has two interfaces. One is via the
+proc filesystem, allowing userland applications send and read arbitrary
+reports to and from a connected USB device. The other is via a very simple
+yet generic input device driver, which dispatches input events (keystrokes,
+mouse or joystick movements) to specific, backward compatible userland
+interfaces. This way a PS/2 mouse, an AT keyboard or a Linux joystick driver
+interface are emulated, and allow applications to immediately work with USB
+mice, USB keyboards and USB joysticks without any changes.
+
+  The input driver is aimed for a little more than USB device handling in
+the future, though. It's generic enough so that it can be used for any
+mouse, keyboard or joystick (and more, of course). A PS/2 mouse driver, a
+serial mouse, Sun mouse, and most of the busmouse drivers were rewritten to
+use this as well as the AT keyboard and Sun keyboard drivers. This will
+hopefully allow conversion of all Linux keyboard and mouse and joystick
+drivers to this scheme.
+
+  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.
+There is also a mailing list for this:
+
+	listproc@atrey.karlin.mff.cuni.cz
+
+Send "subscribe linux-joystick Your Name" to subscribe to it.
+
+2. Usage
+~~~~~~~~
+  Since the driver comes with recent 2.3 kernels, all that's needed to use
+it is to enable it either as a module or compiled-in into the kernel. 
+
+  After that, after reboot (and possibly also inserting the USB and HID
+modules) the following will happen:
+
+* If you selected keyboard support, all USB keystrokes will be also routed
+  to the Linux keyboard driver as if being input through the ordinary system
+  keyboard.
+
+* If you selected mouse support, there will be (one or more) simulated PS/2
+  mouse devices on major 10, minor 32, 33 and more. These simulated mice can
+  in addition to a standard 3-button PS/2 mouse behave like MS Intellimice,
+  with a wheel. If you want to use the wheel, just specify '-t imps2' to gpm
+  and 'Protocol "ImPS/2"' to X, and it will work. A single emulated mouse
+  device can be open by any number of processes (unlike the /dev/psaux), and
+  for each of them the emulation is separate, each can use a different mode.
+  The mousedev driver, which emulates the mice, can also emulate a Genius
+  NewScroll 5 buttons-and-a-wheel mouse, if you set it to a Genius PS/2
+  mode ('-t netmouse' 'Protocol "NetMousePS/2"'). However, not gpm, nor X
+  can decode the 5 buttons yet, so this isn't very useful right now.
+
+* If you selected joystick support, the driver will take over major 15, the
+  joystick major number, and will emulate joysticks on it. This means the
+  normal joystick driver can't be used together with it (now, after the
+  normal joystick drivers are converted to the input scheme, all will work
+  nicely together). Also, you'll probably need to calibrate your joystick
+  manually ('man jscal') to be able to use it, because the USB
+  autocalibration is far from perfect yet.
+
+* If you selected event device support, there will be devices on major 10,
+  minors 64, 65 and more for each input device connected through this
+  driver. These devices output raw events the input driver dispatches. Each
+  has a timestamp. This hopefully will be THE way X will talk to keyboard
+  and mice, because it's hardware independent, and not limited by existing
+  de-facto standards.
+
+3. 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.
+
+  Doing a cat /dev/hidmouse (c, 10, 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 event devics with the 'evtest' utitily available on the
+input driver homepage (see the URL above).
+
+4. FAQ
+~~~~~~
+Q: Why aren't any questions here yet?
+A: Because none were frequent enough yet.
+
+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
+can. Here goes a description of the current state of things, which is going
+to be extended, but not changed incompatibly as time goes:
+
+  You can use blocking and nonblocking reads, also select() on the
+/dev/inputX devices, and you'll always get a whole number of input events on
+a read. Their layout is:
+
+struct input_event {
+	struct timeval time;
+	unsigned short type;
+	unsigned short code;
+	unsigned int value;
+};
+
+  'time' is the timestamp, it returns the time at which the event happened.
+Type is for example EV_REL for relative momement, REL_KEY for a keypress or
+release. More types are defined in include/linux/input.h.
+
+  'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
+list is in include/linux/input.h.
+
+  '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. Proc interface
+~~~~~~~~~~~~~~~~~
+  For HID-specific devices there is also the /proc interface. It isn't
+present in this release yet, though, so it's description will appear here
+together with the code in the driver.
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/ohci-hcd.txt linux/Documentation/usb/ohci-hcd.txt
--- v2.3.36/linux/Documentation/usb/ohci-hcd.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/ohci-hcd.txt	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,98 @@
+
+The OHCI HCD layer is a simple but nearly complete implementation of what the
+USB people would call a HCD  for the OHCI. 
+ (ISO comming soon, Bulk, INT u. CTRL transfers enabled)
+It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
+The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. 
+
+- Roman Weissgaerber <weissg@vienna.at>
+
+ * v4.0 1999/08/18 removed all dummy eds, unlink unused eds, code cleanup, bulk transfers 
+ * v2.1 1999/05/09 ep_addr correction, code cleanup
+ * v0.2.0 1999/05/04 
+ * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers)
+ * virtual root hub is now an option, 
+ * memory allocation based on kmalloc and kfree now, simple Bus error handling, 
+ * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
+ * 
+ * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff
+ * from Greg Smith (ohci.c): better reset ohci-controller handling, hub
+ * 
+ * v0.1.0 1999/04/27 initial release
+ 
+to remove the module try:
+rmmod usb-ohci-hcd
+
+Features:
+- virtual root hub, all basic hub descriptors and commands (state: complete) 
+  this is an option now (v0.2.0)
+  #define  CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB)
+  default is with. 
+  (at the moment: the Virtual Root Hub is included automatically)
+  
+  files: ohci-root-hub.c, ohci-root-hub.h 
+ 
+
+- Endpoint Descriptor (ED) handling more static approach 
+ (EDs should be allocated in parallel to the SET CONFIGURATION command and they live
+ as long as the function (device) is alive or another configuration is choosen.
+ In the HCD layer the EDs has to be allocated manually either by calling a subroutine
+ or by sending a USB root hub vendor specific command to the virtual root hub.
+ At the alternate linux usb stack EDs will be added (allocated) at their first use.
+ ED will be unlinked from the HC chains if they are not bussy.
+ 
+ files: ohci-hcd.c ohci-hcd.h
+ routines:   (do not use for drivers, use the top layer alternate usb commands instead)
+ 
+ int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, 
+            int interval, int load, f_handler handler, int ep_size, int speed)
+       adds an endpoint, (if the endpoint already exists some parameters will be updated)
+       
+ int usb_ohci_rm_ep( ) 
+       removes an endpoint and all pending TDs of that EP
+       
+  usb_ohci_rm_function( )
+       removes all Endpoints of a function (device)
+
+- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers
+  The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has
+  to take care of buffer allocation.
+  files: ohci-hcd.c ohci-hcd.h 
+
+  There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL):
+  
+  int ohci_trans_req(struct ohci * ohci, hcd_ed, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1)
+  
+  CTRL: ctrl, ctrl_len ... cmd buffer 
+        data, data_len ... data buffer (in or out)
+  INT, BULK:  ctrl = NULL, ctrl_len=0,
+  		data, data_len ... data buffer (in or out)
+  ISO: tbd
+
+  There is no buffer reinsertion done by the internal HCD function. 
+  (The interface layer does this for a INT-pipe on request.)
+  If you want a transfer then you have to 
+  provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED
+  you can send as many as you like. They should come back by the callback f_handler in
+  the same order (for each endpoint, not globally) If an error occurs all
+  queued transfers of an endpoint will return unsent. They will be marked with an error status.
+  
+  e.g double-buffering for int transfers:
+
+   	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+  	
+  and when a data0 packet returns by the callback f_handler requeue it:
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+  and when a data1 packet returns by the callback f_handler requeue it:
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+  	
+  lw0, lw1 are private fields for upper layers for ids or fine grained handlers.
+  The alternate usb uses them for dev_id and usb_device_irq handler.
+
+
+- Done list handling: returns the requests (callback f_handler in ED) and does 
+  some error handling, root-hub request dequeuing
+  (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0))
+
+  
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/ov511.txt linux/Documentation/usb/ov511.txt
--- v2.3.36/linux/Documentation/usb/ov511.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/ov511.txt	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,70 @@
+-------------------------------------------------------------------------------
+Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC
+-------------------------------------------------------------------------------
+
+INTRODUCTION:
+
+This is a preliminary version of my OV511 Linux device driver. At the moment,
+it does not do much more than detect the chip and initialize it. As trivial
+as this sounds, it represents many hours of my work. Since OmniVision refused
+to release the full specs to me, I had to write code to probe out the register
+read/write commands. Some code is in place to allow a frame to be grabbed, but
+it is nowhere near complete.
+
+SUPPORTED CAMERAS:
+____________________________________________
+Manufacturer     | Model        | Custom ID 
+-----------------+--------------+-----------
+D-Link           | DSB-C300	    | 3
+Creative Labs    | WebCam 3     | 21
+--------------------------------------------
+
+Any camera using the OV511 and the OV7610 CCD should work with this driver. The
+driver only detects known cameras though, based on their custom id number. If
+you have a currently unsupported camera, the ID number should be reported to you
+in the kernel logs. If you have an unsupported camera, please send me the model,
+manufacturer and ID number and I will add it to the detection code. In the
+meantime, you can add to the code yourself in the function ov511_probe()
+
+WHAT YOU NEED:
+
+- If you want to help with the development, get the chip's specification docs at
+  http://www.ovt.com/omniusbp.html
+
+- A Video4Linux compatible frame grabber program (I recommend vidcat)
+  (see: http://www.exploits.org/v4l/ )
+  
+WHAT NEEDS TO BE DONE:
+
+In short, a lot. 
+
+UPDATE:
+Currently, the control messages are working fine ("vendor commands"; for
+reading and writing the OV511 registers.) The I2C bus commands for reading and
+writing the camera (OV7610) registers are implemented and working, with at least
+one person's camera. The isochronous-in endpoint for video data is finally
+producing data, but since ov511_parse_data() is not implemented you will not see
+a picture yet.
+
+Support for specific CCD's will have to be implemented as well (such as the
+OV7610.) 
+
+The rest of the work will involve implementing support for all the different
+resolutions, color depths, etc. Also, while support for the OV511's proprietary
+lossy compression is apparently not necessary (the code currently disables it,)
+it would be a nice addition as it improves performance quite a bit. OmniVision
+wouldn't tell me how the algorithm works, so we can't really work on that yet.
+Please kindly inform OmniVision that you would like them to release their
+specifications to the Linux community.
+
+HOW TO CONTACT ME:
+
+You can email me at mmcclelland@delphi.com . Please prefix the subject line
+with "OV511: " so that I am certain to notice your message.
+
+CREDITS:
+
+The code is based in no small part on the CPiA driver by Johannes Erdfelt,
+Randy Dunlap, and others. Big thanks to them for their pioneering work on that
+and the USB stack. Thanks to Bret Wallach for getting camera reg IO and ISOC
+working.
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/proc_usb_info.txt linux/Documentation/usb/proc_usb_info.txt
--- v2.3.36/linux/Documentation/usb/proc_usb_info.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/proc_usb_info.txt	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,237 @@
+/proc/bus/usb filesystem output
+===============================
+(version 19991218)
+
+
+The /proc filesystem for USB devices generates
+/proc/bus/usb/drivers and /proc/bus/usb/devices.
+
+/proc/bus/usb/drivers just lists the registered drivers,
+one per line.  Not very interesting or pretty.
+
+In /proc/bus/usb/devices, each device's output has multiple
+lines (except for a root hub) of ASCII output.
+I made it ASCII instead of binary on purpose, so that someone
+can obtain some useful data from it without the use of an
+auxiliary program.  However, with an auxiliary program, the numbers
+in the first 4 columns of each "T:" line (topology info:
+Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram.
+(I think.  I haven't proved this, but I have tested it with 3
+different topo/connections and it looked possible.)
+
+Each line is tagged with a one-character ID for that line:
+
+T = Topology (etc.)
+B = Bandwidth
+D = Device descriptor info.
+P = Product ID info. (from Device descriptor, but they won't fit
+    together on one line)
+S = String info
+C = Configuration descriptor info. (* = active configuration)
+I = Interface descriptor info.
+E = Endpoint descriptor info.
+
+=======================================================================
+
+/proc/bus/usb/devices output format:
+
+Legend:
+  d = decimal number (may have leading spaces or 0's)
+  x = hexadecimal number (may have leading spaces or 0's)
+  s = string
+
+
+Topology info:
+
+T:  Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd
+|   |      |      |       |       |      |        |       |__MaxChildren
+|   |      |      |       |       |      |        |__Device Speed in Mbps
+|   |      |      |       |       |      |__DeviceNumber
+|   |      |      |       |       |__Count of devices at this level
+|   |      |      |       |__Connector/Port on Parent for this device
+|   |      |      |__Parent DeviceNumber
+|   |      |__Level in topology for this bus
+|   |__Bus number
+|__Topology info tag
+
+
+Bandwidth info:
+B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
+|   |                       |         |__Number if isochronous requests
+|   |                       |__Number of interrupt requests
+|   |__Total Bandwidth allocated to this bus
+|__Bandwidth info tag
+
+
+Device descriptor info & Product ID info:
+
+D:  Ver=x.xx Cls=xx(s) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
+P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx
+
+where
+D:  Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
+|   |        |             |      |       |       |__NumberConfigurations
+|   |        |             |      |       |__MaxPacketSize of Default Endpoint
+|   |        |             |      |__DeviceProtocol
+|   |        |             |__DeviceSubClass
+|   |        |__DeviceClass
+|   |__Device USB version
+|__Device info tag #1
+
+where
+P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx
+|   |           |           |__Product revision number
+|   |           |__Product ID code
+|   |__Vendor ID code
+|__Device info tag #2
+
+
+String descriptor info:
+
+S:  Manufacturer=ssss
+|   |__Manufacturer of this device as read from the device.
+|__String info tag
+
+S:  Product=ssss
+|   |__Product description of this device as read from the device.
+|__String info tag
+
+
+Configuration descriptor info:
+
+C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
+|   |       |       |      |__MaxPower in mA
+|   |       |       |__Attributes
+|   |       |__ConfiguratioNumber
+|   |__NumberOfInterfaces
+|__Config info tag
+
+
+Interface descriptor info (can be multiple per Config):
+
+I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
+|   |      |      |       |             |      |       |__Driver name
+|   |      |      |       |             |      |__InterfaceProtocol
+|   |      |      |       |             |__InterfaceSubClass
+|   |      |      |       |__InterfaceClass
+|   |      |      |__NumberOfEndpoints
+|   |      |__AlternateSettingNumber
+|   |__InterfaceNumber
+|__Interface info tag
+
+
+Endpoint descriptor info (can be multiple per Interface):
+
+E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
+E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
+|   |        |            |         |__Interval
+|   |        |            |__EndpointMaxPacketSize
+|   |        |__Attributes(EndpointType)
+|   |__EndpointAddress(I=In,O=Out)
+|__Endpoint info tag
+
+=======================================================================
+
+
+If a user or script is interested only in Topology info, for
+example, use something like "grep ^T: /proc/bus/usb/devices"
+for only the Topology lines.  A command like
+"grep -i ^[tdp]: /proc/bus/usb/devices" can be used to list
+only the lines that begin with the characters in square brackets,
+where the valid characters are TDPCIE.  With a slightly more able
+script, it can display any selected lines (for example, only T, D,
+and P lines) and change their output format.  (The "procusb"
+Perl script is the beginning of this idea.  It will list only
+selected lines [selected from TDPCIE] or "All" lines from
+/proc/bus/usb/devices.)
+
+The Topology lines can be used to generate a graphic/pictorial
+of the USB devices on a system's root hub.  (See more below
+on how to do this.)
+
+The Interface lines can be used to determine what driver is
+being used for each device.
+
+The Configuration lines could be used to list maximum power
+(in milliamps) that a system's USB devices are using.
+For example, "grep ^C: /proc/bus/usb/devices".
+
+
+Here's an example, from a system which has a UHCI root hub,
+an external hub connected to the root hub, and a mouse and
+a serial converter connected to the external hub.
+
+T:  Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
+B:  Alloc= 28/900 us ( 3%), #Int=  2, #Iso=  0
+T:  Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 4
+D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=0451 ProdID=1446 Rev= 1.00
+C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
+E:  Ad=81(I) Atr=03(Int.) MxPS=   1 Ivl=255ms
+T:  Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
+D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=04b4 ProdID=0001 Rev= 0.00
+C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=mouse
+E:  Ad=81(I) Atr=03(Int.) MxPS=   3 Ivl= 10ms
+T:  Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12  MxCh= 0
+D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=0565 ProdID=0001 Rev= 1.08
+S:  Manufacturer=Peracom Networks, Inc.
+S:  Product=Peracom USB to Serial Converter
+C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
+I:  If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
+E:  Ad=81(I) Atr=02(Bulk) MxPS=  64 Ivl= 16ms
+E:  Ad=01(O) Atr=02(Bulk) MxPS=  16 Ivl= 16ms
+E:  Ad=82(I) Atr=03(Int.) MxPS=   8 Ivl=  8ms
+
+
+Selecting only the "T:" and "I:" lines from this (for example, by using
+"procusb ti"), we have:
+
+T:  Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
+T:  Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 4
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
+T:  Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=mouse
+T:  Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12  MxCh= 0
+I:  If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
+
+
+Physically this looks like (or could be converted to):
+
+                      +------------------+
+                      |  PC/root_hub (12)|   Dev# = 1
+                      +------------------+   (nn) is Mbps.
+    Level 0           |  CN.0   |  CN.1  |   [CN = connector/port #]
+                      +------------------+
+                          /
+                         /
+            +-----------------------+
+  Level 1   | Dev#2: 4-port hub (12)|
+            +-----------------------+
+            |CN.0 |CN.1 |CN.2 |CN.3 |
+            +-----------------------+
+                \           \____________________
+                 \_____                          \
+                       \                          \
+               +--------------------+      +--------------------+
+  Level 2      | Dev# 3: mouse (1.5)|      | Dev# 4: serial (12)|
+               +--------------------+      +--------------------+
+
+
+
+Or, in a more tree-like structure (ports [Connectors] without
+connections could be omitted):
+
+PC:  Dev# 1, root hub, 2 ports, 12 Mbps
+|_ CN.0:  Dev# 2, hub, 4 ports, 12 Mbps
+     |_ CN.0:  Dev #3, mouse, 1.5 Mbps
+     |_ CN.1:
+     |_ CN.2:  Dev #4, serial, 12 Mbps
+     |_ CN.3:
+|_ CN.1:
+
+
+                         ### END ###
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/scanner-hp-sane.txt linux/Documentation/usb/scanner-hp-sane.txt
--- v2.3.36/linux/Documentation/usb/scanner-hp-sane.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/scanner-hp-sane.txt	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,69 @@
+Oct. 19, 1999
+
+CHANGES
+
+- Ammended for Linux-2.3.22+
+
+
+INTRODUCTION
+
+This document will hopefully provide enough info on how to get SANE
+working with a Hewlett Packard USB capable scanner using the USB
+interface.  The majority of HP Scanners support the Scanner Control
+Language (SCL) which is both published by HP and supported by SANE.
+The only HP Scanner that I'm aware of that does not support SCL is the
+4200C.  All other HP scanners with USB interfaces should work (4100C,
+5200C, 6200C, and 6300C).  Of course as HP releases new scanners this
+information may change.
+
+
+REQUIREMENTS
+
+In order to get this running you'll need USB support in your kernel in
+addition to USB Scanner support.  Please refer to README.scanner
+for issues pertaining to Linux USB and USB Scanner support.
+
+An installed version of SANE which is available from
+http://www.mostang.com/sane/.  Testing has been performed using
+version SANE-1.0.1.  For instructions on building and installing SANE,
+refer to the various README files within the SANE distribution.
+
+
+OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW?
+
+NOTE: $INSTALL_DIR is the location where SANE was installed.  It may
+be /usr/local, /usr, /opt or somewhere else.  If you don't know, ask
+your system administrator.
+
+1) Make sure that you have the libsane-hp.* libraries under the
+$INSTALL_DIR/lib/sane/ directory.  If you don't, then the HP backend
+was either not compiled or installed properly.
+
+2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following
+files: dll.conf, hp.conf.
+
+  dll.conf:  Make sure that the 'hp' entry is present and uncommented.
+
+  hp.conf: This should contain two lines:
+
+    /dev/usbscanner
+    option connect-device
+
+3) You should now be able to use SANE (xscanimage or scanimage).
+
+Don't forget to read any relevant man pages regarding the usage of
+SANE.  If you have other entries uncommented in dll.conf, you may have
+to specify the device to (x)scanimage.  Again, `man` is your friend.
+The xscanimage (1) man page has info on how to get 'The Gimp' to work
+with xscanimage.  Note that Gimp support must be compiled into SANE
+for it work.  If you are dealing with a RedHat system, this means that
+you'll also need to install the gimp-devel rpm package.
+
+NOTE: The issues regarding core dumping by (x)scanimage have (or seem
+to be thus far) been resolved with version 0.2+ of the USB scanner
+driver which should be available in linux-2.3.23.  If you notice
+otherwise, please contact me.
+
+David /\/elson
+dnelson@jump.net
+http://www.jump.net/~dnelson
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/scanner.txt linux/Documentation/usb/scanner.txt
--- v2.3.36/linux/Documentation/usb/scanner.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/scanner.txt	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,231 @@
+Oct 19, 1999
+
+CHANGES
+
+- Ammended for linux-2.3.22+
+- Appended hp_scan.c to end of this README
+- Removed most references to HP
+
+
+OVERVIEW
+
+This README will address issues regarding how to configure the kernel
+to access a USB scanner.  Although the driver was originally conceived
+for USB HP scanners, it's general enough so that it can be used with
+other scanners.  Also, one can now pass the USB Vendor and
+Product ID's using module parameters for unknown scanners.  Refer to
+the document README.scanner_hp_sane for guidance on how to configure
+SANE to use a USB HP Scanner.
+
+
+ADDITIONAL INFORMATION
+
+http://www.linux-usb.org/
+http://www.dynamine.net/linux-usb/HOWTO/
+
+
+REQUIREMENTS
+
+A host with a USB port.  Ideally, either a UHCI (Intel) or OHCI
+(Compaq and others) hardware port should work.  However, I've only
+been able to really use an OHCI controller.  I did have access to a
+system with a UHCI controller but some very limited testing did not
+produce satisfactory results.  Luke Ordelmans
+<postbus@ordelmans.demon.nl> has reported success using the UHCI host
+controller with kernel 2.3.18 and a ChainTech motherboard.  Here
+lately I've been having better success with the ohci-hcd driver.  But
+since Linux USB support is still in a state of constant development
+that may change at a later date.  I am confident that eventually all
+the host contollers will perform without incident.
+
+A Linux kernel with USB support (preferably linux-2.3.18+)
+
+A Linux kernel with USB Scanner support.
+
+
+CONFIGURATION
+
+Using `make menuconfig` or your prefered method for configuring the
+kernel, select 'Support for USB', 'OHCI/OHCI-HCD/UHCI' depending on
+your hardware, 'USB hub support', and 'USB Scanner support'.  Compile
+and install the modules (you may need to execute `depmod -a` to update
+the module dependencies).  Testing was performed only as modules,
+YMMV.
+
+Add a device for the USB scanner:
+  linux-2.3.22 and above: `mknod /dev/usbscanner c 180 48`
+  linux-2.3.21 and below: `mknod /dev/usbscanner c 16 1`
+
+Set appropriate permissions for /dev/usbscanner (don't forget about
+group and world permissions).  Both read and write permissions are
+required for proper operation.
+
+Load the appropriate modules (if compiled as modules):
+
+  OHCI:
+    modprobe usb-ohci
+    modprobe scanner
+
+  OHCI-HCD:
+    modprobe usb-ohci-hcd
+    modprobe hub
+    modprobe scanner
+
+  UHCI:
+    modprobe usb-uhci
+    modprobe hub (don't know if this is required or not)
+    modprobe scanner
+
+That's it.  SANE should now be able to access the device.  
+
+There is a small test program (hp_scan.c -- appended below) that can
+be used to test the scanner device if it's an HP scanner that supports
+SCL.  Its purpose is to test the driver without having to
+retrieve/configure SANE.  Hp_scan.c will scan the entire bed and put
+the output into a file called 'out.dat' in the current directory.  The
+data in the file is raw data so it's not very useful for imaging.
+
+
+MODULE PARAMETERS
+
+If you have a device that wish to experiment with or try using this
+driver with, but the Vendor and Product ID's are not coded in, don't
+despair.  If the driver was compiled as a module, you can pass options
+to the driver.  Simply add 'options scanner vendor=0x####
+product=0x****' to the conf.modules/modules.conf file replacing the
+#'s and the *'s with the correct ID's.  The ID's can be retrieved from
+the messages file or using `cat /proc/bus/usb/devices` if USB /proc
+support was selected during kernel configuration.
+
+
+BUGS
+
+If you encounter any problems feel free to drop me an email.
+
+David /\/elson
+dnelson@jump.net
+http://www.jump.net/~dnelson
+
+--------------- snip -- hp_scan.c -- snip ---------------
+/*
+
+This is a really crude attempt at writing a short test program.  It's
+mostly only to be used to test connectivity with USB HP scanners that
+understand SCL.  Currently, the supported models are 4100C, 5200C,
+6200C, and the 6300C.  Note that the 4200C is *NOT* acceptable.
+
+Copyright (C) David E. Nelson <dnelson@jump.net>, 1999
+
+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.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <error.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/*
+   Gray Output produces about a 8945400 byte file.
+   Color Output produces a 26836200 byte file. 
+   
+   To compile: gcc -o hp_scan hp_scan.c
+*/
+
+// #define COLOR /* Undef to scan GrayScale */
+
+int send_cmd(int, const char *, int);
+int read_cmd(int, char *, int);
+
+int
+main(void) {
+
+	ssize_t cnt = 0, total_cnt = 0;
+
+	FILE *fpout;
+
+	int fp;
+	int data_size = 32768;
+
+	char *data;
+
+	static char reset_cmd[] = {'\x1b','E'};
+
+#ifdef COLOR
+	static char data_type_cmd[] = {'\x1b','*','a','5','T'}; /* Color */
+	static char data_width_cmd[] = {'\x1b','*','a','2','4','G'}; /* 24 Bit Color */
+#else
+	static char data_type_cmd[] = {'\x1b','*','a','4','T'}; /* Gray */
+	static char data_width_cmd[] = {'\x1b','*','a','8','G'}; /* 8 Bit Gray */
+#endif
+
+	static char query_cmd[] = {'\x1b', '*', 's', '2', '5', '7', 'E'};
+	static char start_scan_cmd[] = {'\x1b','*','f','0','S'};
+	
+	if(!(data=malloc(data_size))) {
+		perror("malloc failed");
+		exit (1);
+	}
+	
+	if((fp=open("/dev/usbscanner", O_RDWR)) < 0) {
+		perror("Unable to open scanner device");
+		exit (1);
+	}
+
+	if((fpout=fopen("out.dat", "w+")) == NULL) {
+		perror("Unable to open ouput file");
+		exit(1);
+	}
+
+	send_cmd(fp, reset_cmd, sizeof(reset_cmd));
+	send_cmd(fp, data_type_cmd, sizeof(data_type_cmd));
+	send_cmd(fp, data_width_cmd, sizeof(data_width_cmd));
+	send_cmd(fp, start_scan_cmd, sizeof(start_scan_cmd));
+
+	while ((cnt = read(fp, data, data_size)) > 0) {
+		printf("Read: %u\n", cnt); 
+		if(fwrite(data, sizeof(char), cnt, fpout) < 0) {
+			perror("Write to output file failed");
+			exit (1);
+		}
+		total_cnt += cnt;
+	}
+	if (cnt < 0) {
+		perror("Read from scanner failed");
+		exit (1);
+	}
+
+	printf("\nRead %lu bytes.\n", total_cnt);
+
+	send_cmd(fp, reset_cmd, sizeof(reset_cmd));
+
+	close(fp);
+	fclose(fpout);
+	return (0);
+}
+
+int
+send_cmd(int fp, const char * cmd, int length) {
+
+	int result;
+	int x;
+
+	if((result = write(fp, cmd, length)) != length) {
+		printf ("Write warning: %d bytes requested, %d written\n");
+	} else if (result < 0) {
+		perror ("send_cmd failure");
+		exit (1);
+	}
+	return (result);
+}
+	
+int
+read_cmd(int fp, char * response, int length) {
+
+	return read(fp, response, length);
+
+}
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/uhci.txt linux/Documentation/usb/uhci.txt
--- v2.3.36/linux/Documentation/usb/uhci.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/uhci.txt	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,165 @@
+Specification and Internals for the New UHCI Driver (Whitepaper...)
+
+	brought to you by
+
+	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)
+ 
+	$Id: README.uhci,v 1.1 1999/12/14 14:03:02 fliegl Exp $
+
+This document and the new uhci sources can be found on
+		http://hotswap.in.tum.de/usb
+
+1. General issues
+
+1.1 Why a new UHCI driver, we already have one?!?
+
+Correct, but its internal structure got more and more mixed up by the (still
+ongoing) efforts to get isochronous transfers (ISO) to work.
+Since there is an increasing need for reliable ISO-transfers (especially 
+for USB-audio needed by TS and for a DAB-USB-Receiver build by GA and DF), 
+this state was a bit unsatisfying in our opinion, so we've decided (based
+on knowledge and experiences with the old UHCI driver) to start 
+from scratch with a new approach, much simpler but at the same time more 
+powerful.
+It is inspired by the way Win98/Win2000 handles USB requests via URBs,
+but it's definitely 100% free of MS-code and doesn't crash while 
+unplugging an used ISO-device like Win98 ;-)
+Some code for HW setup and root hub management was taken from the 
+original UHCI driver, but heavily modified to fit into the new code.
+The invention of the basic concept, and major coding were completed in two 
+days (and nights) on the 16th and 17th of October 1999, now known as the
+great USB-October-Revolution started by GA, DF, and TS ;-)
+
+Since the concept is in no way UHCI dependant, we hope that it will also be 
+transfered to the OHCI-driver, so both drivers share a common API.
+
+1.2. Advantages and disadvantages
+
++ All USB transfer types work now!
++ Asynchronous operation
++ Simple, but powerful interface (only two calls for start and cancel)
++ Easy migration to the new API, simplified by a compatibility API
++ Simple usage of ISO transfers
++ Automatic linking of requests
++ ISO transfers allow variable length for each frame and striping
++ No CPU dependent and non-portable atomic memory access, no asm()-inlines
++ Tested on x86 and Alpha
+
+- Rewriting for ISO transfers needed
+
+1.3. Is there some compatibility to the old API?
+
+Yes, but only for control, bulk and interrupt transfers. We've implemented 
+some wrapper calls for these transfer types. The usbcore works fine with 
+these wrappers. For ISO there's no compatibility, because the old ISO-API 
+and its semantics were unnecessary complicated in our opinion.
+
+1.4. What's really working?
+
+As said above, CTRL und BULK already work fine even with the wrappers,
+so legacy code wouldn't notice the change.
+Regarding to Thomas, ISO transfers now run stable with USB audio.
+INT transfers (e.g. mouse driver) work fine, too.
+
+1.5. Are there any bugs?
+
+No ;-)
+Hm...
+Well, of course this implementation needs extensive testing on all available
+hardware, but we believe that any fixes shouldn't harm the overall concept.
+
+1.6. What should be done next?
+
+A large part of the request handling seems to be identical for UHCI and 
+OHCI, so it would be a good idea to extract the common parts and have only 
+the HW specific stuff in uhci.c. Furthermore, all other USB device drivers
+should need URBification, if they use isochronous or interrupt transfers.
+One thing missing in the current implementation (and the old UHCI driver) 
+is fair queueing for BULK transfers. Since this would need (in principle) 
+the alteration of already constructed TD chains (to switch from depth to 
+breadth execution), another way has to be found. Maybe some simple 
+heuristics work with the same effect.
+
+---------------------------------------------------------------------------
+
+2. Internal structure and mechanisms
+
+To get quickly familiar with the internal structures, here's a short
+description how the new UHCI driver works. However, the ultimate source of
+truth is only uhci.c!
+
+2.1. Descriptor structure (QHs and TDs)
+
+During initialization, the following skeleton is allocated in init_skel:
+
+	 framespecific           |           common chain     
+
+framelist[]
+[  0 ]-----> TD --> TD -------\
+[  1 ]-----> TD --> TD --------> TD ----> QH -------> QH -------> QH ---> NULL
+  ...        TD --> TD -------/
+[1023]-----> TD --> TD ------/
+	     
+	     ^^     ^^           ^^       ^^          ^^          ^^
+   1024 TDs for   7 TDs for    1 TD for   Start of    Start of    End Chain
+	    ISO  INT (2-128ms) 1ms-INT    CTRL Chain  BULK Chain
+
+For each CTRL or BULK transfer a new QH is allocated and the containing data
+transfers are appended as (vertical) TDs. After building the whole QH with its
+dangling TDs, the QH is inserted before the BULK Chain QH (for CTRL) or
+before the End Chain QH (for BULK). Since only the QH->next pointers are
+affected, no atomic memory operation is required. The three QHs in the
+common chain are never equipped with TDs!
+
+For ISO or INT, the TD for each frame is simply inserted into the apropriate
+ISO/INT-TD-chain for the desired frame. The 7 skeleton INT-TDs are scattered
+among the 1024 frames similar to the old UHCI driver.
+
+For CTRL/BULK/ISO, the last TD in the transfer has the IOC-bit set. For INT,
+every TD (there is only one...) has the IOC-bit set.
+
+Besides the data for the UHCI controller (2 or 4 32bit words), the descriptors
+are double-linked through the .vertical and .horizontal elements in the 
+SW data of the descriptor (using the double-linked list structures and 
+operations), but SW-linking occurs only in closed domains, i.e. for each of
+the 1024 ISO-chains and the 8 INT-chains there is a closed cycle. This 
+simplifies all insertions and unlinking operations and avoids costly 
+bus_to_virt()-calls.
+
+2.2. URB structure and linking to QH/TDs
+
+During assembly of the QH and TDs of the requested action, these descriptors
+are stored in urb->urb_list, so the allocated QH/TD descriptors are bound to
+this URB.
+If the assembly was successful and the descriptors were added to the HW chain,
+the corresponding URB is inserted into a global URB list for this controller.
+This list stores all pending URBs.
+
+2.3. Interrupt processing
+
+Since UHCI provides no means to directly detect completed transactions, the
+following is done in each UHCI interrupt (uhci_interrupt()):
+
+For each URB in the pending queue (process_urb()), the ACTIVE-flag of the 
+associated TDs are processed (depending on the transfer type 
+process_{transfer|interrupt|iso}()). If the TDs are not active anymore, 
+they indicate the completion of the transaction and the status is calculated. 
+Inactive QH/TDs are removed from the HW chain (since the host controller
+already removed the TDs from the QH, no atomic access is needed) and 
+eventually the URB is marked as completed (OK or errors) and removed from the 
+pending queue. Then the next linked URB is submitted. After (or immediately 
+before) that, the completion handler is called.
+
+2.4. Unlinking URBs
+
+First, all QH/TDs stored in the URB are unlinked from the HW chain. 
+To ensure that the host controller really left a vertical TD chain, we 
+wait for one frame. After that, the TDs are physically destroyed.
+
+2.5. URB linking and the consequences
+
+Since URBs can be linked and the corresponding submit_urb is called in
+the UHCI-interrupt, all work associated with URB/QH/TD assembly has to be
+interrupt save. This forces kmalloc to use GFP_ATOMIC in the interrupt.
diff -u --recursive --new-file v2.3.36/linux/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt
--- v2.3.36/linux/Documentation/usb/usb-serial.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/usb-serial.txt	Tue Jan  4 16:12:59 2000
@@ -0,0 +1,42 @@
+This serial driver currently only works with the Belkin and Peracom USB 
+Serial devices. It should also work for the Etek converter, but I do 
+not know the vendor id and device id of that device (if anyone does, 
+please let me know.)
+
+If your device is not compatible with the above models, you can try
+out the "generic" interface. This interface does not provide any type
+of control messages sent to the device, and does not support any kind
+of device flow control. All that is required of your device is that
+it has at least one bulk in endpoint, or one bulk out endpoint.
+To enable the driver to recognize your device, build the driver as
+a module and load it by the following invocation:
+	insmod usb-serial.o vendor=0x#### product=0x####
+where the #### is replaced with the hex representation of your device's
+vendor id and product id.
+
+The driver can handle enumerating the device, and sending and receiving
+data from the converter. However, since I do not have a spec for the Belkin,
+Peracom, and eTek devices, and the raw dumps from the Win98 driver are 
+confusing, and eTek keeps giving me the run around, no control signals are 
+currently handled, and the data will most likely come through on a baud
+rate that you are not expecting. So if you have these devices, do not 
+expect the correct data to show up at either end. 
+
+The major number that the driver uses is 188 so to use the driver, create
+the following nodes:
+mknod /dev/ttyUSB0 c 188 0
+mknod /dev/ttyUSB1 c 188 1
+mknod /dev/ttyUSB2 c 188 2
+mknod /dev/ttyUSB3 c 188 3
+
+then plug in a device and use your friendly terminal program to see what
+happens.
+
+If anyone has any problems getting the device to enumerate, or data to 
+flow through it, please contact me.
+
+
+
+greg k-h
+greg@kroah.com
+
diff -u --recursive --new-file v2.3.36/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.36/linux/MAINTAINERS	Tue Jan  4 13:57:16 2000
+++ linux/MAINTAINERS	Thu Jan  6 10:23:46 2000
@@ -192,7 +192,7 @@
 
 CIRRUS LOGIC GENERIC FBDEV DRIVER
 P:	Jeff Garzik
-M:	jgarzik@pobox.com
+M:	jgarzik@mandrakesoft.com
 L:	linux-fbdev@vuser.vu.union.edu
 S:	Maintained
 
@@ -996,7 +996,7 @@
 
 VIA 82Cxxx AUDIO DRIVER
 P:	Jeff Garzik
-M:	jgarzik@pobox.com
+M:	jgarzik@mandrakesoft.com
 S:	Maintained
 
 VIDEO FOR LINUX
diff -u --recursive --new-file v2.3.36/linux/Makefile linux/Makefile
--- v2.3.36/linux/Makefile	Tue Jan  4 13:57:16 2000
+++ linux/Makefile	Thu Jan  6 12:36:34 2000
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 36
+SUBLEVEL = 37
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -343,6 +343,18 @@
 fs lib mm ipc kernel drivers net: dummy
 	$(MAKE) $(subst $@, _dir_$@, $@)
 
+TAGS: dummy
+	etags `find include/asm-$(ARCH) -name '*.h'`
+	find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs etags -a
+	find $(SUBDIRS) init -name '*.c' | xargs etags -a
+
+# Exuberant ctags works better with -I 
+tags: dummy
+	CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__initlocaldata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_NOVERS"`; \
+	ctags $$CTAGSF `find include/asm-$(ARCH) -name '*.h'` && \
+	find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs ctags $$CTAGSF -a && \
+	find $(SUBDIRS) init -name '*.c' | xargs ctags $$CTAGSF -a
+
 MODFLAGS = -DMODULE
 ifdef CONFIG_MODULES
 ifdef CONFIG_MODVERSIONS
@@ -446,7 +458,7 @@
 distclean: mrproper
 	rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
 		-o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
-		-o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS
+		-o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS tags
 
 backup: mrproper
 	cd .. && tar cf - linux/ | gzip -9 > backup.gz
diff -u --recursive --new-file v2.3.36/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.3.36/linux/arch/alpha/kernel/osf_sys.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/alpha/kernel/osf_sys.c	Thu Jan  6 10:14:36 2000
@@ -43,15 +43,9 @@
 #include <asm/hwrpb.h>
 #include <asm/processor.h>
 
-extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
+extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
 extern int do_pipe(int *);
 
-extern struct file_operations *get_blkfops(unsigned int);
-extern struct file_operations *get_chrfops(unsigned int);
-
-extern kdev_t get_unnamed_dev(void);
-extern void put_unnamed_dev(kdev_t);
-
 extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags);
 extern asmlinkage unsigned long sys_brk(unsigned long);
 
@@ -400,18 +394,16 @@
 	uid_t exroot;
 };
 
-static int getdev(const char *name, int rdonly, struct dentry **dp)
+static struct dentry *getdev(const char *name, int rdonly)
 {
-	kdev_t dev;
 	struct dentry *dentry;
 	struct inode *inode;
-	struct file_operations *fops;
 	int retval;
 
 	dentry = namei(name);
 	retval = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
-		return retval;
+		return dentry;
 
 	retval = -ENOTBLK;
 	inode = dentry->d_inode;
@@ -421,48 +413,20 @@
 	retval = -EACCES;
 	if (IS_NODEV(inode))
 		goto out_dput;
-
-	retval = -ENXIO;
-	dev = inode->i_rdev;
-	if (MAJOR(dev) >= MAX_BLKDEV)
-		goto out_dput;
-
-	retval = -ENODEV;
-	fops = get_blkfops(MAJOR(dev));
-	if (!fops)
-		goto out_dput;
-	if (fops->open) {
-		struct file dummy;
-		memset(&dummy, 0, sizeof(dummy));
-		dummy.f_dentry = dentry;
-		dummy.f_mode = rdonly ? 1 : 3;
-		retval = fops->open(inode, &dummy);
-		if (retval)
-			goto out_dput;
-	}
-	*dp = dentry;
-	retval = 0;
-out:
-	return retval;
+	return dentry;
 
 out_dput:
 	dput(dentry);
-	goto out;
-}
-
-static void putdev(struct dentry *dentry)
-{
-	struct file_operations *fops;
-
-	fops = get_blkfops(MAJOR(dentry->d_inode->i_rdev));
-	if (fops->release)
-		fops->release(dentry->d_inode, NULL);
+	return ERR_PTR(retval);
 }
 
 /*
  * We can't actually handle ufs yet, so we translate UFS mounts to
  * ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS
  * layout is so braindead it's a major headache doing it.
+ *
+ * Just how long ago was it written? OTOH our UFS driver may be still
+ * unhappy with OSF UFS. [CHECKME]
  */
 static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags)
 {
@@ -474,13 +438,12 @@
 	if (copy_from_user(&tmp, args, sizeof(tmp)))
 		goto out;
 
-	retval = getdev(tmp.devname, 0, &dentry);
-	if (retval)
+	dentry = getdev(tmp.devname, 0);
+	retval = PTR_ERR(dentry);
+	if (IS_ERR(dentry)
 		goto out;
-	retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname, 
+	retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname, 
 				"ext2", flags, NULL);
-	if (retval)
-		putdev(dentry);
 	dput(dentry);
 out:
 	return retval;
@@ -496,13 +459,12 @@
 	if (copy_from_user(&tmp, args, sizeof(tmp)))
 		goto out;
 
-	retval = getdev(tmp.devname, 1, &dentry);
-	if (retval)
+	dentry = getdev(tmp.devname, 1);
+	retval = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		goto out;
-	retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname, 
+	retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname, 
 				"iso9660", flags, NULL);
-	if (retval)
-		putdev(dentry);
 	dput(dentry);
 out:
 	return retval;
@@ -510,19 +472,12 @@
 
 static int osf_procfs_mount(char *dirname, struct procfs_args *args, int flags)
 {
-	kdev_t dev;
 	int retval;
 	struct procfs_args tmp;
 
 	if (copy_from_user(&tmp, args, sizeof(tmp)))
 		return -EFAULT;
-	dev = get_unnamed_dev();
-	if (!dev)
-		return -ENODEV;
-	retval = do_mount(dev, "", dirname, "proc", flags, NULL);
-	if (retval)
-		put_unnamed_dev(dev);
-	return retval;
+	return do_mount(NULL, "", dirname, "proc", flags, NULL);
 }
 
 asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data)
diff -u --recursive --new-file v2.3.36/linux/arch/alpha/kernel/sys_sio.c linux/arch/alpha/kernel/sys_sio.c
--- v2.3.36/linux/arch/alpha/kernel/sys_sio.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/alpha/kernel/sys_sio.c	Thu Jan  6 09:54:06 2000
@@ -141,7 +141,7 @@
 	struct pci_dev *dev;
 
 	/* Iterate through the devices, collecting IRQ levels.  */
-	for (dev = pci_devices; dev; dev = dev->next) {
+	pci_for_each_dev(dev) {
 		if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) &&
 		    (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA))
 			continue;
diff -u --recursive --new-file v2.3.36/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c
--- v2.3.36/linux/arch/arm/kernel/bios32.c	Tue Dec 14 01:27:23 1999
+++ linux/arch/arm/kernel/bios32.c	Thu Jan  6 09:54:06 2000
@@ -24,7 +24,7 @@
 {
 	struct pci_dev *dev;
 
-	for (dev = pci_devices; dev; dev = dev->next) {
+	pci_for_each_dev(dev) {
 		u16 status;
 
 		pci_read_config_word(dev, PCI_STATUS, &status);
@@ -121,11 +121,12 @@
 	struct pci_dev *dev;
 	int idx;
 
-	for (dev = pci_devices; dev; dev = dev->next)
+	pci_for_each_dev(dev) {
 		for (idx = 0; idx < PCI_NUM_RESOURCES; idx++)
 			if (dev->resource[idx].flags &&
 			    dev->resource[idx].start)
 				pci_claim_resource(dev, idx);
+	}
 }
 
 void __init
diff -u --recursive --new-file v2.3.36/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.3.36/linux/arch/i386/boot/setup.S	Tue Dec  7 09:32:40 1999
+++ linux/arch/i386/boot/setup.S	Tue Jan  4 18:28:26 2000
@@ -202,9 +202,9 @@
 	xorb	%bh, %bh
 	movb	(497), %bl			# get setup sect from bootsect
 	subw	$4, %bx				# LILO loads 4 sectors of setup
-	shlw	$7, %bx				# convert to dwords (1sect=2^7 dwords)
+	shlw	$8, %bx				# convert to words (1sect=2^8 words)
 	movw	%bx, %cx
-	shrw	$2, %bx				# convert to segment
+	shrw	$3, %bx				# convert to segment
 	addw	$SYSSEG, %bx
 	movw	%bx, %cs:start_sys_seg
 # Move rest of setup code/data to here
diff -u --recursive --new-file v2.3.36/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.36/linux/arch/i386/config.in	Tue Jan  4 13:57:16 2000
+++ linux/arch/i386/config.in	Thu Jan  6 10:16:48 2000
@@ -120,6 +120,12 @@
 source drivers/parport/Config.in
 
 bool 'ACPI support' CONFIG_ACPI
+if [ "$CONFIG_ACPI" != "n" ]; then
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+     bool '  Enter S1 for sleep' CONFIG_ACPI_S1_SLEEP
+   fi
+fi
+
 bool 'Advanced Power Management BIOS support' CONFIG_APM
 if [ "$CONFIG_APM" != "n" ]; then
    bool '  Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
diff -u --recursive --new-file v2.3.36/linux/arch/i386/kernel/acpi.c linux/arch/i386/kernel/acpi.c
--- v2.3.36/linux/arch/i386/kernel/acpi.c	Wed Dec 29 13:13:12 1999
+++ linux/arch/i386/kernel/acpi.c	Thu Jan  6 10:16:48 2000
@@ -25,6 +25,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/string.h>
 #include <linux/miscdevice.h>
 #include <linux/sched.h>
 #include <linux/time.h>
@@ -120,6 +121,9 @@
 static int acpi_p_lvl2_tested = 0;
 static int acpi_p_lvl3_tested = 0;
 
+static int acpi_disabled = 0;
+int acpi_active = 0;
+
 // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
 static unsigned long acpi_slp_typ[] = 
 {
@@ -1146,8 +1150,10 @@
 	}
 	else
 	{
+#ifdef CONFIG_ACPI_S1_SLEEP
 		acpi_enter_sx(ACPI_S1);
 		acpi_enter_sx(ACPI_S0);
+#endif
 	}
 	file->f_pos += *len;
 	return 0;
@@ -1160,29 +1166,30 @@
 {
 	int pid;
 
+	if (acpi_disabled)
+		return -ENODEV;
+
 	if (acpi_find_tables() && acpi_find_piix4()) {
 		// no ACPI tables and not PIIX4
 		return -ENODEV;
 	}
 
     	/*
-    	 * Are the latencies in uS or in ticks in the tables? 
-    	 * Maybe this should do ACPI_uS_TO_TMR_TICKS?
-    	 *
-    	 * Whatever. Internally we always keep them in timer
+    	 * Internally we always keep latencies in timer
     	 * ticks, which is simpler and more consistent (what is
     	 * an uS to us?). Besides, that gives people more
     	 * control in the /proc interfaces.
     	 */
 	if (acpi_facp->p_lvl2_lat
 	    && acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
-		acpi_p_lvl2_lat = acpi_facp->p_lvl2_lat;
-		acpi_enter_lvl2_lat = ACPI_TMR_HZ / 1000;
+		acpi_p_lvl2_lat = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl2_lat);
+		acpi_enter_lvl2_lat = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000);
 	}
 	if (acpi_facp->p_lvl3_lat
 	    && acpi_facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
-		acpi_p_lvl3_lat = acpi_facp->p_lvl3_lat;
-		acpi_enter_lvl3_lat = acpi_facp->p_lvl3_lat * 5;
+		acpi_p_lvl3_lat = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat);
+		acpi_enter_lvl3_lat
+			= ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat * 5);
 	}
 
 	if (acpi_facp->sci_int
@@ -1206,6 +1213,8 @@
 
 	acpi_power_off = acpi_power_off_handler;
 
+	acpi_active = 1;
+
 	/*
 	 * Set up the ACPI idle function. Note that we can't really
 	 * do this with multiple CPU's, we'd need a per-CPU ACPI
@@ -1239,6 +1248,22 @@
 
 	acpi_destroy_tables();
 }
+
+static int __init acpi_setup(char *str)
+{
+	while (str && *str) {
+		if (strncmp(str, "off", 3) == 0)
+			acpi_disabled = 1;
+		else if (strncmp(str, "on", 2) == 0)
+			acpi_disabled = 0;
+		str = strpbrk(str, ",");
+		if (str)
+			str += strspn(str, ",");
+	}
+	return 1;
+}
+
+__setup("acpi=", acpi_setup);
 
 /*
  * Register a device with the ACPI subsystem
diff -u --recursive --new-file v2.3.36/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- v2.3.36/linux/arch/i386/kernel/apm.c	Mon Dec 20 18:48:21 1999
+++ linux/arch/i386/kernel/apm.c	Thu Jan  6 10:16:48 2000
@@ -1491,6 +1491,13 @@
 		APM_INIT_ERROR_RETURN;
 	}
 
+#ifdef CONFIG_ACPI
+	if (acpi_active) {
+		printk(KERN_NOTICE "apm: overridden by ACPI.\n");
+		APM_INIT_ERROR_RETURN;
+	}
+#endif
+
 	/*
 	 * Set up a segment that references the real mode segment 0x40
 	 * that extends up to the end of page zero (that we have reserved).
diff -u --recursive --new-file v2.3.36/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.3.36/linux/arch/i386/kernel/i386_ksyms.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/i386/kernel/i386_ksyms.c	Wed Jan  5 10:51:40 2000
@@ -56,6 +56,9 @@
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
 EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
+EXPORT_SYMBOL_NOVERS(__down_write_failed);
+EXPORT_SYMBOL_NOVERS(__down_read_failed);
+EXPORT_SYMBOL_NOVERS(__rwsem_wake);
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
 EXPORT_SYMBOL(csum_partial_copy_generic);
diff -u --recursive --new-file v2.3.36/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.3.36/linux/arch/i386/kernel/irq.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/i386/kernel/irq.c	Wed Jan  5 17:42:08 2000
@@ -707,9 +707,11 @@
 			}
 			spin_unlock_irqrestore(&irq_controller_lock,flags);
 
+#ifdef __SMP__
 			/* Wait to make sure it's not being used on another CPU */
 			while (irq_desc[irq].status & IRQ_INPROGRESS)
 				barrier();
+#endif
 			kfree(action);
 			return;
 		}
diff -u --recursive --new-file v2.3.36/linux/arch/i386/kernel/pci-i386.c linux/arch/i386/kernel/pci-i386.c
--- v2.3.36/linux/arch/i386/kernel/pci-i386.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/i386/kernel/pci-i386.c	Thu Jan  6 09:54:06 2000
@@ -12,7 +12,7 @@
  *	Hannover, Germany
  *	hm@ix.de
  *
- * Copyright 1997--1999 Martin Mares <mj@suse.cz>
+ * Copyright 1997--2000 Martin Mares <mj@suse.cz>
  *
  * For more information, please consult the following manuals (look at
  * http://www.pcisig.com/ for how to get them):
@@ -180,14 +180,17 @@
  *	    as well.
  */
 
-static void __init pcibios_allocate_bus_resources(struct pci_bus *bus)
+static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
 {
+	struct list_head *ln;
+	struct pci_bus *bus;
 	struct pci_dev *dev;
 	int idx;
 	struct resource *r, *pr;
 
 	/* Depth-First Search on bus tree */
-	while (bus) {
+	for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+		bus = pci_bus_b(ln);
 		if ((dev = bus->self)) {
 			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
 				r = &dev->resource[idx];
@@ -198,9 +201,7 @@
 					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
 			}
 		}
-		if (bus->children)
-			pcibios_allocate_bus_resources(bus->children);
-		bus = bus->next;
+		pcibios_allocate_bus_resources(&bus->children);
 	}
 }
 
@@ -211,7 +212,7 @@
 	u16 command;
 	struct resource *r, *pr;
 
-	for(dev=pci_devices; dev; dev=dev->next) {
+	pci_for_each_dev(dev) {
 		pci_read_config_word(dev, PCI_COMMAND, &command);
 		for(idx = 0; idx < 6; idx++) {
 			r = &dev->resource[idx];
@@ -255,7 +256,7 @@
 	int idx;
 	struct resource *r;
 
-	for(dev=pci_devices; dev; dev=dev->next) {
+	pci_for_each_dev(dev) {
 		int class = dev->class >> 8;
 
 		/* Don't touch classless devices and host bridges */
@@ -293,7 +294,8 @@
 
 void __init pcibios_resource_survey(void)
 {
-	pcibios_allocate_bus_resources(pci_root);
+	DBG("PCI: Allocating resources\n");
+	pcibios_allocate_bus_resources(&pci_root_buses);
 	pcibios_allocate_resources(0);
 	pcibios_allocate_resources(1);
 	pcibios_assign_resources();
diff -u --recursive --new-file v2.3.36/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c
--- v2.3.36/linux/arch/i386/kernel/pci-pc.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/i386/kernel/pci-pc.c	Thu Jan  6 09:54:06 2000
@@ -1,7 +1,7 @@
 /*
  *	Low-Level PCI Support for PC
  *
- *	(c) 1999 Martin Mares <mj@suse.cz>
+ *	(c) 1999--2000 Martin Mares <mj@suse.cz>
  */
 
 #include <linux/config.h>
@@ -22,6 +22,8 @@
 
 unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
 
+static struct pci_bus *pci_root_bus;
+
 /*
  * IRQ routing table provided by the BIOS
  */
@@ -624,26 +626,31 @@
 
 static void __init pcibios_sort(void)
 {
-	struct pci_dev *dev = pci_devices;
-	struct pci_dev **last = &pci_devices;
-	struct pci_dev *d, **dd, *e;
-	int idx;
+	LIST_HEAD(sorted_devices);
+	struct list_head *ln;
+	struct pci_dev *dev, *d;
+	int idx, found;
 	unsigned char bus, devfn;
 
 	DBG("PCI: Sorting device list...\n");
-	while ((e = dev)) {
-		idx = 0;
-		while (pci_bios_find_device(e->vendor, e->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
+	while (pci_devices.next != &pci_devices) {
+		ln = pci_devices.next;
+		list_del(ln);
+		dev = pci_dev_g(ln);
+		idx = found = 0;
+		while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
 			idx++;
-			for(dd=&dev; (d = *dd); dd = &d->next) {
+			for (ln=pci_devices.next; ln != &pci_devices; ln=ln->next) {
+				d = pci_dev_g(ln);
 				if (d->bus->number == bus && d->devfn == devfn) {
-					*dd = d->next;
-					*last = d;
-					last = &d->next;
+					list_del(&d->global_list);
+					list_add_tail(&d->global_list, &sorted_devices);
+					if (d == dev)
+						found = 1;
 					break;
 				}
 			}
-			if (!d) {
+			if (ln == &pci_devices) {
 				printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
 				/*
 				 * We must not continue scanning as several buggy BIOSes
@@ -652,16 +659,14 @@
 				break;
 			}
 		}
-		if (e == dev) {
+		if (!found) {
 			printk("PCI: Device %02x:%02x not found by BIOS\n",
 				dev->bus->number, dev->devfn);
-			d = dev;
-			dev = dev->next;
-			*last = d;
-			last = &d->next;
+			list_del(&dev->global_list);
+			list_add_tail(&dev->global_list, &sorted_devices);
 		}
 	}
-	*last = NULL;
+	list_splice(&sorted_devices, &pci_devices);
 }
 
 /*
@@ -736,16 +741,19 @@
 
 static void __init pcibios_fixup_ghosts(struct pci_bus *b)
 {
-	struct pci_dev *d, *e, **z;
+	struct list_head *ln, *mn;
+	struct pci_dev *d, *e;
 	int mirror = PCI_DEVFN(16,0);
 	int seen_host_bridge = 0;
 	int i;
 
 	DBG("PCI: Scanning for ghost devices on bus %d\n", b->number);
-	for(d=b->devices; d && d->devfn < mirror; d=d->sibling) {
+	for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
+		d = pci_dev_b(ln);
 		if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
 			seen_host_bridge++;
-		for(e=d->next; e; e=e->sibling) {
+		for (mn=ln->next; mn != &b->devices; mn=mn->next) {
+			e = pci_dev_b(mn);
 			if (e->devfn != d->devfn + mirror ||
 			    e->vendor != d->vendor ||
 			    e->device != d->device ||
@@ -758,20 +766,23 @@
 					continue;
 			break;
 		}
-		if (!e)
+		if (mn == &b->devices)
 			return;
 	}
 	if (!seen_host_bridge)
 		return;
 	printk("PCI: Ignoring ghost devices on bus %02x\n", b->number);
-	for(e=b->devices; e->sibling != d; e=e->sibling);
-	e->sibling = NULL;
-	for(z=&pci_devices; (d=*z);)
-		if (d->bus == b && d->devfn >= mirror) {
-			*z = d->next;
-			kfree_s(d, sizeof(*d));
+
+	ln = &b->devices;
+	while (ln->next != &b->devices) {
+		d = pci_dev_b(ln->next);
+		if (d->devfn >= mirror) {
+			list_del(&d->global_list);
+			list_del(&d->bus_list);
+			kfree(d);
 		} else
-			z = &d->next;
+			ln = ln->next;
+	}
 }
 
 /*
@@ -783,10 +794,10 @@
  */
 static void __init pcibios_fixup_peer_bridges(void)
 {
-	struct pci_bus *b = pci_root;
+	struct list_head *ln;
+	struct pci_bus *b = pci_root_bus;
 	int n, cnt=-1;
-	struct pci_dev *d;
-	struct pci_ops *ops = pci_root->ops;
+	struct pci_ops *ops = pci_root_bus->ops;
 
 #ifdef CONFIG_PCI_DIRECT
 	/*
@@ -798,8 +809,10 @@
 		return;
 #endif
 
-	for(d=b->devices; d; d=d->sibling)
-		if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+	DBG("PCI: Peer bridge fixup\n");
+
+	for(ln=b->devices.next; ln != &b->devices; ln=ln->next)
+		if ((pci_dev_b(ln)->class >> 8) == PCI_CLASS_BRIDGE_HOST)
 			cnt++;
 	n = b->subordinate + 1;
 	while (n <= 0xff) {
@@ -864,9 +877,9 @@
 		pci_read_config_byte(d, reg++, &subb);
 		DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
 		if (busno)
-			pci_scan_bus(busno, pci_root->ops, NULL);	/* Bus A */
+			pci_scan_bus(busno, pci_root_bus->ops, NULL);	/* Bus A */
 		if (suba < subb)
-			pci_scan_bus(suba+1, pci_root->ops, NULL);	/* Bus B */
+			pci_scan_bus(suba+1, pci_root_bus->ops, NULL);	/* Bus B */
 	}
 }
 
@@ -879,7 +892,7 @@
 	u8 busno;
 	pci_read_config_byte(d, 0x44, &busno);
 	printk("PCI: RCC host bridge: secondary bus %02x\n", busno);
-	pci_scan_bus(busno, pci_root->ops, NULL);
+	pci_scan_bus(busno, pci_root_bus->ops, NULL);
 }
 
 static void __init pci_fixup_compaq(struct pci_dev *d)
@@ -891,7 +904,7 @@
 	u8 busno;
 	pci_read_config_byte(d, 0xc8, &busno);
 	printk("PCI: Compaq host bridge: secondary bus %02x\n", busno);
-	pci_scan_bus(busno, pci_root->ops, NULL);
+	pci_scan_bus(busno, pci_root_bus->ops, NULL);
 }
 
 static void __init pci_fixup_umc_ide(struct pci_dev *d)
@@ -1000,7 +1013,7 @@
 		 *  It might be a secondary bus, but in this case its parent is already
 		 *  known (ascending bus order) and therefore pci_scan_bus returns immediately.
 		 */
-		if (busmap[i] && pci_scan_bus(i, pci_root->ops, NULL))
+		if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL))
 			printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i);
 }
 
@@ -1063,7 +1076,6 @@
 	case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0):
 	case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0):
 	case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0):
-	case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533):
 		/* Intel PIIX: PIRQ holds configuration register address */
 		pci_read_config_byte(router, pirq, &x);
 		if (x < 16) {
@@ -1078,6 +1090,7 @@
 		}
 		DBG(" -> [PIIX] sink\n");
 		return NULL;
+	case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533):
 	default:
 		DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device);
 		if (newirq && mask == (1 << newirq)) {
@@ -1096,6 +1109,7 @@
 	struct pci_dev *dev;
 	u8 pin;
 
+	DBG("PCI: IRQ fixup\n");
 	rtable = pirq_table = pcibios_find_irq_routing_table();
 #ifdef CONFIG_PCI_BIOS
 	if (!rtable && pci_bios_present)
@@ -1105,7 +1119,7 @@
 	if (rtable)
 		pcibios_irq_peer_trick(rtable);
 
-	for(dev=pci_devices; dev; dev=dev->next) {
+	pci_for_each_dev(dev) {
 		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 #if defined(CONFIG_X86_IO_APIC)
 		/*
@@ -1198,7 +1212,7 @@
 	}
 
 	printk("PCI: Probing PCI hardware\n");
-	pci_scan_bus(0, ops, NULL);
+	pci_root_bus = pci_scan_bus(0, ops, NULL);
 
 	pcibios_fixup_irqs();
 	if (pci_probe & PCI_PEER_FIXUP)
diff -u --recursive --new-file v2.3.36/linux/arch/i386/kernel/pci-visws.c linux/arch/i386/kernel/pci-visws.c
--- v2.3.36/linux/arch/i386/kernel/pci-visws.c	Tue Dec  7 09:32:40 1999
+++ linux/arch/i386/kernel/pci-visws.c	Thu Jan  6 09:54:06 2000
@@ -1,7 +1,7 @@
 /*
  *	Low-Level PCI Support for SGI Visual Workstation
  *
- *	(c) 1999 Martin Mares <mj@suse.cz>
+ *	(c) 1999--2000 Martin Mares <mj@suse.cz>
  */
 
 #include <linux/config.h>
@@ -85,7 +85,7 @@
 	u8 pin;
 	int irq;
 
-	for(dev=pci_devices; dev; dev=dev->next) {
+	pci_for_each_dev(dev) {
 		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 		dev->irq = 0;
 		if (!pin)
diff -u --recursive --new-file v2.3.36/linux/arch/m68k/kernel/bios32.c linux/arch/m68k/kernel/bios32.c
--- v2.3.36/linux/arch/m68k/kernel/bios32.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/m68k/kernel/bios32.c	Thu Jan  6 09:54:06 2000
@@ -449,69 +449,6 @@
 
 #endif /* !PCI_MODIFY */
 
-/*
- * Given the vendor and device ids, find the n'th instance of that device
- * in the system.
- */
-
-int pcibios_find_device(unsigned short vendor, unsigned short device_id,
-			unsigned short index, unsigned char *bus,
-			unsigned char *devfn)
-{
-	unsigned int curr = 0;
-	struct pci_dev *dev;
-
-	for (dev = pci_devices; dev; dev = dev->next)
-	{
-		if (dev->vendor == vendor && dev->device == device_id)
-		{
-			if (curr == index)
-			{
-				*devfn = dev->devfn;
-				*bus = dev->bus->number;
-				return PCIBIOS_SUCCESSFUL;
-			}
-			++curr;
-		}
-	}
-	return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-/*
- * Given the class, find the n'th instance of that device
- * in the system.
- */
-
-int pcibios_find_class(unsigned int class_code, unsigned short index,
-		       unsigned char *bus, unsigned char *devfn)
-{
-	unsigned int curr = 0;
-	struct pci_dev *dev;
-
-	for (dev = pci_devices; dev; dev = dev->next)
-	{
-		if (dev->class == class_code)
-		{
-			if (curr == index)
-			{
-				*devfn = dev->devfn;
-				*bus = dev->bus->number;
-				return PCIBIOS_SUCCESSFUL;
-			}
-			++curr;
-		}
-	}
-	return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-int pcibios_present(void)
-{
-	if (MACH_IS_HADES)
-		return 1;
-	else
-		return 0;
-}
-
 void __init pcibios_init(void)
 {
 	printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
@@ -574,7 +511,7 @@
 	 * Scan the tree, allocating PCI memory and I/O space.
 	 */
 
-	layout_bus(&pci_root, orig_mem_base, orig_io_base);
+	layout_bus(pci_bus_b(pci_root.next), orig_mem_base, orig_io_base);
 
 	pci_mem_base = orig_mem_base;
 	pci_io_base = orig_io_base;
diff -u --recursive --new-file v2.3.36/linux/arch/mips/sni/pci.c linux/arch/mips/sni/pci.c
--- v2.3.36/linux/arch/mips/sni/pci.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/mips/sni/pci.c	Thu Jan  6 09:54:06 2000
@@ -30,7 +30,7 @@
 {
 	struct pci_dev *dev;
 
-	for (dev=pci_devices; dev; dev=dev->next) {
+	pci_for_each_dev(dev) {
 		/*
 		 * TODO: Take care of RM300 revision D boards for where the
 		 * network slot became an ordinary PCI slot.
diff -u --recursive --new-file v2.3.36/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c
--- v2.3.36/linux/arch/ppc/kernel/chrp_pci.c	Wed Oct 27 16:34:12 1999
+++ linux/arch/ppc/kernel/chrp_pci.c	Thu Jan  6 09:54:06 2000
@@ -282,8 +282,7 @@
 	}
 	
 	/* PCI interrupts are controlled by the OpenPIC */
-	for( dev=pci_devices ; dev; dev=dev->next )
-	{
+	pci_for_each_dev(dev) {
 		if ( dev->irq )
 			dev->irq = openpic_to_irq( dev->irq );
 		/* these need to be absolute addrs for OF and Matrox FB -- Cort */
diff -u --recursive --new-file v2.3.36/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.3.36/linux/arch/ppc/kernel/pci.c	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/pci.c	Thu Jan  6 09:54:06 2000
@@ -91,15 +91,17 @@
 	return start;
 }
 
-static void __init pcibios_claim_resources(struct pci_bus *bus)
+static void __init pcibios_claim_resources(struct list_head *bus_list)
 {
+	struct list_head *ln, *dn;
+	struct pci_bus *bus;
 	struct pci_dev *dev;
 	int idx;
 
-	while (bus)
-	{
-		for (dev=bus->devices; dev; dev=dev->sibling)
-		{
+	for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+		bus = pci_bus_b(ln);
+		for (dn=bus->devices.next; dn != &bus->devices; dn=dn->next) {
+			dev = pci_dev_b(dn);
 			for (idx = 0; idx < PCI_NUM_RESOURCES; idx++)
 			{
 				struct resource *r = &dev->resource[idx];
@@ -114,9 +116,7 @@
 				}
 			}
 		}
-		if (bus->children)
-			pcibios_claim_resources(bus->children);
-		bus = bus->next;
+		pcibios_claim_resources(&bus->children);
 	}
 }
 
diff -u --recursive --new-file v2.3.36/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c
--- v2.3.36/linux/arch/ppc/kernel/pmac_pci.c	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/pmac_pci.c	Thu Jan  6 09:54:06 2000
@@ -476,7 +476,7 @@
 	 *	  honor the existence of multi-function devices where
 	 *	  different functions have different interrupt pins. [mj]
 	 */
-	for(dev=pci_devices; dev; dev=dev->next)
+	pci_for_each_dev(dev)
 	{
 		/*
 		 * Open Firmware often doesn't initialize the,
diff -u --recursive --new-file v2.3.36/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- v2.3.36/linux/arch/ppc/kernel/prep_pci.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/prep_pci.c	Thu Jan  6 09:54:06 2000
@@ -998,7 +998,7 @@
 	printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
 	if (OpenPIC) {
 		/* PCI interrupts are controlled by the OpenPIC */
-		for(dev=pci_devices; dev; dev=dev->next) {
+		pci_for_each_dev(dev) {
 			if (dev->bus->number == 0) {
                        		dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
 				pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq);
@@ -1007,8 +1007,7 @@
 		return;
 	}
 
-	for(dev=pci_devices; dev; dev=dev->next)
-	{
+	pci_for_each_dev(dev) {
 		/*
 		 * Use our old hard-coded kludge to figure out what
 		 * irq this device uses.  This is necessary on things
diff -u --recursive --new-file v2.3.36/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.3.36/linux/arch/sparc/kernel/sys_sunos.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/sparc/kernel/sys_sunos.c	Thu Jan  6 10:14:36 2000
@@ -721,7 +721,7 @@
 };
 
 
-extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
+extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
 extern dev_t get_unnamed_dev(void);
 extern void put_unnamed_dev(dev_t);
 extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
@@ -797,7 +797,6 @@
 	char *the_name;
 	struct nfs_mount_data linux_nfs_mount;
 	struct sunos_nfs_mount_args *sunos_mount = data;
-	dev_t dev;
 
 	/* Ok, here comes the fun part: Linux's nfs mount needs a
 	 * socket connection to the server, but SunOS mount does not
@@ -839,13 +838,7 @@
 	linux_nfs_mount.hostname [255] = 0;
 	putname (the_name);
 	
-	dev = get_unnamed_dev ();
-	
-	ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
-	if (ret)
-	    put_unnamed_dev(dev);
-
-	return ret;
+	return do_mount (NULL, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
 }
 
 asmlinkage int
diff -u --recursive --new-file v2.3.36/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.3.36/linux/arch/sparc64/kernel/sys_sunos32.c	Wed Dec 29 13:13:14 1999
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Thu Jan  6 10:14:36 2000
@@ -685,7 +685,7 @@
 	char       *netname;   /* server's netname */
 };
 
-extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
+extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
 extern dev_t get_unnamed_dev(void);
 extern void put_unnamed_dev(dev_t);
 extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
@@ -767,7 +767,6 @@
 	char *the_name;
 	struct nfs_mount_data linux_nfs_mount;
 	struct sunos_nfs_mount_args *sunos_mount = data;
-	dev_t dev;
 
 	/* Ok, here comes the fun part: Linux's nfs mount needs a
 	 * socket connection to the server, but SunOS mount does not
@@ -809,13 +808,7 @@
 	linux_nfs_mount.hostname [255] = 0;
 	putname (the_name);
 
-	dev = get_unnamed_dev ();
-	
-	ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
-	if (ret)
-	    put_unnamed_dev(dev);
-
-	return ret;
+	return do_mount (NULL, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
 }
 
 /* XXXXXXXXXXXXXXXXXXXX */
diff -u --recursive --new-file v2.3.36/linux/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c
--- v2.3.36/linux/drivers/acorn/block/fd1772.c	Mon Aug  2 10:19:52 1999
+++ linux/drivers/acorn/block/fd1772.c	Wed Jan  5 07:01:22 2000
@@ -1350,10 +1350,6 @@
 static int fd_ioctl(struct inode *inode, struct file *filp,
 		    unsigned int cmd, unsigned long param)
 {
-#define IOCTL_MODE_BIT 8
-#define OPEN_WRITE_BIT 16
-#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
-
 	int drive, device;
 
 	device = inode->i_rdev;
@@ -1361,8 +1357,6 @@
 		RO_IOCTLS(inode->i_rdev, param);
 	}
 	drive = MINOR(device);
-	if (!IOCTL_ALLOWED)
-		return -EPERM;
 	switch (cmd) {
 	case FDFMTBEG:
 		return 0;
@@ -1544,12 +1538,6 @@
 	if (old_dev && old_dev != inode->i_rdev)
 		invalidate_buffers(old_dev);
 
-	/* Allow ioctls if we have write-permissions even if read-only open */
-	if (filp->f_mode & 2 || permission(inode, 2) == 0)
-		filp->f_mode |= IOCTL_MODE_BIT;
-	if (filp->f_mode & 2)
-		filp->f_mode |= OPEN_WRITE_BIT;
-
 	if (filp->f_flags & O_NDELAY)
 		return 0;
 
@@ -1570,12 +1558,9 @@
 {
 	int drive;
 
-	drive = inode->i_rdev & 3;
+	drive = MINOR(inode->i_rdev) & 3;
 
-	if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
-		/* if the file is mounted OR (writable now AND writable at open
-		   time) Linus: Does this cover all cases? */
-		block_fsync(inode, filp);
+	block_fsync(inode, filp);
 
 	if (fd_ref[drive] < 0)
 		fd_ref[drive] = 0;
diff -u --recursive --new-file v2.3.36/linux/drivers/block/alim15x3.c linux/drivers/block/alim15x3.c
--- v2.3.36/linux/drivers/block/alim15x3.c	Mon Dec 20 18:48:21 1999
+++ linux/drivers/block/alim15x3.c	Thu Jan  6 09:54:06 2000
@@ -609,23 +609,13 @@
 
 unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
 {
-	struct pci_dev *isa;
 	unsigned long fixdma_base = dev->resource[4].start;
 	byte tmpbyte;
 	unsigned long flags;
 
 	pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
 
-	for (isa = pci_devices; isa; isa=isa->next) {
-		/*
-		 * look for ISA bridge
-		 */
-		if (isa->vendor == PCI_VENDOR_ID_AL &&
-		    isa->device == PCI_DEVICE_ID_AL_M1533) {
-			isa_dev = isa;
-			break;
-		}
-	}
+	isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
 
 	if (!fixdma_base || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) {
 		/*
diff -u --recursive --new-file v2.3.36/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c
--- v2.3.36/linux/drivers/block/ataflop.c	Tue Dec 14 01:27:23 1999
+++ linux/drivers/block/ataflop.c	Wed Jan  5 07:01:22 2000
@@ -1559,10 +1559,6 @@
 static int fd_ioctl(struct inode *inode, struct file *filp,
 		    unsigned int cmd, unsigned long param)
 {
-#define IOCTL_MODE_BIT 8
-#define OPEN_WRITE_BIT 16
-#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
-
 	int drive, type;
 	kdev_t device;
 	struct atari_format_descr fmt_desc;
@@ -1616,8 +1612,6 @@
 			return -EFAULT;
 		return 0;
 	}
-	if (!IOCTL_ALLOWED)
-		return -EPERM;
 	switch (cmd) {
 	case FDSETPRM:
 	case FDDEFPRM:
@@ -1928,12 +1922,6 @@
 	if (old_dev && old_dev != MINOR(inode->i_rdev))
 		invalidate_buffers(MKDEV(FLOPPY_MAJOR, old_dev));
 
-	/* Allow ioctls if we have write-permissions even if read-only open */
-	if (filp->f_mode & 2 || permission (inode, 2) == 0)
-		filp->f_mode |= IOCTL_MODE_BIT;
-	if (filp->f_mode & 2)
-		filp->f_mode |= OPEN_WRITE_BIT;
-
 	if (filp->f_flags & O_NDELAY)
 		return 0;
 
@@ -1957,14 +1945,7 @@
 
 	drive = MINOR(inode->i_rdev) & 3;
 
-	/*
-	 * If filp is NULL, we're being called from blkdev_release
-	 * or after a failed mount attempt.  In the former case the
-	 * device has already been sync'ed, and in the latter no
-	 * sync is required.  Otherwise, sync if filp is writable.
-	 */
-	if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
-		block_fsync (filp, filp->f_dentry);
+	block_fsync (filp, filp->f_dentry);
 
 	if (fd_ref[drive] < 0)
 		fd_ref[drive] = 0;
diff -u --recursive --new-file v2.3.36/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.3.36/linux/drivers/block/floppy.c	Tue Dec 14 01:27:23 1999
+++ linux/drivers/block/floppy.c	Wed Jan  5 07:01:22 2000
@@ -3387,9 +3387,6 @@
 static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 		    unsigned long param)
 {
-#define IOCTL_MODE_BIT 8
-#define OPEN_WRITE_BIT 16
-#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
 #define OUT(c,x) case c: outparam = (const char *) (x); break
 #define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
 
@@ -3457,8 +3454,7 @@
 		return -EINVAL;
 
 	/* permission checks */
-	if (((cmd & 0x40) && !IOCTL_ALLOWED) ||
-	    ((cmd & 0x80) && !suser()))
+	if ((cmd & 0x80) && !suser())
 		return -EPERM;
 
 	/* copyin */
@@ -3578,7 +3574,6 @@
 		return fd_copyout((void *)param, outparam, size);
 	else
 		return 0;
-#undef IOCTL_ALLOWED
 #undef OUT
 #undef IN
 }
@@ -3630,53 +3625,13 @@
 		printk("\n");
 }
 
-static ssize_t floppy_read(struct file * filp, char *buf,
-			   size_t count, loff_t *ppos)
-{
-	struct inode *inode = filp->f_dentry->d_inode;
-	int drive = DRIVE(inode->i_rdev);
-
-	check_disk_change(inode->i_rdev);
-	if (UTESTF(FD_DISK_CHANGED))
-		return -ENXIO;
-	return block_read(filp, buf, count, ppos);
-}
-
-static ssize_t floppy_write(struct file * filp, const char * buf,
-			    size_t count, loff_t *ppos)
-{
-	struct inode * inode = filp->f_dentry->d_inode;
-	int block;
-	int ret;
-	int drive = DRIVE(inode->i_rdev);
-
-	if (!UDRS->maxblock)
-		UDRS->maxblock=1;/* make change detectable */
-	check_disk_change(inode->i_rdev);
-	if (UTESTF(FD_DISK_CHANGED))
-		return -ENXIO;
-	if (!UTESTF(FD_DISK_WRITABLE))
-		return -EROFS;
-	block = (*ppos + count) >> 9;
-	INFBOUND(UDRS->maxblock, block);
-	ret= block_write(filp, buf, count, ppos);
-	return ret;
-}
-
 static int floppy_release(struct inode * inode, struct file * filp)
 {
 	int drive;
 
 	drive = DRIVE(inode->i_rdev);
 
-	/*
-	 * If filp is NULL, we're being called from blkdev_release
-	 * or after a failed mount attempt.  In the former case the
-	 * device has already been sync'ed, and in the latter no
-	 * sync is required.  Otherwise, sync if filp is writable.
-	 */
-	if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
-		block_fsync(filp, filp->f_dentry);
+	block_fsync(filp, filp->f_dentry);
 
 	if (UDRS->fd_ref < 0)
 		UDRS->fd_ref=0;
@@ -3774,12 +3729,6 @@
 		invalidate_buffers(MKDEV(FLOPPY_MAJOR,old_dev));
 	}
 
-	/* Allow ioctls if we have write-permissions even if read-only open */
-	if ((filp->f_mode & 2) || (permission(inode,2) == 0))
-		filp->f_mode |= IOCTL_MODE_BIT;
-	if (filp->f_mode & 2)
-		filp->f_mode |= OPEN_WRITE_BIT;
-
 	if (UFDCS->rawcmd == 1)
 		UFDCS->rawcmd = 2;
 
@@ -3880,8 +3829,8 @@
 
 static struct file_operations floppy_fops = {
 	NULL,			/* lseek - default */
-	floppy_read,		/* read - general block-dev read */
-	floppy_write,		/* write - general block-dev write */
+	block_read,		/* read - general block-dev read */
+	block_write,		/* write - general block-dev write */
 	NULL,		       	/* readdir - bad */
 	NULL,			/* poll */
 	fd_ioctl,		/* ioctl */
diff -u --recursive --new-file v2.3.36/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c
--- v2.3.36/linux/drivers/block/ide-pci.c	Mon Dec 20 18:48:21 1999
+++ linux/drivers/block/ide-pci.c	Thu Jan  6 09:54:06 2000
@@ -635,7 +635,7 @@
 	if (PCI_FUNC(dev->devfn) & 1)
 		return;
 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
-	for (findev=pci_devices; findev; findev=findev->next) {
+	pci_for_each_dev(findev) {
 		if ((findev->vendor == dev->vendor) &&
 		    (findev->device == dev->device) &&
 		    ((findev->devfn - dev->devfn) == 1) &&
@@ -669,9 +669,7 @@
 	ide_pci_devid_t		devid;
 	ide_pci_device_t	*d;
 
-	if (!pci_present())
-		return;
-	for(dev = pci_devices; dev; dev=dev->next) {
+	pci_for_each_dev(dev) {
 		devid.vid = dev->vendor;
 		devid.did = dev->device;
 		for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
diff -u --recursive --new-file v2.3.36/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.3.36/linux/drivers/block/loop.c	Tue Dec 14 01:27:23 1999
+++ linux/drivers/block/loop.c	Thu Jan  6 10:14:36 2000
@@ -375,7 +375,10 @@
 	}
 
 	if (S_ISBLK(inode->i_mode)) {
-		error = blkdev_open(inode, file);
+		/* dentry will be wired, so... */
+		error = blkdev_get(inode->i_bdev, file->f_mode,
+				   file->f_flags, BDEV_FILE);
+
 		lo->lo_device = inode->i_rdev;
 		lo->lo_flags = 0;
 
@@ -482,7 +485,8 @@
 		return -EBUSY;
 
 	if (S_ISBLK(dentry->d_inode->i_mode))
-		blkdev_release (dentry->d_inode);
+		blkdev_put(dentry->d_inode->i_bdev, BDEV_FILE);
+
 	lo->lo_dentry = NULL;
 
 	if (lo->lo_backing_file != NULL) {
diff -u --recursive --new-file v2.3.36/linux/drivers/block/swim3.c linux/drivers/block/swim3.c
--- v2.3.36/linux/drivers/block/swim3.c	Tue Dec 14 01:27:23 1999
+++ linux/drivers/block/swim3.c	Wed Jan  5 07:01:22 2000
@@ -250,9 +250,6 @@
 static int swim3_add_device(struct device_node *swims);
 int swim3_init(void);
 
-#define IOCTL_MODE_BIT	8
-#define OPEN_WRITE_BIT	16
-
 static void swim3_select(struct floppy_state *fs, int sel)
 {
 	volatile struct swim3 *sw = fs->swim3;
@@ -821,8 +818,7 @@
 	if (devnum >= floppy_count)
 		return -ENODEV;
 		
-	if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) ||
-	    ((cmd & 0x80) && !suser()))
+	if ((cmd & 0x80) && !suser())
 		return -EPERM;
 
 	fs = &floppy_states[devnum];
@@ -916,12 +912,6 @@
 	else
 		++fs->ref_count;
 
-	/* Allow ioctls if we have write-permissions even if read-only open */
-	if ((filp->f_mode & 2) || (permission(inode, 2) == 0))
-		filp->f_mode |= IOCTL_MODE_BIT;
-	if (filp->f_mode & 2)
-		filp->f_mode |= OPEN_WRITE_BIT;
-
 	return 0;
 }
 
@@ -934,14 +924,7 @@
 	if (devnum >= floppy_count)
 		return -ENODEV;
 
-	/*
-	 * If filp is NULL, we're being called from blkdev_release
-	 * or after a failed mount attempt.  In the former case the
-	 * device has already been sync'ed, and in the latter no
-	 * sync is required.  Otherwise, sync if filp is writable.
-	 */
-	if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
-		block_fsync (filp, filp->f_dentry);
+	block_fsync (filp, filp->f_dentry);
 
 	fs = &floppy_states[devnum];
 	sw = fs->swim3;
diff -u --recursive --new-file v2.3.36/linux/drivers/block/swim_iop.c linux/drivers/block/swim_iop.c
--- v2.3.36/linux/drivers/block/swim_iop.c	Tue Dec 14 01:27:23 1999
+++ linux/drivers/block/swim_iop.c	Wed Jan  5 07:01:22 2000
@@ -45,9 +45,6 @@
 
 #define MAX_FLOPPIES	4
 
-#define IOCTL_MODE_BIT	8
-#define OPEN_WRITE_BIT	16
-
 enum swim_state {
 	idle,
 	available,
@@ -397,8 +394,7 @@
 	if (devnum >= floppy_count)
 		return -ENODEV;
 		
-	if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) ||
-	    ((cmd & 0x80) && !suser()))
+	if ((cmd & 0x80) && !suser())
 		return -EPERM;
 
 	fs = &floppy_states[devnum];
@@ -451,12 +447,6 @@
 	else
 		++fs->ref_count;
 
-	/* Allow ioctls if we have write-permissions even if read-only open */
-	if ((filp->f_mode & 2) || (permission(inode, 2) == 0))
-		filp->f_mode |= IOCTL_MODE_BIT;
-	if (filp->f_mode & 2)
-		filp->f_mode |= OPEN_WRITE_BIT;
-
 	return 0;
 }
 
@@ -468,14 +458,7 @@
 	if (devnum >= floppy_count)
 		return -ENODEV;
 
-	/*
-	 * If filp is NULL, we're being called from blkdev_release
-	 * or after a failed mount attempt.  In the former case the
-	 * device has already been sync'ed, and in the latter no
-	 * sync is required.  Otherwise, sync if filp is writable.
-	 */
-	if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
-		block_fsync (filp, filp->f_dentry);
+	block_fsync (filp, filp->f_dentry);
 
 	fs = &floppy_states[devnum];
 	if (fs->ref_count > 0) fs->ref_count--;
diff -u --recursive --new-file v2.3.36/linux/drivers/block/via82cxxx.c linux/drivers/block/via82cxxx.c
--- v2.3.36/linux/drivers/block/via82cxxx.c	Mon Dec 20 18:48:21 1999
+++ linux/drivers/block/via82cxxx.c	Thu Jan  6 10:23:46 2000
@@ -2,7 +2,7 @@
  * linux/drivers/block/via82cxxx.c	Version 0.06	Dec. 13, 1999
  *
  *  Copyright (C) 1998-99 Michel Aubry, Maintainer
- *  Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@pobox.com)
+ *  Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@mandrakesoft.com)
  *  Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
  *  May be copied or modified under the terms of the GNU General Public License
  *
diff -u --recursive --new-file v2.3.36/linux/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c
--- v2.3.36/linux/drivers/char/agp/agpgart_fe.c	Tue Dec 14 01:27:24 1999
+++ linux/drivers/char/agp/agpgart_fe.c	Thu Jan  6 10:23:46 2000
@@ -1094,5 +1094,6 @@
 
 void agp_frontend_cleanup(void)
 {
+	misc_deregister(&agp_miscdev);
 	return;
 }
diff -u --recursive --new-file v2.3.36/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.3.36/linux/drivers/char/bttv.c	Tue Jan  4 13:57:16 2000
+++ linux/drivers/char/bttv.c	Thu Jan  6 09:54:06 2000
@@ -3465,13 +3465,12 @@
 
 static int find_bt848(void)
 {
-        struct pci_dev *dev = pci_devices;
+        struct pci_dev *dev;
         int result=0;
 
         bttv_num=0;
 
-        while (dev)
-        {
+	pci_for_each_dev(dev) {
                 if (dev->vendor == PCI_VENDOR_ID_BROOKTREE)
                         if ((dev->device == PCI_DEVICE_ID_BT848)||
                             (dev->device == PCI_DEVICE_ID_BT849)||
@@ -3480,7 +3479,6 @@
                                 result=configure_bt848(dev,bttv_num++);
                 if (result)
                         return result;
-                dev = dev->next;
         }
 	if(bttv_num)
 		printk(KERN_INFO "bttv: %d Bt8xx card(s) found.\n", bttv_num);
diff -u --recursive --new-file v2.3.36/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.3.36/linux/drivers/char/random.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/char/random.c	Thu Jan  6 10:14:36 2000
@@ -1936,7 +1936,7 @@
 	/* Alternative: return sum of all words? */
 }
 
-#if 0	/* May be needed for IPv6 */
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 
 static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12])
 {
@@ -2001,6 +2001,59 @@
 #define REKEY_INTERVAL	300
 #define HASH_BITS 24
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+__u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr,
+				   __u16 sport, __u16 dport)
+{
+	static __u32	rekey_time = 0;
+	static __u32	count = 0;
+	static __u32	secret[12];
+	struct timeval 	tv;
+	__u32		seq;
+
+	/* The procedure is the same as for IPv4, but addresses are longer. */
+
+	do_gettimeofday(&tv);	/* We need the usecs below... */
+
+	if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
+		rekey_time = tv.tv_sec;
+		/* First five words are overwritten below. */
+		get_random_bytes(&secret[5], sizeof(secret)-5*4);
+		count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS;
+	}
+
+	memcpy(secret, saddr, 16);
+	secret[4]=(sport << 16) + dport;
+
+	seq = (twothirdsMD4Transform(daddr, secret) &
+	       ((1<<HASH_BITS)-1)) + count;
+
+	seq += tv.tv_usec + tv.tv_sec*1000000;
+	return seq;
+}
+
+__u32 secure_ipv6_id(__u32 *daddr)
+{
+	static time_t	rekey_time = 0;
+	static __u32	secret[12];
+	time_t		t;
+
+	/*
+	 * Pick a random secret every REKEY_INTERVAL seconds.
+	 */
+	t = CURRENT_TIME;
+	if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
+		rekey_time = t;
+		/* First word is overwritten below. */
+		get_random_bytes(secret, sizeof(secret));
+	}
+
+	return twothirdsMD4Transform(daddr, secret);
+}
+
+#endif
+
+
 __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
 				 __u16 sport, __u16 dport)
 {
@@ -2052,6 +2105,38 @@
 	       saddr, daddr, sport, dport, seq);
 #endif
 	return seq;
+}
+
+/*  The code below is shamelessly stolen from secure_tcp_sequence_number().
+ *  All blames to Andrey V. Savochkin <saw@msu.ru>.
+ */
+__u32 secure_ip_id(__u32 daddr)
+{
+	static time_t	rekey_time = 0;
+	static __u32	secret[12];
+	time_t		t;
+
+	/*
+	 * Pick a random secret every REKEY_INTERVAL seconds.
+	 */
+	t = CURRENT_TIME;
+	if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
+		rekey_time = t;
+		/* First word is overwritten below. */
+		get_random_bytes(secret+1, sizeof(secret)-4);
+	}
+
+	/*
+	 *  Pick a unique starting offset for each IP destination.
+	 *  Note that the words are placed into the first words to be
+	 *  mixed in with the halfMD4.  This is because the starting
+	 *  vector is also a random secret (at secret+8), and further
+	 *  hashing fixed data into it isn't going to improve anything,
+	 *  so we should get started with the variable data.
+	 */
+	secret[0]=daddr;
+
+	return halfMD4Transform(secret+8, secret);
 }
 
 #ifdef CONFIG_SYN_COOKIES
diff -u --recursive --new-file v2.3.36/linux/drivers/char/raw.c linux/drivers/char/raw.c
--- v2.3.36/linux/drivers/char/raw.c	Fri Oct 15 15:25:13 1999
+++ linux/drivers/char/raw.c	Thu Jan  6 10:14:36 2000
@@ -18,13 +18,11 @@
 
 #define dprintk(x...) 
 
-static kdev_t raw_device_bindings[256] = {};
+static struct block_device *raw_device_bindings[256] = {};
 static int raw_device_inuse[256] = {};
 static int raw_device_sector_size[256] = {};
 static int raw_device_sector_bits[256] = {};
 
-extern struct file_operations * get_blkfops(unsigned int major);
-
 static ssize_t rw_raw_dev(int rw, struct file *, char *, size_t, loff_t *);
 
 ssize_t	raw_read(struct file *, char *, size_t, loff_t *);
@@ -62,64 +60,11 @@
 	NULL		/* fsync */
 };
 
-
-
 void __init raw_init(void)
 {
 	register_chrdev(RAW_MAJOR, "raw", &raw_fops);
 }
 
-
-/*
- * The raw IO open and release code needs to fake appropriate
- * open/release calls to the underlying block devices.  
- */
-
-static int bdev_open(kdev_t dev, int mode)
-{
-	int err = 0;
-	struct file dummy_file = {};
-	struct dentry dummy_dentry = {};
-	struct inode * inode = get_empty_inode();
-	
-	if (!inode)
-		return -ENOMEM;
-	
-	dummy_file.f_op = get_blkfops(MAJOR(dev));
-	if (!dummy_file.f_op) {
-		err = -ENODEV;
-		goto done;
-	}
-	
-	if (dummy_file.f_op->open) {
-		inode->i_rdev = dev;
-		dummy_dentry.d_inode = inode;
-		dummy_file.f_dentry = &dummy_dentry;
-		dummy_file.f_mode = mode;
-		err = dummy_file.f_op->open(inode, &dummy_file);
-	}
-
- done:
-	iput(inode);
-	return err;
-}
-
-static int bdev_close(kdev_t dev)
-{
-	int err;
-	struct inode * inode = get_empty_inode();
-
-	if (!inode)
-		return -ENOMEM;
-	
-	inode->i_rdev = dev;
-	err = blkdev_release(inode);
-	iput(inode);
-	return err;
-}
-
-
-
 /* 
  * Open/close code for raw IO.
  */
@@ -127,7 +72,8 @@
 int raw_open(struct inode *inode, struct file *filp)
 {
 	int minor;
-	kdev_t bdev;
+	struct block_device * bdev;
+	kdev_t rdev;	/* it should eventually go away */
 	int err;
 	int sector_size;
 	int sector_bits;
@@ -150,10 +96,11 @@
 	 */
 
 	bdev = raw_device_bindings[minor];
-	if (bdev == NODEV) 
+	if (!bdev)
 		return -ENODEV;
 
-	err = bdev_open(bdev, filp->f_mode);
+	rdev = to_kdev_t(bdev->bd_dev);
+	err = blkdev_get(bdev, filp->f_mode, 0, BDEV_RAW);
 	if (err)
 		return err;
 	
@@ -171,15 +118,15 @@
 	 */
 	
 	sector_size = 512;
-	if (lookup_vfsmnt(bdev) != NULL) {
-		if (blksize_size[MAJOR(bdev)])
-			sector_size = blksize_size[MAJOR(bdev)][MINOR(bdev)];
+	if (lookup_vfsmnt(rdev) != NULL) {
+		if (blksize_size[MAJOR(rdev)])
+			sector_size = blksize_size[MAJOR(rdev)][MINOR(rdev)];
 	} else {
-		if (hardsect_size[MAJOR(bdev)])
-			sector_size = hardsect_size[MAJOR(bdev)][MINOR(bdev)];
+		if (hardsect_size[MAJOR(rdev)])
+			sector_size = hardsect_size[MAJOR(rdev)][MINOR(rdev)];
 	}
 
-	set_blocksize(bdev, sector_size);
+	set_blocksize(rdev, sector_size);
 	raw_device_sector_size[minor] = sector_size;
 
 	for (sector_bits = 0; !(sector_size & 1); )
@@ -192,11 +139,11 @@
 int raw_release(struct inode *inode, struct file *filp)
 {
 	int minor;
-	kdev_t bdev;
+	struct block_device *bdev;
 	
 	minor = MINOR(inode->i_rdev);
 	bdev = raw_device_bindings[minor];
-	bdev_close(bdev);
+	blkdev_put(bdev, BDEV_RAW);
 	raw_device_inuse[minor]--;
 	return 0;
 }
@@ -261,11 +208,14 @@
 				err = -EBUSY;
 				break;
 			}
+			if (raw_device_bindings[minor])
+				bdput(raw_device_bindings[minor]);
 			raw_device_bindings[minor] = 
-				MKDEV(rq.block_major, rq.block_minor);
+				bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor)));
 		} else {
-			rq.block_major = MAJOR(raw_device_bindings[minor]);
-			rq.block_minor = MINOR(raw_device_bindings[minor]);
+			kdev_t dev=to_kdev_t(raw_device_bindings[minor]->bd_dev);
+			rq.block_major = MAJOR(dev);
+			rq.block_minor = MINOR(dev);
 			err = copy_to_user((void *) arg, &rq, sizeof(rq));
 		}
 		break;
@@ -317,7 +267,7 @@
 	 */
 
 	minor = MINOR(filp->f_dentry->d_inode->i_rdev);
-	dev = raw_device_bindings[minor];
+	dev = to_kdev_t(raw_device_bindings[minor]->bd_dev);
 	sector_size = raw_device_sector_size[minor];
 	sector_bits = raw_device_sector_bits[minor];
 	sector_mask = sector_size- 1;
diff -u --recursive --new-file v2.3.36/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.3.36/linux/drivers/char/serial.c	Wed Dec 29 13:13:15 1999
+++ linux/drivers/char/serial.c	Thu Jan  6 09:54:06 2000
@@ -3990,7 +3990,6 @@
  */
 static void probe_serial_pci(void) 
 {
-	u16 subvendor, subdevice;
 	int k, line;
 	struct pci_dev *dev = NULL;
 	struct pci_board *board;
@@ -4002,18 +4001,7 @@
 	printk(KERN_DEBUG "Entered probe_serial_pci()\n");
 #endif
   
-	if (!pcibios_present()) {
-#ifdef SERIAL_DEBUG_PCI
-		printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n");
-#endif
-		return;
-	}
-
-	for(dev=pci_devices; dev; dev=dev->next) {
-		pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID,
-					 &subvendor);
-		pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subdevice);
-
+	pci_for_each_dev(dev) {
 		for (board = pci_boards; board->vendor; board++) {
 			if (board->vendor != (unsigned short) PCI_ANY_ID &&
 			    dev->vendor != board->vendor)
@@ -4022,10 +4010,10 @@
 			    dev->device != board->device)
 				continue;
 			if (board->subvendor != (unsigned short) PCI_ANY_ID &&
-			    subvendor != board->subvendor)
+			    dev->subsystem_vendor != board->subvendor)
 				continue;
 			if (board->subdevice != (unsigned short) PCI_ANY_ID &&
-			    subdevice != board->subdevice)
+			    dev->subsystem_device != board->subdevice)
 				continue;
 			break;
 		}
diff -u --recursive --new-file v2.3.36/linux/drivers/char/stradis.c linux/drivers/char/stradis.c
--- v2.3.36/linux/drivers/char/stradis.c	Mon Dec 20 18:48:21 1999
+++ linux/drivers/char/stradis.c	Thu Jan  6 09:54:06 2000
@@ -2243,26 +2243,19 @@
 int init_stradis_cards(struct video_init *unused)
 {
 #endif
-	struct pci_dev *dev = pci_devices;
+	struct pci_dev *dev = NULL;
 	int result = 0, i;
-	u32 newcard;
 
 	saa_num = 0;
 
-	while (dev) {
-		if (dev->vendor == PCI_VENDOR_ID_PHILIPS)
-			if (dev->device == PCI_DEVICE_ID_PHILIPS_SAA7146) {
-				pci_read_config_dword(dev,
-					PCI_SUBSYSTEM_VENDOR_ID, &newcard);
-				if (!newcard)
-					printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num);
-				else
-					printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num); 
-				result = configure_saa7146(dev, saa_num++);
-			}
+	while ((dev = pci_find_device(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, dev))) {
+		if (!dev->subsystem_vendor_id)
+			printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num);
+		else
+			printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num); 
+		result = configure_saa7146(dev, saa_num++);
 		if (result)
 			return result;
-		dev = dev->next;
 	}
 	if (saa_num)
 		printk(KERN_INFO "stradis: %d card(s) found.\n", saa_num);
diff -u --recursive --new-file v2.3.36/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c
--- v2.3.36/linux/drivers/i2o/i2o_pci.c	Thu Nov 18 20:25:37 1999
+++ linux/drivers/i2o/i2o_pci.c	Thu Jan  6 09:54:06 2000
@@ -229,9 +229,8 @@
 	int count=0;
 	
 	printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
-	
-	for(dev=pci_devices; dev!=NULL; dev=dev->next)
-	{
+
+	pci_for_each_dev(dev) {
 		if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O)
 			continue;
 		if((dev->class&0xFF)>1)
diff -u --recursive --new-file v2.3.36/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
--- v2.3.36/linux/drivers/macintosh/via-pmu.c	Fri Oct 15 15:25:13 1999
+++ linux/drivers/macintosh/via-pmu.c	Thu Jan  6 09:54:06 2000
@@ -1047,8 +1047,9 @@
 	struct pci_save *ps;
 
 	npci = 0;
-	for (pd = pci_devices; pd != NULL; pd = pd->next)
+	pci_for_each_dev(pd) {
 		++npci;
+	}
 	n_pbook_pci_saves = npci;
 	if (npci == 0)
 		return;
@@ -1057,13 +1058,12 @@
 	if (ps == NULL)
 		return;
 
-	for (pd = pci_devices; pd != NULL && npci != 0; pd = pd->next) {
+	pci_for_each_dev(pd) {
 		pci_read_config_word(pd, PCI_COMMAND, &ps->command);
 		pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
 		pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
 		pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address);
 		++ps;
-		--npci;
 	}
 }
 
@@ -1071,11 +1071,12 @@
 pbook_pci_restore(void)
 {
 	u16 cmd;
-	struct pci_save *ps = pbook_pci_saves;
+	struct pci_save *ps = pbook_pci_saves - 1;
 	struct pci_dev *pd;
 	int j;
 
-	for (pd = pci_devices; pd != NULL; pd = pd->next, ++ps) {
+	pci_for_each_dev(pd) {
+		ps++;
 		if (ps->command == 0)
 			continue;
 		pci_read_config_word(pd, PCI_COMMAND, &cmd);
diff -u --recursive --new-file v2.3.36/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c
--- v2.3.36/linux/drivers/net/pcmcia/ray_cs.c	Mon Dec 20 18:48:21 1999
+++ linux/drivers/net/pcmcia/ray_cs.c	Wed Jan  5 10:34:02 2000
@@ -2529,13 +2529,23 @@
  * eg ifconfig 
  */
     int i;
-    dev_link_t *link = dev_list;
-    struct net_device *dev = (struct net_device *)link->priv;
-    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    dev_link_t *link;
+    struct net_device *dev;
+    ray_dev_t *local;
     UCHAR *p;
     struct freq_hop_element *pfh;
     UCHAR c[33];
 
+    link = dev_list;
+    if (!link)
+    	return 0;
+    dev = (struct net_device *)link->priv;
+    if (!dev)
+    	return 0;
+    local = (ray_dev_t *)dev->priv;
+    if (!local)
+    	return 0;
+
     len = 0;
 
     len += sprintf(buf + len, "Raylink Wireless LAN driver status\n");
@@ -2663,7 +2673,59 @@
     }
     return 0;
 } /* End build_auth_frame */
+
 /*===========================================================================*/
+
+static void raycs_write(const char *name, write_proc_t *w, void *data)
+{
+	struct proc_dir_entry * entry = create_proc_entry(name, S_IFREG | S_IWUSR, NULL);
+	if (entry) {
+		entry->write_proc = w;
+		entry->data = data;
+	}
+}
+
+static int write_essid(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	static char proc_essid[33];
+	int len = count;
+
+	if (len > 32)
+		len = 32;
+	memset(proc_essid, 0, 33);
+	if (copy_from_user(proc_essid, buffer, len))
+		return -EFAULT;
+	essid = proc_essid;
+	return count;
+}
+
+static int write_int(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	static char proc_number[10];
+	char *p;
+	int nr, len;
+
+	if (!count)
+		return 0;
+
+	if (count > 9)
+		return -EINVAL;
+	if (copy_from_user(proc_number, buffer, count))
+		return -EFAULT;
+	p = proc_number;
+	nr = 0;
+	len = count;
+	do {
+		unsigned int c = *p - '0';
+		if (c > 9)
+			return -EINVAL;
+		nr = nr*10 + c;
+		p++;
+	} while (--len);
+	*(int *)data = nr;
+	return count;
+}
+
 static int __init init_ray_cs(void)
 {
     int rc;
@@ -2671,41 +2733,35 @@
     DEBUG(1, "%s\n", rcsid);
     rc = register_pcmcia_driver(&dev_info, &ray_attach, &ray_detach);
     DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",rc);
-#ifdef CONFIG_PROC_FS    
-    /* [proc-namespace][fixme] It shouldn't be under root, damnit! */
-    create_proc_info_entry("ray_cs", 0, &proc_root, ray_cs_proc_read);
-#endif    
+
+    proc_mkdir("driver/ray_cs", 0);
+
+    create_proc_info_entry("driver/ray_cs/ray_cs", 0, NULL, ray_cs_proc_read);
+    raycs_write("driver/ray_cs/essid", write_essid, NULL);
+    raycs_write("driver/ray_cs/net_type", write_int, &net_type);
+    raycs_write("driver/ray_cs/translate", write_int, &translate);
     if (translate != 0) translate = 1;
     return 0;
 } /* init_ray_cs */
 
-#ifndef MODULE
-
-static char init_ess_id[ESSID_SIZE];
-static int __init essid_setup(char *str)
-{
-	strncpy(init_ess_id, str, ESSID_SIZE);
-	essid = init_ess_id;
-	return 1;
-}
-__setup("essid=", essid_setup);
-
-#endif
-
 /*===========================================================================*/
 
 static void __exit exit_ray_cs(void)
 {
     DEBUG(0, "ray_cs: cleanup_module\n");
 
+
+    remove_proc_entry("ray_cs", proc_root_driver);
     unregister_pcmcia_driver(&dev_info);
     while (dev_list != NULL) {
         if (dev_list->state & DEV_CONFIG) ray_release((u_long)dev_list);
         ray_detach(dev_list);
     }
-#ifdef CONFIG_PROC_FS    
-    remove_proc_entry("ray_cs", &proc_root);
-#endif   
+    remove_proc_entry("driver/ray_cs/ray_cs", NULL);
+    remove_proc_entry("driver/ray_cs/essid", NULL);
+    remove_proc_entry("driver/ray_cs/net_type", NULL);
+    remove_proc_entry("driver/ray_cs/translate", NULL);
+    remove_proc_entry("driver/ray_cs", NULL);
 } /* exit_ray_cs */
 
 module_init(init_ray_cs);
diff -u --recursive --new-file v2.3.36/linux/drivers/net/pcmcia/tulip_cb.c linux/drivers/net/pcmcia/tulip_cb.c
--- v2.3.36/linux/drivers/net/pcmcia/tulip_cb.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/net/pcmcia/tulip_cb.c	Wed Jan  5 15:55:10 2000
@@ -3324,10 +3324,10 @@
 	if (*devp) {
 		struct net_device *dev = *devp;
 		struct tulip_private *tp = dev->priv;
+		*devp = *next;
 		unregister_netdev(dev);
 		kfree(dev);
 		kfree(tp);
-		*devp = *next;
 		kfree(node);
 		MOD_DEC_USE_COUNT;
 	}
diff -u --recursive --new-file v2.3.36/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.3.36/linux/drivers/parport/parport_pc.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/parport/parport_pc.c	Thu Jan  6 09:54:06 2000
@@ -1828,7 +1828,7 @@
 	}
 
 	/* Look for parallel controllers that we don't know about. */
-	for (pcidev = pci_devices; pcidev; pcidev = pcidev->next) {
+	pci_for_each_dev(pcidev) {
 		const int class_noprogif = pcidev->class & ~0xff;
 		if (class_noprogif != (PCI_CLASS_COMMUNICATION_PARALLEL << 8))
 			continue;
diff -u --recursive --new-file v2.3.36/linux/drivers/pci/compat.c linux/drivers/pci/compat.c
--- v2.3.36/linux/drivers/pci/compat.c	Tue Dec  7 09:32:44 1999
+++ linux/drivers/pci/compat.c	Thu Jan  6 09:54:06 2000
@@ -3,7 +3,7 @@
  *
  *	PCI Bus Services -- Function For Backward Compatibility
  *
- *	Copyright 1998, 1999 Martin Mares <mj@suse.cz>
+ *	Copyright 1998--2000 Martin Mares <mj@suse.cz>
  */
 
 #include <linux/types.h>
@@ -13,7 +13,7 @@
 int
 pcibios_present(void)
 {
-	return !!pci_devices;
+	return pci_devices.next != &pci_devices;
 }
 
 int
diff -u --recursive --new-file v2.3.36/linux/drivers/pci/helper.c linux/drivers/pci/helper.c
--- v2.3.36/linux/drivers/pci/helper.c	Thu Nov 18 20:25:37 1999
+++ linux/drivers/pci/helper.c	Thu Jan  6 10:24:04 2000
@@ -3,7 +3,7 @@
  *
  * drivers/pci/helper.c
  *
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
  * This software is free.  See the file COPYING for licensing details.
  *
  */
diff -u --recursive --new-file v2.3.36/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.3.36/linux/drivers/pci/pci.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/pci/pci.c	Thu Jan  6 09:54:06 2000
@@ -6,7 +6,7 @@
  *	Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
  *	David Mosberger-Tang
  *
- *	Copyright 1997 -- 1999 Martin Mares <mj@suse.cz>
+ *	Copyright 1997 -- 2000 Martin Mares <mj@suse.cz>
  */
 
 #include <linux/types.h>
@@ -27,19 +27,19 @@
 #define DBG(x...)
 #endif
 
-struct pci_bus *pci_root;
-struct pci_dev *pci_devices = NULL;
-static struct pci_dev **pci_last_dev_p = &pci_devices;
+LIST_HEAD(pci_root_buses);
+LIST_HEAD(pci_devices);
 
 struct pci_dev *
 pci_find_slot(unsigned int bus, unsigned int devfn)
 {
 	struct pci_dev *dev;
 
-	for(dev=pci_devices; dev; dev=dev->next)
+	pci_for_each_dev(dev) {
 		if (dev->bus->number == bus && dev->devfn == devfn)
-			break;
-	return dev;
+			return dev;
+	}
+	return NULL;
 }
 
 
@@ -48,20 +48,16 @@
 		unsigned int ss_vendor, unsigned int ss_device,
 		struct pci_dev *from)
 {
-	struct pci_dev *dev;
+	struct list_head *n = from ? from->global_list.next : pci_devices.next;
 
-	if (from)
-		dev = from->next;
-	else
-		dev = pci_devices;
-
-	while (dev) {
+	while (n != &pci_devices) {
+		struct pci_dev *dev = pci_dev_g(n);
 		if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
 		    (device == PCI_ANY_ID || dev->device == device) &&
 		    (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
 		    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
 			return dev;
-		dev = dev->next;
+		n = n->next;
 	}
 	return NULL;
 }
@@ -77,13 +73,15 @@
 struct pci_dev *
 pci_find_class(unsigned int class, struct pci_dev *from)
 {
-	if (!from)
-		from = pci_devices;
-	else
-		from = from->next;
-	while (from && from->class != class)
-		from = from->next;
-	return from;
+	struct list_head *n = from ? from->global_list.next : pci_devices.next;
+
+	while (n != &pci_devices) {
+		struct pci_dev *dev = pci_dev_g(n);
+		if (dev->class == class)
+			return dev;
+		n = n->next;
+	}
+	return NULL;
 }
 
 
@@ -412,6 +410,19 @@
 	}
 }
 
+static struct pci_bus * __init pci_alloc_bus(void)
+{
+	struct pci_bus *b;
+
+	b = kmalloc(sizeof(*b), GFP_KERNEL);
+	if (b) {
+		memset(b, 0, sizeof(*b));
+		INIT_LIST_HEAD(&b->children);
+		INIT_LIST_HEAD(&b->devices);
+	}
+	return b;
+}
+
 static struct pci_bus * __init pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
 {
 	struct pci_bus *child;
@@ -419,11 +430,9 @@
 	/*
 	 * Allocate a new bus, and inherit stuff from the parent..
 	 */
-	child = kmalloc(sizeof(*child), GFP_KERNEL);
-	memset(child, 0, sizeof(*child));
+	child = pci_alloc_bus();
 
-	child->next = parent->children;
-	parent->children = child;
+	list_add_tail(&child->node, &parent->children);
 	child->self = dev;
 	dev->subordinate = child;
 	child->parent = parent;
@@ -455,6 +464,7 @@
 	/*
 	 * Insert it into the tree of buses.
 	 */
+	DBG("Scanning CardBus bridge %s\n", dev->slot_name);
 	child = pci_add_new_bus(bus, dev, ++busnr);
 
 	for (i = 0; i < 4; i++)
@@ -517,6 +527,7 @@
 	/*
 	 * Insert it into the tree of buses.
 	 */
+	DBG("Scanning behind PCI bridge %s\n", dev->slot_name);
 	child = pci_add_new_bus(bus, dev, ++max);
 	sprintf(child->name, "PCI Bus #%02x", child->number);
 
@@ -599,6 +610,8 @@
 	dev->class = class;
 	class >>= 8;
 
+	DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number, dev->devfn, dev->vendor, dev->device, class, dev->hdr_type);
+
 	switch (dev->hdr_type) {		    /* header type */
 	case PCI_HEADER_TYPE_NORMAL:		    /* standard header */
 		if (class == PCI_CLASS_BRIDGE_PCI)
@@ -694,21 +707,12 @@
 			first_dev = dev;
 		}
 
-		DBG("PCI: %02x:%02x [%04x/%04x] %06x %02x\n", bus->number, dev->devfn, dev->vendor, dev->device, dev->class, hdr_type);
-
-		/*
-		 * Put it into the global PCI device chain. It's used to
-		 * find devices once everything is set up.
-		 */
-		*pci_last_dev_p = dev;
-		pci_last_dev_p = &dev->next;
-
 		/*
-		 * Now insert it into the list of devices held
-		 * by the parent bus.
+		 * Link the device to both the global PCI device chain and
+		 * the per-bus list of devices.
 		 */
-		*bus->last_dev_p = dev;
-		bus->last_dev_p = &dev->sibling;
+		list_add_tail(&dev->global_list, &pci_devices);
+		list_add_tail(&dev->bus_list, &bus->devices);
 
 		/* Fix up broken headers */
 		pci_fixup_device(PCI_FIXUP_HEADER, dev);
@@ -719,10 +723,10 @@
 static unsigned int __init pci_do_scan_bus(struct pci_bus *bus)
 {
 	unsigned int devfn, max;
+	struct list_head *ln;
 	struct pci_dev *dev, dev0;
 
-	DBG("pci_do_scan_bus for bus %d\n", bus->number);
-	bus->last_dev_p = &bus->devices;
+	DBG("Scanning bus %02x\n", bus->number);
 	max = bus->secondary;
 
 	/* Create a device template */
@@ -740,8 +744,10 @@
 	 * After performing arch-dependent fixup of the bus, look behind
 	 * all PCI-to-PCI bridges on this bus.
 	 */
+	DBG("Fixups for bus %02x\n", bus->number);
 	pcibios_fixup_bus(bus);
-	for (dev = bus->devices; dev; dev = dev->sibling) {
+	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+		dev = pci_dev_b(ln);
 		switch (dev->class >> 8) {
 		case PCI_CLASS_BRIDGE_PCI:
 			max = pci_scan_bridge(bus, dev, max);
@@ -759,40 +765,34 @@
 	 *
 	 * Return how far we've got finding sub-buses.
 	 */
-	DBG("PCI: pci_do_scan_bus returning with max=%02x\n", max);
+	DBG("Bus scan for %02x returning with max=%02x\n", bus->number, max);
 	return max;
 }
 
-static int __init pci_bus_exists(struct pci_bus *b, int nr)
+static int __init pci_bus_exists(struct list_head *list, int nr)
 {
-	while (b) {
-		if (b->number == nr)
-			return 1;
-		if (b->children && pci_bus_exists(b->children, nr))
+	struct list_head *l;
+
+	for(l=list->next; l != list; l = l->next) {
+		struct pci_bus *b = pci_bus_b(l);
+		if (b->number == nr || pci_bus_exists(&b->children, nr))
 			return 1;
-		b = b->next;
 	}
 	return 0;
 }
 
 struct pci_bus * __init pci_alloc_primary_bus(int bus)
 {
-	struct pci_bus *b, **r;
+	struct pci_bus *b;
 
-	if (pci_bus_exists(pci_root, bus)) {
+	if (pci_bus_exists(&pci_root_buses, bus)) {
 		/* If we already got to this bus through a different bridge, ignore it */
 		DBG("PCI: Bus %02x already known\n", bus);
 		return NULL;
 	}
 
-	b = kmalloc(sizeof(*b), GFP_KERNEL);
-	memset(b, 0, sizeof(*b));
-
-	/* Put the new bus at the end of the chain of busses.  */
-	r = &pci_root;
-	while (*r)
-		r = &(*r)->next;
-	*r = b;
+	b = pci_alloc_bus();
+	list_add_tail(&b->node, &pci_root_buses);
 
 	b->number = b->secondary = bus;
 	b->resource[0] = &ioport_resource;
@@ -817,8 +817,9 @@
 
 	pcibios_init();
 
-	for(dev=pci_devices; dev; dev=dev->next)
+	pci_for_each_dev(dev) {
 		pci_fixup_device(PCI_FIXUP_FINAL, dev);
+	}
 }
 
 static int __init pci_setup(char *str)
diff -u --recursive --new-file v2.3.36/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids
--- v2.3.36/linux/drivers/pci/pci.ids	Wed Dec 29 13:13:16 1999
+++ linux/drivers/pci/pci.ids	Thu Jan  6 09:54:06 2000
@@ -4,7 +4,7 @@
 #	Maintained by Martin Mares <pci-ids@ucw.cz>
 #	If you have any new entries, send them to the maintainer.
 #
-#	$Id: pci.ids,v 1.43 1999/12/04 12:32:55 mj Exp $
+#	$Id: pci.ids,v 1.46 2000/01/02 20:32:11 mj Exp $
 #
 
 # Vendors, devices and subsystems. Please keep sorted.
@@ -778,7 +778,8 @@
 	0002  PT80C524 [Nile]
 	0005  National PC87550 System Controller
 	8002  PT80C524 [Nile]
-1067  Mitsubishi Electronics
+1067  Mitsubishi Electric
+	1002  VG500 [VolumePro Volume Rendering Accelerator]
 1068  Diversified Technology
 1069  Mylex Corporation
 	0001  DAC960P
@@ -865,13 +866,14 @@
 	0010  VME Bridge Model 618
 	3000  VME Bridge Model 2706
 108c  Oakleigh Systems Inc.
-108d  Olicom
-	0001  OC-3136/3137
+108d Olicom
+	0001  Token-Ring 16/4 PCI Adapter (3136/3137)
 	0002  16/4 Token Ring
-	0004  OC-3139/3140 RapidFire Token-Ring 16/4
-	0005  OC-3250 GoCard Token-Ring 16/4
+	0004  RapidFire 3139 Token-Ring 16/4 PCI Adapter
+	0005  GoCard 3250 Token-Ring 16/4 CardBus PC Card
 	0006  OC-3530 RapidFire Token-Ring 100
-	0007  OC-3141 RapidFire Token-Ring 16/4
+	0007  RapidFire 3141 Token-Ring 16/4 PCI Fiber Adapter
+	0008  RapidFire 3540 HSTR 100/16/4 PCI Adapter
 	0011  OC-2315
 	0012  OC-2325
 	0013  OC-2183/2185
@@ -1012,17 +1014,23 @@
 	9080  9080
 		10b5 9080  9080 [real subsystem ID not set]
 10b6  Madge Networks
-	0001  Smart 16/4 Ringnode
-	0002  Smart 16/4 BM Mk2 Ringnode
-	0003  Smart 16/4 Ringnode
-		0e11 b0fd  NC4621 4/16 Token-Ring Adapter + WOL
-		10b6 0003  Smart 16/4 Ringnode Mk3
-		10b6 0007  Presto Mk2
-	0004  Smart 16/4 Ringnode (BM)
+	0001  Smart 16/4 PCI Ringnode
+	0002  Smart 16/4 PCI Ringnode Mk2
+		10b6 0002  Smart 16/4 PCI Ringnode Mk2
+		10b6 0006  16/4 CardBus Adapter
+	0003  Smart 16/4 PCI Ringnode Mk3
+		0e11 b0fd  Compaq NC4621 PCI, 4/16, WOL
+		10b6 0003  Smart 16/4 PCI Ringnode Mk3
+		10b6 0007  Presto PCI Plus Adapter
+	0004  Smart 16/4 PCI Ringnode Mk1
 	0006  16/4 Cardbus Adapter
-	0007  Presto
-	1000  Collage 25 ATM adaptor
-	1001  Collage 155 Server
+		10b6 0006  16/4 CardBus Adapter
+	0007  Presto PCI Adapter
+	0009  Smart 100/16/4 PCI-HS Ringnode
+	000a  Smart 100/16/4 PCI Ringnode
+	000b  16/4 CardBus Adapter Mk2
+	1000  Collage 25 ATM Adapter
+	1001  Collage 155 ATM Server Adapter
 10b7  3Com Corporation
 	0001  3c985 1000BaseSX
 	3390  Token Link Velocity
@@ -2108,6 +2116,8 @@
 	8888  Cinemaster C 3.0 DVD Decoder
 1240  Marathon Technologies Corp.
 1241  DSC Communications
+1242  Jaycor Networks, Inc.
+	4643  FCI-1063 Fibre Channel Adapter
 1243  Delphax
 1244  AVM Audiovisuelles MKTG & Computer System GmbH
 	0700  B1 ISDN
@@ -2295,7 +2305,8 @@
 12c4  Connect Tech Inc
 12c5  Picture Elements Incorporated
 	0081  PCIVST [Grayscale Thresholding Engine]
-	0086  THR2 Thresholder
+	0085  Video Simulator/Sender
+	0086  THR2 Multi-scale Thresholder
 12c6  Mitani Corporation
 12c7  Dialogic Corp
 12c8  G Force Co, Ltd
@@ -3271,6 +3282,7 @@
 		0e11 b123  NC1634 Gigabit Ethernet Adapter
 		1014 0119  Netfinity Gigabit Ethernet SX Adapter
 		8086 1000  EtherExpress PRO/1000 Gigabit Server Adapter
+	1030  82559 InBusiness 10/100
 	1209  82559ER
 	1221  82092AA_0
 	1222  82092AA_1
diff -u --recursive --new-file v2.3.36/linux/drivers/pci/pcisyms.c linux/drivers/pci/pcisyms.c
--- v2.3.36/linux/drivers/pci/pcisyms.c	Wed Dec 29 13:13:17 1999
+++ linux/drivers/pci/pcisyms.c	Thu Jan  6 09:54:06 2000
@@ -18,7 +18,7 @@
 EXPORT_SYMBOL(pci_write_config_word);
 EXPORT_SYMBOL(pci_write_config_dword);
 EXPORT_SYMBOL(pci_devices);
-EXPORT_SYMBOL(pci_root);
+EXPORT_SYMBOL(pci_root_buses);
 EXPORT_SYMBOL(pci_enable_device);
 EXPORT_SYMBOL(pci_find_class);
 EXPORT_SYMBOL(pci_find_device);
@@ -27,6 +27,7 @@
 EXPORT_SYMBOL(pci_simple_probe);
 EXPORT_SYMBOL(pci_set_power_state);
 EXPORT_SYMBOL(pci_assign_resource);
+EXPORT_SYMBOL(pci_setup_device);
 #ifdef	CONFIG_PROC_FS
 EXPORT_SYMBOL(pci_proc_attach_device);
 EXPORT_SYMBOL(pci_proc_detach_device);
diff -u --recursive --new-file v2.3.36/linux/drivers/pci/proc.c linux/drivers/pci/proc.c
--- v2.3.36/linux/drivers/pci/proc.c	Wed Dec  8 14:11:26 1999
+++ linux/drivers/pci/proc.c	Thu Jan  6 09:54:06 2000
@@ -218,12 +218,12 @@
 static int
 get_pci_dev_info(char *buf, char **start, off_t pos, int count)
 {
-	struct pci_dev *dev = pci_devices;
+	struct pci_dev *dev;
 	off_t at = 0;
 	int len, i, cnt;
 
 	cnt = 0;
-	while (dev && count > cnt) {
+	pci_for_each_dev(dev) {
 		len = sprintf(buf, "%02x%02x\t%04x%04x\t%x",
 			dev->bus->number,
 			dev->devfn,
@@ -247,7 +247,6 @@
 				cnt += len;
 			buf += len;
 		}
-		dev = dev->next;
 	}
 	return (count > cnt) ? cnt : count;
 }
@@ -289,18 +288,6 @@
 	return 0;
 }
 
-void __init proc_bus_pci_add(struct pci_bus *bus)
-{
-	while (bus) {
-		struct pci_dev *dev;
-
-		for(dev = bus->devices; dev; dev = dev->sibling)
-			pci_proc_attach_device(dev);
-		if (bus->children)
-			proc_bus_pci_add(bus->children);
-		bus = bus->next;
-	}
-}
 
 /*
  *  Backward compatible /proc/pci interface.
@@ -406,12 +393,15 @@
 	int nprinted, len, begin = 0;
 	struct pci_dev *dev;
 
-	len   = sprintf(buf, "PCI devices found:\n");
+	len = sprintf(buf, "PCI devices found:\n");
 
-	for (dev = pci_devices; dev; dev = dev->next) {
+	*eof = 1;
+	pci_for_each_dev(dev) {
 		nprinted = sprint_dev_config(dev, buf + len, count - len);
-		if (nprinted < 0)
+		if (nprinted < 0) {
+			*eof = 0;
 			break;
+		}
 		len += nprinted;
 		if (len+begin < off) {
 			begin += len;
@@ -420,8 +410,6 @@
 		if (len+begin >= off+count)
 			break;
 	}
-	if (!dev || len+begin < off)
-		*eof = 1;
 	off -= begin;
 	*start = buf + off;
 	len -= off;
@@ -435,10 +423,13 @@
 static int __init pci_proc_init(void)
 {
 	if (pci_present()) {
+		struct pci_dev *dev;
 		proc_bus_pci_dir = proc_mkdir("pci", proc_bus);
 		create_proc_info_entry("devices", 0, proc_bus_pci_dir,
 					get_pci_dev_info);
-		proc_bus_pci_add(pci_root);
+		pci_for_each_dev(dev) {
+			pci_proc_attach_device(dev);
+		}
 		create_proc_read_entry("pci", 0, NULL, pci_read_proc, NULL);
 	}
 	return 0;
diff -u --recursive --new-file v2.3.36/linux/drivers/pci/setup.c linux/drivers/pci/setup.c
--- v2.3.36/linux/drivers/pci/setup.c	Mon Dec 20 18:48:21 1999
+++ linux/drivers/pci/setup.c	Thu Jan  6 09:54:06 2000
@@ -144,8 +144,10 @@
 pci_assign_unassigned_resources(u32 min_io, u32 min_mem)
 {
 	struct pci_dev *dev;
-	for (dev = pci_devices; dev; dev = dev->next)
+
+	pci_for_each_dev(dev) {
 		pdev_assign_unassigned_resources(dev, min_io, min_mem);
+	}
 }
 
 #define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
@@ -157,14 +159,16 @@
 	struct pbus_set_ranges_data inner;
 	struct pci_bus *child;
 	struct pci_dev *dev;
+	struct list_node *ln;
 
 	inner.found_vga = 0;
 	inner.mem_start = inner.io_start = ~0UL;
 	inner.mem_end = inner.io_end = 0;
 
 	/* Collect information about how our direct children are layed out. */
-	for (dev = bus->devices; dev; dev = dev->sibling) {
+	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
 		int i;
+		dev = pci_dev_b(ln);
 		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 			struct resource *res = &dev->resource[i];
 			if (res->flags & IORESOURCE_IO) {
@@ -184,8 +188,8 @@
 	}
 
 	/* And for all of the sub-busses.  */
-	for (child = bus->children; child; child = child->next)
-		pbus_set_ranges(child, &inner);
+	for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
+		pbus_set_ranges(pci_bus_b(ln), &inner);
 
 	/* Align the values.  */
 	inner.io_start = ROUND_DOWN(inner.io_start, 4*1024);
@@ -271,9 +275,10 @@
 void __init
 pci_set_bus_ranges(void)
 {
-	struct pci_bus *bus;
-	for (bus = pci_root; bus; bus = bus->next)
-		pbus_set_ranges(bus, NULL);
+	struct list_node *ln;
+
+	for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next)
+		pci_set_ranges(pci_bus_b(ln), NULL);
 }
 
 static void __init
@@ -315,8 +320,9 @@
 	       int (*map_irq)(struct pci_dev *, u8, u8))
 {
 	struct pci_dev *dev;
-	for (dev = pci_devices; dev; dev = dev->next)
+	pci_for_each_dev(dev) {
 		pdev_fixup_irq(dev, swizzle, map_irq);
+	}
 }
 
 int
diff -u --recursive --new-file v2.3.36/linux/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c
--- v2.3.36/linux/drivers/pcmcia/cardbus.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/pcmcia/cardbus.c	Thu Jan  6 09:54:06 2000
@@ -267,8 +267,8 @@
 	bus = s->cap.cb_dev->subordinate;
 	memset(&tmp, 0, sizeof(tmp));
 	tmp.bus = bus;
+	tmp.sysdata = bus->sysdata;
 	tmp.devfn = 0;
-	printk("bus=%p, number=%d\n", bus, bus->number);
 
 	pci_readw(&tmp, PCI_VENDOR_ID, &vend);
 	pci_readw(&tmp, PCI_DEVICE_ID, &dev);
@@ -280,8 +280,7 @@
 	if (hdr & 0x80) {
 		do {
 			tmp.devfn = fn;
-			pci_readw(&tmp, PCI_VENDOR_ID, &v);
-			if (v != vend)
+			if (pci_readw(&tmp, PCI_VENDOR_ID, &v) || !v || v == 0xffff)
 				break;
 			fn++;
 		} while (fn < 8);
@@ -298,15 +297,14 @@
 		int r;
 
 		dev->bus = bus;
+		dev->sysdata = bus->sysdata;
 		dev->devfn = i;
-		if (i < fn - 1) {
-			dev->sibling = dev->next = &c[i + 1].dev;
-		}
 		dev->vendor = vend;
 		pci_readw(dev, PCI_DEVICE_ID, &dev->device);
 		dev->hdr_type = hdr;
 
 		pci_setup_device(dev);
+		/* FIXME: Do we need to enable the expansion ROM? */
 		for (r = 0; r < 7; r++) {
 			struct resource *res = dev->resource + r;
 			if (res->flags) {
@@ -321,19 +319,17 @@
 			       res->end,
 			       res->flags);
 		}
-		pci_enable_device(dev);
 
+		list_add_tail(&dev->bus_list, &bus->devices);
+		list_add_tail(&dev->global_list, &pci_devices);
 #ifdef CONFIG_PROC_FS
 		pci_proc_attach_device(dev);
 #endif
+
+		pci_enable_device(dev);
 	}
 
-	/* Link into PCI device chain */
-	bus->devices = &c[0].dev;
-	c[fn - 1].dev.next = pci_devices;
-	pci_devices = &c[0].dev;
 	s->cb_config = c;
-
 	return CS_SUCCESS;
 }
 
@@ -351,25 +347,18 @@
 void cb_free(socket_info_t * s)
 {
 	cb_config_t *c = s->cb_config;
-	struct pci_bus *bus = s->cap.cb_dev->subordinate;
+	int i;
 
 	if (c) {
-		struct pci_dev **p;
-		/* Unlink from PCI device chain */
-		p = &pci_devices;
-		while (*p) {
-			struct pci_dev *dev = *p;
-			if (dev->bus != bus) {
-				p = &dev->next;
-				continue;
-			}
-			*p = dev->next;
+		for(i=0; i<s->functions; i++) {
+			struct pci_dev *dev = &c[i].dev;
+			list_del(&dev->bus_list);
+			list_del(&dev->global_list);
 			free_resources(dev);
 #ifdef CONFIG_PROC_FS
 			pci_proc_detach_device(dev);
 #endif
 		}
-		bus->devices = NULL;
 		kfree(s->cb_config);
 		s->cb_config = NULL;
 		printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cb_dev->subordinate->number);
diff -u --recursive --new-file v2.3.36/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c
--- v2.3.36/linux/drivers/pcmcia/yenta.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/pcmcia/yenta.c	Wed Jan  5 16:11:46 2000
@@ -428,13 +428,18 @@
 
 	/* Are we set up to route the IO irq to the PCI irq? */
 	bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL);
-	if (!(bridge_ctrl & CB_BRIDGE_INTR)) {
-		socket->io_irq = socket->cb_irq;
-		if (socket->cb_irq && socket->cb_irq < 16)
-			return 1 << socket->cb_irq;
+	if (socket->cb_irq) {
+		if (bridge_ctrl & CB_BRIDGE_INTR) {
+			bridge_ctrl &= ~CB_BRIDGE_INTR;
+			config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
+		}
+		printk("CardBus: using PCI interrupt %d\n", socket->cb_irq);
+		return 1 << socket->cb_irq;
+	}
 
-		/* Uhhuh. Try falling back on ISA interrupts */
-		printk("CardBus: Hmm.. Bad PCI irq routing (irq%d)\n", socket->cb_irq);
+	/* Uhhuh. No PCI interrupt: try falling back on ISA interrupts */
+	printk("CardBus: Hmm.. No PCI irq routing (irq%d).\n", socket->cb_irq);
+	if (!(bridge_ctrl & CB_BRIDGE_INTR)) {
 		bridge_ctrl |= CB_BRIDGE_INTR;
 		config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
 	}
@@ -558,8 +563,6 @@
 	offset = 0x1c + 8*nr;
 	bus = socket->dev->subordinate;
 	res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr;
-	printk("dev=%p, bus=%p, parent=%p\n", socket->dev, bus, socket->dev->bus);
-	printk("res = %p, bus->res = %p\n", res, bus->resource[nr]);
 	res->name = bus->name;
 	res->flags = type;
 	res->start = 0;
diff -u --recursive --new-file v2.3.36/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c
--- v2.3.36/linux/drivers/pnp/isapnp.c	Tue Dec  7 09:32:45 1999
+++ linux/drivers/pnp/isapnp.c	Thu Jan  6 11:39:35 2000
@@ -39,6 +39,9 @@
 #include <asm/uaccess.h>
 #include <linux/isapnp.h>
 
+LIST_HEAD(isapnp_cards);
+LIST_HEAD(isapnp_devices);
+
 #ifdef CONFIG_PROC_FS
 #include "isapnp_proc.c"
 #endif
@@ -108,9 +111,6 @@
 #define _LTAG_MEM32RANGE	0x85
 #define _LTAG_FIXEDMEM32RANGE	0x86
 
-struct pci_bus *isapnp_cards = NULL;	/* ISA PnP cards */
-struct pci_dev *isapnp_devices = NULL;	/* ISA PnP devices */
-static struct pci_dev *isapnp_last_device = NULL;
 static unsigned char isapnp_checksum_value;
 static DECLARE_MUTEX(isapnp_cfg_mutex);
 static int isapnp_detected = 0;
@@ -749,18 +749,13 @@
 {
 	int number = 0, skip = 0, dependent = 0, compat = 0;
 	unsigned char type, tmp[17];
-	struct pci_dev *dev, *prev_dev;
+	struct pci_dev *dev;
 	struct isapnp_resources *res = NULL;
 	
 	if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
 		return 1;
-	card->devices = dev;
-	if (isapnp_last_device) {
-		isapnp_last_device->next = dev;
-		isapnp_last_device = dev;
-	} else {
-		isapnp_devices = isapnp_last_device = dev;
-	}
+	list_add(&dev->bus_list, &card->devices);
+	list_add_tail(&dev->global_list, &isapnp_devices);
 	while (1) {
 		if (isapnp_read_tag(&type, &size)<0)
 			return 1;
@@ -769,13 +764,11 @@
 		switch (type) {
 		case _STAG_LOGDEVID:
 			if (size >= 5 && size <= 6) {
-				prev_dev = dev;
 				isapnp_config_prepare(dev);
 				if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
 					return 1;
-				prev_dev->sibling = dev;
-				isapnp_last_device->next = dev;
-				isapnp_last_device = dev;
+				list_add_tail(&dev->bus_list, &card->devices);
+				list_add_tail(&dev->global_list, &isapnp_devices);
 				size = 0;
 				skip = 0;
 			} else {
@@ -970,7 +963,7 @@
 {
 	int csn;
 	unsigned char header[9], checksum;
-	struct pci_bus *card, *prev = NULL;
+	struct pci_bus *card;
 
 	isapnp_wait();
 	isapnp_key();
@@ -997,11 +990,8 @@
 		if (isapnp_checksum_value != 0x00)
 			printk("isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value);
 		card->checksum = isapnp_checksum_value;
-		if (!isapnp_cards)
-			isapnp_cards = card;
-		else
-			prev->next = card;
-		prev = card;
+
+		list_add_tail(&card->node, &isapnp_cards);
 	}
 	return 0;
 }
@@ -1012,9 +1002,7 @@
 
 int isapnp_present(void)
 {
-	if (isapnp_devices)
-		return 1;
-	return 0;
+	return !list_empty(&isapnp_devices);
 }
 
 int isapnp_cfg_begin(int csn, int logdev)
@@ -1152,16 +1140,17 @@
 				 unsigned short device,
 				 struct pci_bus *from)
 {
-	struct pci_bus *card;
+	struct list_head *list;
 
-	if (from == NULL) {
-		from = isapnp_cards;
-	} else {
-		from = from->next;
-	}
-	for (card = from; card; card = card->next) {
+	list = isapnp_cards.next;
+	if (from)
+		list = from->node.next;
+
+	while (list != &isapnp_cards) {
+		struct pci_bus *card = list_entry(list, struct pci_bus, node);
 		if (card->vendor == vendor && card->device == device)
 			return card;
+		list = list->next;
 	}
 	return NULL;
 }
@@ -1171,39 +1160,45 @@
 				unsigned short function,
 				struct pci_dev *from)
 {
-	struct pci_dev *dev;
-	int idx;
-	
 	if (card == NULL) {	/* look for a logical device from all cards */
-		if (from == NULL) {
-			from = isapnp_devices;
-		} else {
-			from = from->next;
-		}
-		for (dev = from; dev; dev = dev->next) {
+		struct list_head *list;
+
+		list = isapnp_devices.next;
+		if (from)
+			list = from->global_list.next;
+
+		while (list != &isapnp_devices) {
+			int idx;
+			struct pci_dev *dev = list_entry(list, struct pci_dev, global_list);
+
 			if (dev->vendor == vendor && dev->device == function)
 				return dev;
 			for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++)
 				if (dev->vendor_compatible[idx] == vendor &&
 				    dev->device_compatible[idx] == function)
 					return dev;
+			list = list->next;
 		}
 	} else {
-		if (from == NULL) {
-			from = card->devices;
-		} else {
-			from = from->next;
-		}
+		struct list_head *list;
+
+		list = card->devices.next;
+		if (from)
+			list = from->bus_list.next;
 		if (from->bus != card)	/* something is wrong */
 			return NULL;
-		for (dev = from; dev; dev = dev->sibling) {
+		while (list != &card->devices) {
+			int idx;
+			struct pci_dev *dev = list_entry(list, struct pci_dev, bus_list);
+
 			if (dev->vendor == vendor && dev->device == function)
 				return dev;
 			for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++)
 				if (dev->vendor_compatible[idx] == vendor &&
 				    dev->device_compatible[idx] == function)
 					return dev;
-		}		
+			list = list->next;
+		}
 	}
 	return NULL;
 }
@@ -1442,7 +1437,7 @@
 {
 	int i, tmp, rport, rsize;
 	struct isapnp_port *xport;
-	struct pci_dev *dev;
+	struct list_head *list;
 
 	if (check_region(port, size))
 		return 1;
@@ -1454,7 +1449,9 @@
 		if (port + size > rport && port + size < (rport + rsize) - 1)
 			return 1;
 	}
-	for (dev = isapnp_devices; dev; dev = dev->next) {
+
+	for (list = isapnp_devices.next; list != &isapnp_devices ; list = list->next) {
+		struct pci_dev *dev = list_entry(list, struct pci_dev, global_list);
 		if (dev->active) {
 			for (tmp = 0; tmp < 8; tmp++) {
 				if (dev->resource[tmp].flags) {
@@ -1543,7 +1540,7 @@
 static int isapnp_check_interrupt(struct isapnp_cfgtmp *cfg, int irq, int idx)
 {
 	int i;
-	struct pci_dev *dev;
+	struct list_head *list;
 
 	if (irq < 0 || irq > 15)
 		return 1;
@@ -1551,7 +1548,8 @@
 		if (isapnp_reserve_irq[i] == irq)
 			return 1;
 	}
-	for (dev = isapnp_devices; dev; dev = dev->next) {
+	for (list = isapnp_devices.next; list != &isapnp_devices; list = list->next) {
+		struct pci_dev *dev = list_entry(list, struct pci_dev, global_list);
 		if (dev->active) {
 			if (dev->irq_resource[0].start == irq ||
 			    dev->irq_resource[1].start == irq)
@@ -1622,7 +1620,7 @@
 static int isapnp_check_dma(struct isapnp_cfgtmp *cfg, int dma, int idx)
 {
 	int i;
-	struct pci_dev *dev;
+	struct list_head *list;
 
 	if (dma < 0 || dma == 4 || dma > 7)
 		return 1;
@@ -1630,7 +1628,8 @@
 		if (isapnp_reserve_dma[i] == dma)
 			return 1;
 	}
-	for (dev = isapnp_devices; dev; dev = dev->next) {
+	for (list = isapnp_devices.next; list != &isapnp_devices ; list = list->next) {
+		struct pci_dev *dev = list_entry(list, struct pci_dev, global_list);
 		if (dev->active) {
 			if (dev->dma_resource[0].start == dma || dev->dma_resource[1].start == dma)
 				return 1;
@@ -1695,8 +1694,8 @@
 {
 	int i, tmp;
 	unsigned int raddr, rsize;
-	struct pci_dev *dev;
 	struct isapnp_mem *xmem;
+	struct list_head *list;
 
 	for (i = 0; i < 8; i++) {
 		raddr = (unsigned int)isapnp_reserve_mem[i << 1];
@@ -1708,7 +1707,8 @@
 		if (__check_region(&iomem_resource, addr, size))
 			return 1;
 	}
-	for (dev = isapnp_devices; dev; dev = dev->next) {
+	for (list = isapnp_devices.next; list != &isapnp_devices ; list = list->next) {
+		struct pci_dev *dev = list_entry(list, struct pci_dev, global_list);
 		if (dev->active) {
 			for (tmp = 0; tmp < 4; tmp++) {
 				if (dev->resource[tmp].flags) {
@@ -2052,23 +2052,14 @@
 
 static void __init isapnp_pci_init(void)
 {
-	int devfn;
 	struct pci_dev *dev;
-	
-	for (devfn = 0; devfn < 255; devfn++) {
-		dev = pci_find_slot(0, devfn);
-		if (dev != NULL)
-			break;
-	}
-	if (dev == NULL)
-		return;
-	while (dev) {
+
+	pci_for_each_dev(dev) {
 #ifdef ISAPNP_DEBUG
 		printk("PCI: reserved IRQ: %i\n", dev->irq);
 #endif
 		if (dev->irq > 0)
 			isapnp_do_reserve_irq(dev->irq);
-		dev = dev->next;
 	}
 }
 
@@ -2094,8 +2085,7 @@
 int __init isapnp_init(void)
 {
 	int cards;
-	struct pci_bus *card;
-	struct pci_dev *dev;
+	struct list_head *list;
 
 	if (isapnp_disable) {
 		isapnp_detected = 0;
@@ -2144,15 +2134,20 @@
 	}
 	isapnp_build_device_list();
 	cards = 0;
-	for (card = isapnp_cards; card; card = card->next)
+
+	for (list = isapnp_cards.next; list != &isapnp_cards; list=list->next) {
+		struct pci_bus *card = list_entry(list, struct pci_bus, node);
+
 		cards++;
-	if (isapnp_verbose) {
-		for (card = isapnp_cards; card; card = card->next) {
+		if (isapnp_verbose) {
+			struct list_head *devlist;
 			printk( "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown");
 			if (isapnp_verbose < 2)
 				continue;
-			for (dev = card->devices; dev; dev = dev->next)
+			for (devlist = card->devices.next; devlist != &card->devices; devlist = devlist->next) {
+				struct pci_dev *dev = list_entry(list, struct pci_dev, bus_list);
 				printk("isapnp:   Device '%s'\n", dev->name[0]?card->name:"Unknown");
+			}
 		}
 	}
 	if (cards) {
diff -u --recursive --new-file v2.3.36/linux/drivers/pnp/isapnp_proc.c linux/drivers/pnp/isapnp_proc.c
--- v2.3.36/linux/drivers/pnp/isapnp_proc.c	Tue Dec  7 09:32:45 1999
+++ linux/drivers/pnp/isapnp_proc.c	Thu Jan  6 10:54:12 2000
@@ -20,8 +20,6 @@
  */
 
 static void *isapnp_alloc(long size);
-struct pci_bus *isapnp_cards;
-struct pci_dev *isapnp_devices;
 
 struct isapnp_info_buffer {
 	char *buffer;		/* pointer to begin of buffer */
@@ -539,10 +537,12 @@
  
 static void isapnp_info_read(isapnp_info_buffer_t *buffer)
 {
-	struct pci_bus *card;
-	struct pci_dev *dev;
+	struct list_head *card_list;
 	
-	for (card = isapnp_cards; card; card = card->next) {
+	for (card_list = isapnp_cards.next; card_list != &isapnp_cards; card_list = card_list->next) {
+		struct pci_bus *card = list_entry(card_list, struct pci_bus, node);
+		struct list_head *dev_list;
+
 		isapnp_printf(buffer, "Card %i '", card->number);
 		isapnp_print_devid(buffer, card->vendor, card->device);
 		isapnp_printf(buffer, ":%s'", card->name[0]?card->name:"Unknown");
@@ -551,8 +551,10 @@
 		if (card->productver)
 			isapnp_printf(buffer, " Product version %x.%x", card->productver >> 4, card->productver & 0x0f);
 		isapnp_printf(buffer,"\n");
-		for (dev = card->devices; dev; dev = dev->sibling)
+		for (dev_list = card->devices.next; dev_list != &card->devices; dev_list = dev_list->next) {
+			struct pci_dev *dev = list_entry(dev_list, struct pci_dev, bus_list);
 			isapnp_print_device(buffer, dev);
+		}
 	}
 }
 
@@ -640,14 +642,17 @@
 static int isapnp_select_csn(char *line)
 {
 	int csn;
+	struct list_head *list;
 	char index[16], value[32];
 
 	isapnp_info_device = NULL;
 	isapnp_get_str(index, line, sizeof(index));
 	csn = simple_strtoul(index, NULL, 0);
-	for (isapnp_info_card = isapnp_cards; isapnp_info_card; isapnp_info_card = isapnp_info_card->next)
+	for (list = isapnp_cards.next; list != &isapnp_cards; list = list->next) {
+		isapnp_info_card = list_entry(list, struct pci_bus, node);
 		if (isapnp_info_card->number == csn)
 			break;
+	}
 	if (isapnp_info_card == NULL) {
 		printk("isapnp: cannot find CSN %i\n", csn);
 		return 1;
diff -u --recursive --new-file v2.3.36/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.3.36/linux/drivers/scsi/megaraid.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/scsi/megaraid.c	Thu Jan  6 09:54:06 2000
@@ -1411,37 +1411,27 @@
 {
   mega_host_config *megaCfg;
   struct Scsi_Host *host;
-  u_char pciBus, pciDevFun, megaIrq;
+  u_char megaIrq;
   u32 megaBase;
-  u16 pciIdx = 0;
   u16 numFound = 0;
 
-  struct pci_dev *pdev = pci_devices;
+  struct pci_dev *pdev = NULL;
   
   while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
-    pciBus = pdev->bus->number;
-    pciDevFun = pdev->devfn;
     if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
       u16 magic;
-      pcibios_read_config_word (pciBus, pciDevFun,
-				PCI_CONF_AMISIG,
-				&magic);
-      if (magic != AMI_SIGNATURE) {
-        pciIdx++;
+      pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic);
+      if (magic != AMI_SIGNATURE)
 	continue;		/* not an AMI board */
-      }
     }
-    printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n",
+    printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x: in %s\n",
 	    pciVendor,
 	    pciDev,
-	    pciIdx, pciBus,
-	    PCI_SLOT (pciDevFun),
-	    PCI_FUNC (pciDevFun));
+	    pdev->slot_name);
 
     /* Read the base port and IRQ from PCI */
     megaBase = pdev->resource[0].start;
     megaIrq  = pdev->irq;
-    pciIdx++;
 
     if (flag & BOARD_QUARTZ) {
 
@@ -1470,7 +1460,7 @@
     megaCfg->host->irq = megaIrq;
     megaCfg->host->io_port = megaBase;
     megaCfg->host->n_io_port = 16;
-    megaCfg->host->unique_id = (pciBus << 8) | pciDevFun;
+    megaCfg->host->unique_id = (pdev->bus->number << 8) | pdev->devfn;
     megaCtlrs[numCtlrs++] = megaCfg; 
     if (flag != BOARD_QUARTZ) {
       /* Request our IO Range */
diff -u --recursive --new-file v2.3.36/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.3.36/linux/drivers/sound/es1370.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/sound/es1370.c	Wed Jan  5 08:22:31 2000
@@ -3,7 +3,7 @@
 /*
  *      es1370.c  --  Ensoniq ES1370/Asahi Kasei AK4531 audio driver.
  *
- *      Copyright (C) 1998-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *      Copyright (C) 1998-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *      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
@@ -52,68 +52,68 @@
  *  there are several MIDI to PCM (WAV) packages, one of them is timidity.
  *
  *  Revision history
- *    26.03.98   0.1   Initial release
- *    31.03.98   0.2   Fix bug in GETOSPACE
- *    04.04.98   0.3   Make it work (again) under 2.0.33
- *                     Fix mixer write operation not returning the actual
- *                     settings
- *    05.04.98   0.4   First attempt at using the new PCI stuff
- *    29.04.98   0.5   Fix hang when ^C is pressed on amp
- *    07.05.98   0.6   Don't double lock around stop_*() in *_release()
- *    10.05.98   0.7   First stab at a simple midi interface (no bells&whistles)
- *    14.05.98   0.8   Don't allow excessive interrupt rates
- *    08.06.98   0.9   First release using Alan Cox' soundcore instead of
- *                     miscdevice
- *    05.07.98   0.10  Fixed the driver to correctly maintin OSS style volume
- *                     settings (not sure if this should be standard)
- *                     Fixed many references: f_flags should be f_mode
- *                     -- Gerald Britton <gbritton@mit.edu>
- *    03.08.98   0.11  Now mixer behaviour can basically be selected between
- *                     "OSS documented" and "OSS actual" behaviour
- *                     Fixed mixer table thanks to Hakan.Lennestal@lu.erisoft.se
- *                     On module startup, set DAC2 to 11kSPS instead of 5.5kSPS,
- *                     as it produces an annoying ssssh in the lower sampling rate
- *                     Do not include modversions.h
- *    22.08.98   0.12  Mixer registers actually have 5 instead of 4 bits
- *                     pointed out by Itai Nahshon
- *    31.08.98   0.13  Fix realplayer problems - dac.count issues
- *    08.10.98   0.14  Joystick support fixed
- *		       -- Oliver Neukum <c188@org.chemie.uni-muenchen.de>
- *    10.12.98   0.15  Fix drain_dac trying to wait on not yet initialized DMA
- *    16.12.98   0.16  Don't wake up app until there are fragsize bytes to read/write
- *    06.01.99   0.17  remove the silly SA_INTERRUPT flag.
- *                     hopefully killed the egcs section type conflict
- *    12.03.99   0.18  cinfo.blocks should be reset after GETxPTR ioctl.
- *                     reported by Johan Maes <joma@telindus.be>
- *    22.03.99   0.19  return EAGAIN instead of EBUSY when O_NONBLOCK
- *                     read/write cannot be executed
- *    07.04.99   0.20  implemented the following ioctl's: SOUND_PCM_READ_RATE, 
- *                     SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; 
- *                     Alpha fixes reported by Peter Jones <pjones@redhat.com>
- *                     Note: joystick address handling might still be wrong on archs
- *                     other than i386
- *    10.05.99   0.21  Added support for an electret mic for SB PCI64
- *                     to the Linux kernel sound driver. This mod also straighten
- *                     out the question marks around the mic impedance setting
- *                     (micz). From Kim.Berts@fisub.mail.abb.com
- *    11.05.99   0.22  Implemented the IMIX call to mute recording monitor.
- *                     Guenter Geiger <geiger@epy.co.at>
- *    15.06.99   0.23  Fix bad allocation bug.
- *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
- *    28.06.99   0.24  Add pci_set_master
- *    02.08.99   0.25  Added workaround for the "phantom write" bug first
- *                     documented by Dave Sharpless from Anchor Games
- *    03.08.99   0.26  adapt to Linus' new __setup/__initcall
- *                     added kernel command line option "es1370=joystick[,lineout[,micbias]]"
- *                     removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
- *    12.08.99   0.27  module_init/__setup fixes
- *    19.08.99   0.28  SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
- *    31.08.99   0.29  add spin_lock_init
- *                     __initlocaldata to fix gcc 2.7.x problems
- *                     replaced current->state = x with set_current_state(x)
- *    03.09.99   0.30  change read semantics for MIDI to match
- *                     OSS more closely; remove possible wakeup race
- *    28.10.99   0.31  More waitqueue races fixed
+ *    26.03.1998   0.1   Initial release
+ *    31.03.1998   0.2   Fix bug in GETOSPACE
+ *    04.04.1998   0.3   Make it work (again) under 2.0.33
+ *                       Fix mixer write operation not returning the actual
+ *                       settings
+ *    05.04.1998   0.4   First attempt at using the new PCI stuff
+ *    29.04.1998   0.5   Fix hang when ^C is pressed on amp
+ *    07.05.1998   0.6   Don't double lock around stop_*() in *_release()
+ *    10.05.1998   0.7   First stab at a simple midi interface (no bells&whistles)
+ *    14.05.1998   0.8   Don't allow excessive interrupt rates
+ *    08.06.1998   0.9   First release using Alan Cox' soundcore instead of
+ *                       miscdevice
+ *    05.07.1998   0.10  Fixed the driver to correctly maintin OSS style volume
+ *                       settings (not sure if this should be standard)
+ *                       Fixed many references: f_flags should be f_mode
+ *                       -- Gerald Britton <gbritton@mit.edu>
+ *    03.08.1998   0.11  Now mixer behaviour can basically be selected between
+ *                       "OSS documented" and "OSS actual" behaviour
+ *                       Fixed mixer table thanks to Hakan.Lennestal@lu.erisoft.se
+ *                       On module startup, set DAC2 to 11kSPS instead of 5.5kSPS,
+ *                       as it produces an annoying ssssh in the lower sampling rate
+ *                       Do not include modversions.h
+ *    22.08.1998   0.12  Mixer registers actually have 5 instead of 4 bits
+ *                       pointed out by Itai Nahshon
+ *    31.08.1998   0.13  Fix realplayer problems - dac.count issues
+ *    08.10.1998   0.14  Joystick support fixed
+ *		         -- Oliver Neukum <c188@org.chemie.uni-muenchen.de>
+ *    10.12.1998   0.15  Fix drain_dac trying to wait on not yet initialized DMA
+ *    16.12.1998   0.16  Don't wake up app until there are fragsize bytes to read/write
+ *    06.01.1999   0.17  remove the silly SA_INTERRUPT flag.
+ *                       hopefully killed the egcs section type conflict
+ *    12.03.1999   0.18  cinfo.blocks should be reset after GETxPTR ioctl.
+ *                       reported by Johan Maes <joma@telindus.be>
+ *    22.03.1999   0.19  return EAGAIN instead of EBUSY when O_NONBLOCK
+ *                       read/write cannot be executed
+ *    07.04.1999   0.20  implemented the following ioctl's: SOUND_PCM_READ_RATE, 
+ *                       SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; 
+ *                       Alpha fixes reported by Peter Jones <pjones@redhat.com>
+ *                       Note: joystick address handling might still be wrong on archs
+ *                       other than i386
+ *    10.05.1999   0.21  Added support for an electret mic for SB PCI64
+ *                       to the Linux kernel sound driver. This mod also straighten
+ *                       out the question marks around the mic impedance setting
+ *                       (micz). From Kim.Berts@fisub.mail.abb.com
+ *    11.05.1999   0.22  Implemented the IMIX call to mute recording monitor.
+ *                       Guenter Geiger <geiger@epy.co.at>
+ *    15.06.1999   0.23  Fix bad allocation bug.
+ *                       Thanks to Deti Fliegl <fliegl@in.tum.de>
+ *    28.06.1999   0.24  Add pci_set_master
+ *    02.08.1999   0.25  Added workaround for the "phantom write" bug first
+ *                       documented by Dave Sharpless from Anchor Games
+ *    03.08.1999   0.26  adapt to Linus' new __setup/__initcall
+ *                       added kernel command line option "es1370=joystick[,lineout[,micbias]]"
+ *                       removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
+ *    12.08.1999   0.27  module_init/__setup fixes
+ *    19.08.1999   0.28  SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
+ *    31.08.1999   0.29  add spin_lock_init
+ *                       __initlocaldata to fix gcc 2.7.x problems
+ *                       replaced current->state = x with set_current_state(x)
+ *    03.09.1999   0.30  change read semantics for MIDI to match
+ *                       OSS more closely; remove possible wakeup race
+ *    28.10.1999   0.31  More waitqueue races fixed
  *
  * some important things missing in Ensoniq documentation:
  *
diff -u --recursive --new-file v2.3.36/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.3.36/linux/drivers/sound/es1371.c	Tue Dec  7 09:32:46 1999
+++ linux/drivers/sound/es1371.c	Wed Jan  5 08:22:31 2000
@@ -3,7 +3,7 @@
 /*
  *      es1371.c  --  Creative Ensoniq ES1371.
  *
- *      Copyright (C) 1998-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *      Copyright (C) 1998-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *      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
@@ -38,62 +38,64 @@
  *  there are several MIDI to PCM (WAV) packages, one of them is timidity.
  *
  *  Revision history
- *    04.06.98   0.1   Initial release
- *                     Mixer stuff should be overhauled; especially optional AC97 mixer bits
- *                     should be detected. This results in strange behaviour of some mixer
- *                     settings, like master volume and mic.
- *    08.06.98   0.2   First release using Alan Cox' soundcore instead of miscdevice
- *    03.08.98   0.3   Do not include modversions.h
- *                     Now mixer behaviour can basically be selected between
- *                     "OSS documented" and "OSS actual" behaviour
- *    31.08.98   0.4   Fix realplayer problems - dac.count issues
- *    27.10.98   0.5   Fix joystick support
- *                     -- Oliver Neukum (c188@org.chemie.uni-muenchen.de)
- *    10.12.98   0.6   Fix drain_dac trying to wait on not yet initialized DMA
- *    23.12.98   0.7   Fix a few f_file & FMODE_ bugs
- *                     Don't wake up app until there are fragsize bytes to read/write
- *    06.01.99   0.8   remove the silly SA_INTERRUPT flag.
- *                     hopefully killed the egcs section type conflict
- *    12.03.99   0.9   cinfo.blocks should be reset after GETxPTR ioctl.
- *                     reported by Johan Maes <joma@telindus.be>
- *    22.03.99   0.10  return EAGAIN instead of EBUSY when O_NONBLOCK
- *                     read/write cannot be executed
- *    07.04.99   0.11  implemented the following ioctl's: SOUND_PCM_READ_RATE, 
- *                     SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; 
- *                     Alpha fixes reported by Peter Jones <pjones@redhat.com>
- *                     Another Alpha fix (wait_src_ready in init routine)
- *                     reported by "Ivan N. Kokshaysky" <ink@jurassic.park.msu.ru>
- *                     Note: joystick address handling might still be wrong on archs
- *                     other than i386
- *    15.06.99   0.12  Fix bad allocation bug.
- *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
- *    28.06.99   0.13  Add pci_set_master
- *    03.08.99   0.14  adapt to Linus' new __setup/__initcall
- *                     added kernel command line option "es1371=joystickaddr"
- *                     removed CONFIG_SOUND_ES1371_JOYPORT_BOOT kludge
- *    10.08.99   0.15  (Re)added S/PDIF module option for cards revision >= 4.
- *                     Initial version by Dave Platt <dplatt@snulbug.mtview.ca.us>.
- *                     module_init/__setup fixes
- *    08.16.99   0.16  Joe Cotellese <joec@ensoniq.com>
- *                     Added detection for ES1371 revision ID so that we can
- *                     detect the ES1373 and later parts.
- *                     added AC97 #defines for readability
- *                     added a /proc file system for dumping hardware state
- *                     updated SRC and CODEC w/r functions to accomodate bugs
- *                     in some versions of the ES137x chips.
- *    31.08.99   0.17  add spin_lock_init
- *                     __initlocaldata to fix gcc 2.7.x problems
- *                     replaced current->state = x with set_current_state(x)
- *    03.09.99   0.18  change read semantics for MIDI to match
- *                     OSS more closely; remove possible wakeup race
- *    21.10.99   0.19  Round sampling rates, requested by
- *                     Kasamatsu Kenichi <t29w0267@ip.media.kyoto-u.ac.jp>
- *    27.10.99   0.20  Added SigmaTel 3D enhancement string
- *                     Codec ID printing changes
- *    28.10.99   0.21  More waitqueue races fixed
- *                     Joe Cotellese <joec@ensoniq.com>
- *                     Changed PCI detection routine so we can more easily
- *                     detect ES137x chip and derivatives.
+ *    04.06.1998   0.1   Initial release
+ *                       Mixer stuff should be overhauled; especially optional AC97 mixer bits
+ *                       should be detected. This results in strange behaviour of some mixer
+ *                       settings, like master volume and mic.
+ *    08.06.1998   0.2   First release using Alan Cox' soundcore instead of miscdevice
+ *    03.08.1998   0.3   Do not include modversions.h
+ *                       Now mixer behaviour can basically be selected between
+ *                       "OSS documented" and "OSS actual" behaviour
+ *    31.08.1998   0.4   Fix realplayer problems - dac.count issues
+ *    27.10.1998   0.5   Fix joystick support
+ *                       -- Oliver Neukum (c188@org.chemie.uni-muenchen.de)
+ *    10.12.1998   0.6   Fix drain_dac trying to wait on not yet initialized DMA
+ *    23.12.1998   0.7   Fix a few f_file & FMODE_ bugs
+ *                       Don't wake up app until there are fragsize bytes to read/write
+ *    06.01.1999   0.8   remove the silly SA_INTERRUPT flag.
+ *                       hopefully killed the egcs section type conflict
+ *    12.03.1999   0.9   cinfo.blocks should be reset after GETxPTR ioctl.
+ *                       reported by Johan Maes <joma@telindus.be>
+ *    22.03.1999   0.10  return EAGAIN instead of EBUSY when O_NONBLOCK
+ *                       read/write cannot be executed
+ *    07.04.1999   0.11  implemented the following ioctl's: SOUND_PCM_READ_RATE, 
+ *                       SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; 
+ *                       Alpha fixes reported by Peter Jones <pjones@redhat.com>
+ *                       Another Alpha fix (wait_src_ready in init routine)
+ *                       reported by "Ivan N. Kokshaysky" <ink@jurassic.park.msu.ru>
+ *                       Note: joystick address handling might still be wrong on archs
+ *                       other than i386
+ *    15.06.1999   0.12  Fix bad allocation bug.
+ *                       Thanks to Deti Fliegl <fliegl@in.tum.de>
+ *    28.06.1999   0.13  Add pci_set_master
+ *    03.08.1999   0.14  adapt to Linus' new __setup/__initcall
+ *                       added kernel command line option "es1371=joystickaddr"
+ *                       removed CONFIG_SOUND_ES1371_JOYPORT_BOOT kludge
+ *    10.08.1999   0.15  (Re)added S/PDIF module option for cards revision >= 4.
+ *                       Initial version by Dave Platt <dplatt@snulbug.mtview.ca.us>.
+ *                       module_init/__setup fixes
+ *    08.16.1999   0.16  Joe Cotellese <joec@ensoniq.com>
+ *                       Added detection for ES1371 revision ID so that we can
+ *                       detect the ES1373 and later parts.
+ *                       added AC97 #defines for readability
+ *                       added a /proc file system for dumping hardware state
+ *                       updated SRC and CODEC w/r functions to accomodate bugs
+ *                       in some versions of the ES137x chips.
+ *    31.08.1999   0.17  add spin_lock_init
+ *                       __initlocaldata to fix gcc 2.7.x problems
+ *                       replaced current->state = x with set_current_state(x)
+ *    03.09.1999   0.18  change read semantics for MIDI to match
+ *                       OSS more closely; remove possible wakeup race
+ *    21.10.1999   0.19  Round sampling rates, requested by
+ *                       Kasamatsu Kenichi <t29w0267@ip.media.kyoto-u.ac.jp>
+ *    27.10.1999   0.20  Added SigmaTel 3D enhancement string
+ *                       Codec ID printing changes
+ *    28.10.1999   0.21  More waitqueue races fixed
+ *                       Joe Cotellese <joec@ensoniq.com>
+ *                       Changed PCI detection routine so we can more easily
+ *                       detect ES137x chip and derivatives.
+ *    05.01.2000   0.22  Should now work with rev7 boards; patch by
+ *                       Eric Lemar, elemar@cs.washington.edu
  */
 
 /*****************************************************************************/
@@ -1260,7 +1262,7 @@
 		
 	case SOUND_MIXER_SPEAKER:
 		j = rdcodec(s, AC97_PCBEEP_VOL);
-		if (j & AC97_MUTE
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 		return put_user(0x6464 - ((j >> 1) & 0xf) * 0x606, (int *)arg);
 		
@@ -3132,8 +3134,8 @@
 	pci_set_master(pcidev);  /* enable bus mastering */
 	/* if we are a 5880 turn on the AC97 */
 	if (s->vendor == PCI_VENDOR_ID_ENSONIQ &&
-	    s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 &&
-	    s->rev == CT5880REV_CT5880_C) {
+	    ((s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && s->rev == CT5880REV_CT5880_C) || 
+	     (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_CT5880_A))) { 
 		cssr |= CSTAT_5880_AC97_RST;
 		outl(cssr, s->io+ES1371_REG_STATUS);
 		/* need to delay around 20ms(bleech) to give
diff -u --recursive --new-file v2.3.36/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.3.36/linux/drivers/sound/esssolo1.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/sound/esssolo1.c	Wed Jan  5 08:22:31 2000
@@ -61,6 +61,8 @@
  *    07.10.99   0.9   Fix initialization; complain if sequencer writes time out
  *                     Revised resource grabbing for the FM synthesizer
  *    28.10.99   0.10  More waitqueue races fixed
+ *    09.12.99   0.11  Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M)
+ *                     Disabling recording on Alpha
  *
  */
 
@@ -419,6 +421,14 @@
 				break;
 		if (!db->rawbuf)
 			return -ENOMEM;
+		/* work around a problem of the alpha port */
+		if ((gfp_mask & GFP_DMA) && (virt_to_bus(db->rawbuf) & (~0xffffffUL))) {
+			printk(KERN_ERR "solo1: requested DMA buffer below 16M but got 0x%lx, Alpha bug?\n", 
+			       (unsigned long)virt_to_bus(db->rawbuf));
+			kfree(db->rawbuf);
+			db->rawbuf = NULL;
+			return -ENOMEM;
+		}
 		db->buforder = order;
 		/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
 		mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
@@ -1417,6 +1427,12 @@
 		if (s->dma_dac.mapped)
 			s->dma_dac.count &= s->dma_dac.fragsize-1;
 		spin_unlock_irqrestore(&s->lock, flags);
+#if 0
+		printk(KERN_DEBUG "esssolo1: GETOPTR: bytes %u blocks %u ptr %u, buforder %u numfrag %u fragshift %u\n"
+		       KERN_DEBUG "esssolo1: swptr %u count %u fragsize %u dmasize %u fragsamples %u\n",
+		       cinfo.bytes, cinfo.blocks, cinfo.ptr, s->dma_dac.buforder, s->dma_dac.numfrag, s->dma_dac.fragshift,
+		       s->dma_dac.swptr, s->dma_dac.count, s->dma_dac.fragsize, s->dma_dac.dmasize, s->dma_dac.fragsamples);
+#endif
                 return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
 
         case SNDCTL_DSP_GETBLKSIZE:
@@ -1549,10 +1565,6 @@
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 	up(&s->open_sem);
 	MOD_INC_USE_COUNT;
-	if (prog_dmabuf_dac(s) || prog_dmabuf_adc(s)) {
-		solo1_release(inode, file);
-		return -ENOMEM;
-	}
 	prog_codec(s);
 	return 0;
 }
@@ -2142,7 +2154,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "solo1: version v0.10 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "solo1: version v0.11 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
 		if (!RSRCISIOREGION(pcidev, 0) ||
diff -u --recursive --new-file v2.3.36/linux/drivers/sound/nm256_audio.c linux/drivers/sound/nm256_audio.c
--- v2.3.36/linux/drivers/sound/nm256_audio.c	Wed Oct 27 16:34:12 1999
+++ linux/drivers/sound/nm256_audio.c	Wed Jan  5 10:47:14 2000
@@ -45,14 +45,7 @@
 #define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
 #define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006
 
-/* eeeew. */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
 #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-#else
-#define RSRCADDRESS(dev,num) ((dev)->base_address[(num)] \
-			      & PCI_BASE_ADDRESS_MEM_MASK)
-
-#endif
 
 /* List of cards.  */
 static struct nm256_info *nmcard_list;
diff -u --recursive --new-file v2.3.36/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.3.36/linux/drivers/sound/sonicvibes.c	Wed Dec  8 14:11:26 1999
+++ linux/drivers/sound/sonicvibes.c	Wed Jan  5 08:22:31 2000
@@ -3,7 +3,7 @@
 /*
  *      sonicvibes.c  --  S3 Sonic Vibes audio driver.
  *
- *      Copyright (C) 1998-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *      Copyright (C) 1998-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *      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
@@ -35,55 +35,55 @@
  *  out first how to drive them...
  *
  *  Revision history
- *    06.05.98   0.1   Initial release
- *    10.05.98   0.2   Fixed many bugs, esp. ADC rate calculation
- *                     First stab at a simple midi interface (no bells&whistles)
- *    13.05.98   0.3   Fix stupid cut&paste error: set_adc_rate was called instead of
- *                     set_dac_rate in the FMODE_WRITE case in sv_open
- *                     Fix hwptr out of bounds (now mpg123 works)
- *    14.05.98   0.4   Don't allow excessive interrupt rates
- *    08.06.98   0.5   First release using Alan Cox' soundcore instead of miscdevice
- *    03.08.98   0.6   Do not include modversions.h
- *                     Now mixer behaviour can basically be selected between
- *                     "OSS documented" and "OSS actual" behaviour
- *    31.08.98   0.7   Fix realplayer problems - dac.count issues
- *    10.12.98   0.8   Fix drain_dac trying to wait on not yet initialized DMA
- *    16.12.98   0.9   Fix a few f_file & FMODE_ bugs
- *    06.01.99   0.10  remove the silly SA_INTERRUPT flag.
- *                     hopefully killed the egcs section type conflict
- *    12.03.99   0.11  cinfo.blocks should be reset after GETxPTR ioctl.
- *                     reported by Johan Maes <joma@telindus.be>
- *    22.03.99   0.12  return EAGAIN instead of EBUSY when O_NONBLOCK
- *                     read/write cannot be executed
- *    05.04.99   0.13  added code to sv_read and sv_write which should detect
- *                     lockups of the sound chip and revive it. This is basically
- *                     an ugly hack, but at least applications using this driver
- *                     won't hang forever. I don't know why these lockups happen,
- *                     it might well be the motherboard chipset (an early 486 PCI
- *                     board with ALI chipset), since every busmastering 100MB
- *                     ethernet card I've tried (Realtek 8139 and Macronix tulip clone)
- *                     exhibit similar behaviour (they work for a couple of packets
- *                     and then lock up and can be revived by ifconfig down/up).
- *    07.04.99   0.14  implemented the following ioctl's: SOUND_PCM_READ_RATE, 
- *                     SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; 
- *                     Alpha fixes reported by Peter Jones <pjones@redhat.com>
- *                     Note: dmaio hack might still be wrong on archs other than i386
- *    15.06.99   0.15  Fix bad allocation bug.
- *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
- *    28.06.99   0.16  Add pci_set_master
- *    03.08.99   0.17  adapt to Linus' new __setup/__initcall
- *                     added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
- *    12.08.99   0.18  module_init/__setup fixes
- *    24.08.99   0.19  get rid of the dmaio kludge, replace with allocate_resource
- *    31.08.99   0.20  add spin_lock_init
- *                     __initlocaldata to fix gcc 2.7.x problems
- *                     use new resource allocation to allocate DDMA IO space
- *                     replaced current->state = x with set_current_state(x)
- *    03.09.99   0.21  change read semantics for MIDI to match
- *                     OSS more closely; remove possible wakeup race
- *    28.10.99   0.22  More waitqueue races fixed
- *    01.12.99   0.23  New argument to allocate_resource
- *    07.12.99   0.24  More allocate_resource semantics change
+ *    06.05.1998   0.1   Initial release
+ *    10.05.1998   0.2   Fixed many bugs, esp. ADC rate calculation
+ *                       First stab at a simple midi interface (no bells&whistles)
+ *    13.05.1998   0.3   Fix stupid cut&paste error: set_adc_rate was called instead of
+ *                       set_dac_rate in the FMODE_WRITE case in sv_open
+ *                       Fix hwptr out of bounds (now mpg123 works)
+ *    14.05.1998   0.4   Don't allow excessive interrupt rates
+ *    08.06.1998   0.5   First release using Alan Cox' soundcore instead of miscdevice
+ *    03.08.1998   0.6   Do not include modversions.h
+ *                       Now mixer behaviour can basically be selected between
+ *                       "OSS documented" and "OSS actual" behaviour
+ *    31.08.1998   0.7   Fix realplayer problems - dac.count issues
+ *    10.12.1998   0.8   Fix drain_dac trying to wait on not yet initialized DMA
+ *    16.12.1998   0.9   Fix a few f_file & FMODE_ bugs
+ *    06.01.1999   0.10  remove the silly SA_INTERRUPT flag.
+ *                       hopefully killed the egcs section type conflict
+ *    12.03.1999   0.11  cinfo.blocks should be reset after GETxPTR ioctl.
+ *                       reported by Johan Maes <joma@telindus.be>
+ *    22.03.1999   0.12  return EAGAIN instead of EBUSY when O_NONBLOCK
+ *                       read/write cannot be executed
+ *    05.04.1999   0.13  added code to sv_read and sv_write which should detect
+ *                       lockups of the sound chip and revive it. This is basically
+ *                       an ugly hack, but at least applications using this driver
+ *                       won't hang forever. I don't know why these lockups happen,
+ *                       it might well be the motherboard chipset (an early 486 PCI
+ *                       board with ALI chipset), since every busmastering 100MB
+ *                       ethernet card I've tried (Realtek 8139 and Macronix tulip clone)
+ *                       exhibit similar behaviour (they work for a couple of packets
+ *                       and then lock up and can be revived by ifconfig down/up).
+ *    07.04.1999   0.14  implemented the following ioctl's: SOUND_PCM_READ_RATE, 
+ *                       SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; 
+ *                       Alpha fixes reported by Peter Jones <pjones@redhat.com>
+ *                       Note: dmaio hack might still be wrong on archs other than i386
+ *    15.06.1999   0.15  Fix bad allocation bug.
+ *                       Thanks to Deti Fliegl <fliegl@in.tum.de>
+ *    28.06.1999   0.16  Add pci_set_master
+ *    03.08.1999   0.17  adapt to Linus' new __setup/__initcall
+ *                       added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
+ *    12.08.1999   0.18  module_init/__setup fixes
+ *    24.08.1999   0.19  get rid of the dmaio kludge, replace with allocate_resource
+ *    31.08.1999   0.20  add spin_lock_init
+ *                       __initlocaldata to fix gcc 2.7.x problems
+ *                       use new resource allocation to allocate DDMA IO space
+ *                       replaced current->state = x with set_current_state(x)
+ *    03.09.1999   0.21  change read semantics for MIDI to match
+ *                       OSS more closely; remove possible wakeup race
+ *    28.10.1999   0.22  More waitqueue races fixed
+ *    01.12.1999   0.23  New argument to allocate_resource
+ *    07.12.1999   0.24  More allocate_resource semantics change
  *
  */
 
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/CREDITS linux/drivers/usb/CREDITS
--- v2.3.36/linux/drivers/usb/CREDITS	Sun Nov  7 16:37:34 1999
+++ linux/drivers/usb/CREDITS	Wed Dec 31 16:00:00 1969
@@ -1,160 +0,0 @@
-Credits for the Simple Linux USB Driver:
-
-The following people have contributed to this code (in alphabetical
-order by last name).  I'm sure this list should be longer, its
-difficult to maintain, add yourself with a patch if desired.
-
-  Alan Cox <alan@lxorguk.ukuu.org.uk>
-  Johannes Erdfelt <jerdfelt@sventech.com>
-  ham <ham@unsuave.com>
-  Bradley M Keryan <keryan@andrew.cmu.edu>
-  Paul Mackerras <paulus@cs.anu.edu.au>
-  David E. Nelson <dnelson@jump.net>
-  Vojtech Pavlik <vojtech@suse.cz>
-  Gregory P. Smith <greg@electricrain.com>
-  Linus Torvalds <torvalds@transmeta.com>
-  Roman Weissgaerber <weissg@vienna.at>
-  <Kazuki.Yasumatsu@fujixerox.co.jp>
-
-Special thanks to:
-
-  Inaky Perez Gonzalez <inaky@peloncho.fis.ucm.es> for starting the
-  Linux USB driver effort and writing much of the larger uusbd driver.
-  Much has been learned from that effort.
-
-  The NetBSD & FreeBSD USB developers.  For being on the Linux USB list
-  and offering suggestions and sharing implementation experiences.
-
-Additional thanks to the following companies and people for donations
-of hardware, support, time and development (this is from the original
-THANKS file in Inaky's driver):
-
-        The following corporations have helped us in the development
-        of Linux USB / UUSBD:
-
-	- 3Com GmbH for donating a ISDN Pro TA and supporting me
-	  in technical questions and with test equipment. I'd never 
-	  expect such a great help.
-
-        - USAR Systems provided us with one of their excellent USB
-          Evaluation Kits. It allows us to test the Linux-USB driver
-          for compilance with the latest USB specification. USAR
-          Systems recognized the importance of an up-to-date open
-          Operating System and supports this project with
-          Hardware. Thanks!.
-
-        - Thanks to Intel Corporation for their precious help.
-
-        - We teamed up with Cherry to make Linux the first OS with
-          built-in USB support. Cherry is one of the biggest keyboard
-          makers in the world.
-
-        - CMD Technology, Inc. sponsored us kindly donating a CSA-6700
-          PCI-to-USB Controller Board to test the OHCI implementation.
-
-        - Due to their support to us, Keytronic can be sure that they
-          will sell keyboards to some of the 3 million (at least)
-          Linux users.
-
-        - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
-          It was almost imposible to get a PC backplate USB connector
-          for the motherboard here at Europe (mine, home-made, was
-          quite lowsy :). Now I know where to adquire nice USB stuff!
-
-        - Genius Germany donated a USB mouse to test the mouse boot
-          protocol. They've also donated a F-23 digital joystick and a
-          NetMouse Pro. Thanks! 
-
-        - AVM GmbH Berlin is supporting the development of the Linux
-          USB driver for the AVM ISDN Controller B1 USB. AVM is a
-          leading manufacturer for active and passive ISDN Controllers
-          and CAPI 2.0-based software. The active design of the AVM B1
-          is open for all OS platforms, including Linux.
-
-        - Thanks to Y-E Data, Inc. for donating their FlashBuster-U
-          USB Floppy Disk Drive, so we could test the bulk transfer
-          code.
-
-        - Many thanks to Logitech for contributing a three axis USB
-          mouse. 
-
-          Logitech designs, manufactures and markets
-          Human Interface Devices, having a long history and
-          experience in making devices such as keyboards, mice,
-          trackballs, cameras, loudspeakers and control devices for
-          gaming and professional use.
-
-          Being a recognized vendor and seller for all these devices,
-          they have donated USB mice, a joystick and a scanner, as a
-          way to acknowledge the importance of Linux and to allow
-          Logitech customers to enjoy support in their favorite
-          operating systems and all Linux users to use Logitech and
-          other USB hardware.
-
-          Logitech is official sponsor of the Linux Conference on
-          Feb. 11th 1999 in Vienna, where we'll will present the
-          current state of the Linux USB effort.
-
-        - CATC has provided means to uncover dark corners of the UHCI
-          inner workings with a USB Inspector.
-
-        - Thanks to Entrega for providing PCI to USB cards, hubs and
-          converter products for development. 
-
-
-        And thanks go to (hey! in no particular order :)
-
-        - Oren Tirosh <orenti@hishome.net>, for standing so patiently
-          all my doubts'bout USB and giving lots of cool ideas.
-
-        - Jochen Karrer <karrer@wpfd25.physik.uni-wuerzburg.de>, for
-          pointing out mortal bugs and giving advice.
-
-        - Edmund Humemberger <ed@atnet.at>, for it's great work on
-          public relationships and general management stuff for the
-          Linux-USB effort.
-
-        - Alberto Menegazzi <flash@flash.iol.it> is starting the
-          documentation for the UUSBD. Go for it!
-
-        - Ric Klaren <ia_ric@cs.utwente.nl> for doing nice
-          introductory documents (compiting with Alberto's :).
-
-        - Christian Groessler <cpg@aladdin.de>, for it's help on those
-          itchy bits ... :)
-
-        - Paul MacKerras for polishing OHCI and pushing me harder for
-          the iMac support, giving improvements and enhancements.
-
-        - Fernando Herrera <fherrera@eurielec.etsit.upm.es> has taken
-          charge of composing, maintaining and feeding the
-          long-awaited, unique and marvelous UUSBD FAQ! Tadaaaa!!!
-
-        - Rasca Gmelch <thron@gmx.de> has revived the raw driver and
-          pointed bugs, as well as started the uusbd-utils package.
-
-        - Peter Dettori <dettori@ozy.dec.com> is unconvering bugs like
-          crazy, as well as making cool suggestions, great :)
-
-        - All the Free Software and Linux community, the FSF & the GNU
-          project, the MIT X consortium, the TeX people ... everyone!
-          You know who you are!
-
-        - Big thanks to Richard Stallman for creating Emacs!
-
-        - The people at the linux-usb mailing list, for reading so
-          many messages :) Ok, no more kidding; for all your advices!
-
-        - All the people at the USB Implementors Forum for their
-          help and assistance.
-
-        - Nathan Myers <ncm@cantrip.org>, for his advice! (hope you
-          liked Cibeles' party).
-
-        - Linus Torvalds, for starting, developing and managing Linux.
-
-        - Mike Smith, Craig Keithley, Thierry Giron and Janet Schank
-          for convincing me USB Standard hubs are not that standard
-          and that's good to allow for vendor specific quirks on the
-          standard hub driver.
-
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/README.URB linux/drivers/usb/README.URB
--- v2.3.36/linux/drivers/usb/README.URB	Mon Dec 20 18:48:22 1999
+++ linux/drivers/usb/README.URB	Wed Dec 31 16:00:00 1969
@@ -1,196 +0,0 @@
-1. Specification of the API
-
-1.1. Basic concept or 'What is an URB?'
-
-The basic idea of the new driver is message passing, the message itself is 
-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. 
-
-- Execution of an URB is an inherently asynchronous operation, i.e. the 
-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
-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
-different, 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 continous streaming itself is transparently done by the 
-URB-machinery.
-
-1.2. The URB structure
-
-typedef struct urb
-{
-// 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 
-
-// This is used for urb linking
-	struct urb* next;               // pointer to next URB  
-	struct usb_device *dev;         // pointer to associated USB device
-
-// pipe is assembled by the various well known pipe-macros in usb.h
-	unsigned int pipe;              // pipe information
-
-// status after each completion
-	int status;                     // returned status
-	unsigned int transfer_flags;    // ASAP, SP_OK, EARLY_COMPLETE
-
-// for data stage (CTRL), BULK, INT and ISO
-	void *transfer_buffer;          // associated data buffer
-
-// expected length
-	int transfer_buffer_length;     // data buffer length
-	int actual_length;              // actual data buffer length    
-
-// setup stage for CTRL (always 8 bytes!)
-	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;
-
-1.3. How to get an URB?
-
-URBs are allocated with the following call
-
-	purb_t alloc_urb(int isoframes)
-
-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.
-
-To free an URB, use
-
-	void free_urb(purb_t purb)
-
-This call also may free internal (host controller specific) memory in the
-future.
-
-1.4. What has to be filled in?
-
-Depending on the type of transaction, there are some macros 
-(FILL_CONTROL_URB, FILL_BULK_URB, and FILL_INT_URB, defined in uhci.h)
-that simplify the URB creation. In general, all macros need the usb
-device pointer, the pipe (usual format), the transfer buffer, the 
-desired transfer length, the completion  handler, and its context. 
-Take a look at the uhci_control_msg-function that convert the old API 
-into an URB.
-
-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 
-transfer_flags.
-
-Usually, (to reduce restart time) the completion handler is called
-AFTER the URB re-submission. You can get the other way by setting
-USB_URB_EARLY_COMPLETE in transfer_flags. This is implicite for
-INT transfers.
-
-1.5. How to submit an URB?
-
-Just call
-
-	int submit_urb(purb_t purb)
-
-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)
-- Too many requested ISO frames (-EFBIG)
-- Invalid INT interval (-EINVAL)
-- More than one packet for INT (-EINVAL)
-
-After submission, urb->status is USB_ST_URB_PENDING.
-
-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 (implicitely ASAP).
-
-1.6. How to cancel an already running URB?
-
-Call
-	int unlink_urb(purb_t purb)
-
-It removes the urb from the internal list and frees all allocated
-HW descriptors. The status is changed to USB_ST_URB_KILLED. After 
-unlink_urb() returns, you can safely free the URB with free_urb(urb)
-and all other possibly associated data (urb->context etc.)
-
-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 *);
-
-i.e. it gets just the URB that caused the completion call.
-In the completion handler, you should have a look at urb->status to
-detect any USB errors. Since the context parameter is included in the URB,
-you can pass information to the completion handler. 
-
-
-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 alloc_urb(n)
-(recommended), the isoframe-parameter n can be used to allocate the
-structures for n frames.
-
-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 transfered length and 
-status contains the resulting USB-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 continous
-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 continous streaming you have to use URB
-linking. 
-
-1.9. How to start interrupt (INT) transfers?
-
-INT transfers are currently implemented with 8 different queues for intervals 
-for 1, 2, 4,... 128ms. Only one TD is allocated for each interrupt. After
-calling the completion handler, the TD is recycled.
-With the submission of one URB, the interrupt is scheduled until it is
-canceled by unlink_urb.
-
-The submit_urb()-call modifies urb->interval to the rounded value.
-
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/README.acm linux/drivers/usb/README.acm
--- v2.3.36/linux/drivers/usb/README.acm	Mon Aug  2 14:29:08 1999
+++ linux/drivers/usb/README.acm	Wed Dec 31 16:00:00 1969
@@ -1,94 +0,0 @@
-The ACM driver works with modems and ISDN TAs that use the USB Abstract
-Control Model standard. 
-
-****************************
-Test it:
-Watch out, the driver is not stable and tested. Sync often, make backups,
-most importand: don't blame me...
-
-Create device files:
-mknod /dev/ttyACM0 c 166 0
-mknod /dev/ttyACM1 c 166 1
-mknod /dev/ttyACM2 c 166 2
-mknod /dev/ttyACM3 c 166 3
-Compile a kernel with support for your host controller (uhci only for now!)
-and support for ACM. Boot this kernel. If you connect your device to the
-USB bus you should see messages like the following:
-
-Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
-Jul 19 20:14:29 office kernel: Found 02:09
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office last message repeated 2 times
-Jul 19 20:14:29 office kernel: parsed = 39 len = 67
-Jul 19 20:14:29 office kernel: Expected descriptor 04/09, got 02/09 - skipping
-Jul 19 20:14:29 office kernel:    0 09
-Jul 19 20:14:29 office kernel:    1 02
-Jul 19 20:14:29 office kernel:    2 43
-Jul 19 20:14:29 office kernel:    3 00
-Jul 19 20:14:29 office kernel:    4 02
-Jul 19 20:14:29 office kernel:    5 02
-Jul 19 20:14:29 office kernel:    6 04
-Jul 19 20:14:29 office kernel:    7 60
-Jul 19 20:14:29 office kernel:    8 00
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 02:09
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office kernel: parsed = 67 len = 0
-Jul 19 20:14:29 office kernel: getstringtable
-Jul 19 20:14:29 office kernel: acm_probe
-Jul 19 20:14:29 office kernel: USB ACM found
-
-Watch out for the line:
-Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
-and the line:
-Jul 19 20:14:29 office kernel: USB ACM found
-These two lines show that the device was seen by the usb host controller and
-then recognized by the acm driver as a valid device.
-
-If you use a terminal emulation software like minicom with /dev/ttyACM0 you
-should be able to send AT commands to your device and get responses. I've 
-been able to do zmodem downloads to another pc. However downloads from one
-ISDN TA to another ISDN TA connected to the same PC didn't work. Don't
-know why. Flow control is not finised after all and i'd guess there might
-be problems on heavily loades PCs. I also did some tests with ppp but i'm
-not finised with this. There might be a chance to get it working. However
-i'd like to know if your device is recognized as an ACM device. I'm also
-interested if the thing is stable or if it crashes.
-(should i say how it crases?)
-
-You should be able to add and remove devices from the bus. The driver will
-always try to fill up unused ttys. This means if you hotplug devices their
-order may have changed after reboot. This is not the behaviour Linus liked
-to see but it's ok for now. (I hope ;-)
-
-Please report your experiences to me:
-fuerst@in.tum.de
-
-***************************
-I've tested it with:
-3Com ISDN Pro TA.
-
-It should work with (That means i know these devices conform to ACM):
-3Com Office Connect Modem
-3Com Sportster USB (I think that's what it's called)
-
-***************************
-Many thanks to 3Com which did not only support me with hardware but also
-with technical support in USB questions. They also allowed me to do tests in
-their lab. Great!
-
-***************************
-Known bugs:
-Flow control not tested (likely not to work)
-Some tty function calls not implemented (putchar, etc...)
-Huge amounts of debug output (compile in [*] Magic SysRq key and press ALT+PRTSCR+0 )
-Not all mem is freed at close (need terminate irq in hcd)
-
-***************************
-Have fun,
-	Armin Fuerst
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/README.dc2xx linux/drivers/usb/README.dc2xx
--- v2.3.36/linux/drivers/usb/README.dc2xx	Tue Nov 23 22:42:21 1999
+++ linux/drivers/usb/README.dc2xx	Wed Dec 31 16:00:00 1969
@@ -1,110 +0,0 @@
-13 November 1999
-david-b@pacbell.net
-
-This is an overview of how to use the "dc2xx" USB driver with certain
-digital still cameras from Kodak and other vendors.
-
-
-CAMERAS
-
-This driver will mostly be used with Kodak DC-2xx series digital still
-cameras, but it should be trivial to tell it about several non-Kodak
-USB-enabled cameras.
-
-You'll most likely want to hook it up to recent versions of "gPhoto"
-(www.gphoto.org), since version 0.4 and later know how to use it to talk
-to Kodak DC-240 and DC-280 cameras over USB.
-
-In addition the DC-260, DC-265, and DC-290 are currently recognized.
-However, like other cameras using the "Digita OS" (from www.flashpoint.com)
-there is no gPhoto support for this camera.  At this writing the best
-known support for these cameras is a Python script that supports image
-downloading from those cameras.  (See archives of the linux-usb mailing
-list.)  The DC-220 should also work with this driver, given information
-about the USB product IDs.  When it becomes available, the HP PhotoSmart
-C500 should also work ... it's another Digita OS camera with USB support.)
-
-It's likely that other digital still cameras can also use this USB driver,
-even if they're not from Kodak and don't use Digita.  The reason is that
-most currently known USB still camera protocols treat USB like a faster
-packet-carrying connection than a serial line, which is exactly how this
-driver looks to an application.
-
-
-USB HARDWARE
-
-This has been shown to work on x86 OHCI and UHCI (Intel) chipsets.  OHCI has
-been trouble free; not so with UHCI, which was first seen to be happy with
-2.3.24 kernels, and has not been as fast as OHCI.
-
-Note that in some cases changes in BIOS settings may be needed before
-your USB works.  At least one user has reported a need for SMP-related 
-settings as well.
-
-As yet, no reports have come from Linux users on non-Intel hardware.
-(You could color coordinate your iMac with a DC-240i ... :-)
-
-
-SETUP
-
-Configure in the DC2XX USB driver, and have it in your kernel.  Recently I
-compile it right in, but I've done it as a module in the past.
-
-Create a device, perhaps like this (both read and write):
-
-    # mknod -m 0666 /dev/kodak c 10 170
-
-That "170" is not formally assigned, and this command may change.  If you're
-using a non-Kodak camera, you may prefer another name.
-
-Don't plug in more than one compatible camera at this time.  One of them
-will be ignored, but I'd not be sure which one!
-
-
-SANITY TESTING
-
-First:  if you've got /proc support, make sure that the driver has hooked
-itself up correctly.
-
-    - you should see an entry in /proc/misc for the a Kodak DC-2xx
-      minor device number
-
-    - you should see an entry in /proc/bus/usb/drivers for "dc2xx",
-      if you also enabled USB /proc support.
-
-Second:  when you connect your camera to the computer, does it get recognized
-by the driver?
-
-    - if you've got /proc/bus/usb/devices, you should see an entry
-      something like this.  The "ProdID" may be different if you didn't
-      plug in a DC-240, but the "Driver=dc2xx" had better be there.
-
-	T:  Lev=01 Prnt=00 Port=00 Cnt=01 Dev#=  1 Spd=12  MxCh= 0
-	D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
-	P:  Vendor=040a ProdID=0120 Rev= 1.08
-	C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=100mA
-	I:  If#= 0 Alt= 0 #EPs= 2 Cls=00(>ifc ) Sub=00 Prot=00 Driver=dc2xx
-	E:  Ad=01(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
-	E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
-
-    - if you don't have /proc support for USB, see if "dmesg" output
-      tells you that you plugged in your camera.
-
-	USB new device connect, assigned device number 1
-	Manufacturer: Eastman Kodak Company
-	Product: KODAK DC240 Zoom Digital Camera
-	USB Camera is connected
-	usbcore: dc2xx driver claimed interface c3a68600
-	ohci-control thread sleeping
-
-Third:  (optional) can you use gPhoto to talk to the camera?
-
-    - When you configure your camera, tell it to use "/dev/kodak" (or
-      whatever name you used).  Right now, gPhoto emits a diagnostic
-      message (non-GUI) saying that it since it didn't act like a TTY,
-      it's assuming it's got a USB connection.
-
-    - With the camera turned on, get the "camera summary".  It'll
-      talk to the camera -- and tell you you're using USB.
-
-If you got that far, you should be able to use everything fine.
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/README.error-codes linux/drivers/usb/README.error-codes
--- v2.3.36/linux/drivers/usb/README.error-codes	Mon Dec 20 18:48:22 1999
+++ linux/drivers/usb/README.error-codes	Wed Dec 31 16:00:00 1969
@@ -1,108 +0,0 @@
-$Id: README.error-codes,v 1.1 1999/12/14 14:03:02 fliegl Exp $
-
-This is the documentation of (hopefully) all possible error codes (and
-their interpretation) that can be returned from the hostcontroller driver 
-and from usbcore.
-
-NOTE:
-The USB_ST_* codes are deferred and are only listed for compatibility, new
-software should use only -E* instead!
-
-
-
-**************************************************************************
-*                   Error codes returned by usb_submit_urb               *
-**************************************************************************
-
-Non-USB-specific:
-
-USB_ST_NOERROR
-0		URB submission went fine
-
--ENOMEM		no memory for allocation of internal structures	
-
-USB-specific:
-
--ENODEV		specified USB-device or bus doesn't exist
-
--ENXIO		specified endpoint doesn't exist on the device
-
-USB_ST_URB_INVALID_ERROR
--EINVAL		a) Invalid transfer type specified (or not supported)
-		b) Invalid interrupt interval (0<=n<256)
-		c) more than one interrupt packet requested
-
--EAGAIN		a) specified ISO start frame too early
-		b) (using ISO-ASAP) too much scheduled for the future
-		   wait some time and try again.
-
--EFBIG		too much ISO frames requested (currently uhci>900)
-
--EPIPE		specified pipe-handle is already stalled
-
--EMSGSIZE	endpoint message size is zero, do interface/alternate setting
-
-
-**************************************************************************
-*                   Error codes returned by in urb->status               *
-*                   or in iso_frame_desc[n].status (for ISO)             *
-**************************************************************************
-
-USB_ST_NOERROR
-0			Transfer completed successfully
-
-USB_ST_URB_KILLED
--ENOENT			URB was canceled by unlink_urb
-
-USB_ST_URB_PENDING
--EINPROGRESS		URB still pending, no results yet
-			(actually no error until now;-)
-
-USB_ST_BITSTUFF
-USB_ST_INTERNALERROR
--EPROTO			a) bitstuff error
-			b) unknown USB error 
-
-USB_ST_CRC
--EILSEQ			CRC mismatch
-
--EPIPE			a) babble detect
-			b) endpoint stalled
-
-USB_ST_BUFFERUNDERRUN
--ENOST			buffer error
-
-USB_ST_NORESPONSE
-USB_ST_TIMEOUT
--ETIMEDOUT		transfer timed out, NAK
-
-USB_ST_REMOVED	
--ENODEV			device was removed
-
-USB_ST_SHORT_PACKET
--EREMOTEIO		short packet detected
-
-USB_ST_PARTIAL_ERROR
--EXDEV			ISO transfer only partially completed
-			look at individual frame status for details
-
-USB_ST_URB_INVALID_ERROR
--EINVAL			ISO madness, if this happens: Log off and go home
-
-**************************************************************************
-*              Error codes returned by usbcore-functions                 *
-*           (expect also other submit and transfer status codes)         *
-**************************************************************************
-
-usb_register():
-USB_ST_NOTSUPPORTED
--EINVAL			error during registering new driver
-
-usb_terminate_bulk():
-USB_ST_REMOVED
--ENODEV			urb already removed
-
-usb_get_*/usb_set_*():
-			All USB errors (submit/status) can occur
-
-
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/README.hid linux/drivers/usb/README.hid
--- v2.3.36/linux/drivers/usb/README.hid	Tue Jan  4 13:57:17 2000
+++ linux/drivers/usb/README.hid	Wed Dec 31 16:00:00 1969
@@ -1,162 +0,0 @@
-			   Linux HID driver v0.8
-		 (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
-		    (c) 1999 Andreas Gal <agal@uwsp.edu>
-			     Sponsored by SuSE
-----------------------------------------------------------------------------
-
-0. Disclaimer
-~~~~~~~~~~~~~
-  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@suse.cz>, or by paper mail: Vojtech Pavlik,
-Ucitelska 1576, 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.
-
-1. Introduction
-~~~~~~~~~~~~~~~
-  This is a driver for USB devices conforming to the USB HID (Human Input
-Device) standard. These devices include namely keyboards, mice and
-joysticks.
-
-  However many other devices (monitors, speakers, UPSs ...) also communicate
-through the same protocol, which makes its specification somewhat bloated.
-This isn't a problem, though, because the driver doesn't need to know about
-all the possible devices it can control, and can just parse the protocol and
-leave the rest of the job (for example understanding what the UPS wants to
-say) to the userland.
-
-  Because of this, the USB HID driver has two interfaces. One is via the
-proc filesystem, allowing userland applications send and read arbitrary
-reports to and from a connected USB device. The other is via a very simple
-yet generic input device driver, which dispatches input events (keystrokes,
-mouse or joystick movements) to specific, backward compatible userland
-interfaces. This way a PS/2 mouse, an AT keyboard or a Linux joystick driver
-interface are emulated, and allow applications to immediately work with USB
-mice, USB keyboards and USB joysticks without any changes.
-
-  The input driver is aimed for a little more than USB device handling in
-the future, though. It's generic enough so that it can be used for any
-mouse, keyboard or joystick (and more, of course). A PS/2 mouse driver, a
-serial mouse, Sun mouse, and most of the busmouse drivers were rewritten to
-use this as well as the AT keyboard and Sun keyboard drivers. This will
-hopefully allow conversion of all Linux keyboard and mouse and joystick
-drivers to this scheme.
-
-  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.
-There is also a mailing list for this:
-
-	listproc@atrey.karlin.mff.cuni.cz
-
-Send "subscribe linux-joystick Your Name" to subscribe to it.
-
-2. Usage
-~~~~~~~~
-  Since the driver comes with recent 2.3 kernels, all that's needed to use
-it is to enable it either as a module or compiled-in into the kernel. 
-
-  After that, after reboot (and possibly also inserting the USB and HID
-modules) the following will happen:
-
-* If you selected keyboard support, all USB keystrokes will be also routed
-  to the Linux keyboard driver as if being input through the ordinary system
-  keyboard.
-
-* If you selected mouse support, there will be (one or more) simulated PS/2
-  mouse devices on major 10, minor 32, 33 and more. These simulated mice can
-  in addition to a standard 3-button PS/2 mouse behave like MS Intellimice,
-  with a wheel. If you want to use the wheel, just specify '-t imps2' to gpm
-  and 'Protocol "ImPS/2"' to X, and it will work. A single emulated mouse
-  device can be open by any number of processes (unlike the /dev/psaux), and
-  for each of them the emulation is separate, each can use a different mode.
-  The mousedev driver, which emulates the mice, can also emulate a Genius
-  NewScroll 5 buttons-and-a-wheel mouse, if you set it to a Genius PS/2
-  mode ('-t netmouse' 'Protocol "NetMousePS/2"'). However, not gpm, nor X
-  can decode the 5 buttons yet, so this isn't very useful right now.
-
-* If you selected joystick support, the driver will take over major 15, the
-  joystick major number, and will emulate joysticks on it. This means the
-  normal joystick driver can't be used together with it (now, after the
-  normal joystick drivers are converted to the input scheme, all will work
-  nicely together). Also, you'll probably need to calibrate your joystick
-  manually ('man jscal') to be able to use it, because the USB
-  autocalibration is far from perfect yet.
-
-* If you selected event device support, there will be devices on major 10,
-  minors 64, 65 and more for each input device connected through this
-  driver. These devices output raw events the input driver dispatches. Each
-  has a timestamp. This hopefully will be THE way X will talk to keyboard
-  and mice, because it's hardware independent, and not limited by existing
-  de-facto standards.
-
-3. 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.
-
-  Doing a cat /dev/hidmouse (c, 10, 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 event devics with the 'evtest' utitily available on the
-input driver homepage (see the URL above).
-
-4. FAQ
-~~~~~~
-Q: Why aren't any questions here yet?
-A: Because none were frequent enough yet.
-
-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
-can. Here goes a description of the current state of things, which is going
-to be extended, but not changed incompatibly as time goes:
-
-  You can use blocking and nonblocking reads, also select() on the
-/dev/inputX devices, and you'll always get a whole number of input events on
-a read. Their layout is:
-
-struct input_event {
-	struct timeval time;
-	unsigned short type;
-	unsigned short code;
-	unsigned int value;
-};
-
-  'time' is the timestamp, it returns the time at which the event happened.
-Type is for example EV_REL for relative momement, REL_KEY for a keypress or
-release. More types are defined in include/linux/input.h.
-
-  'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
-list is in include/linux/input.h.
-
-  '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. Proc interface
-~~~~~~~~~~~~~~~~~
-  For HID-specific devices there is also the /proc interface. It isn't
-present in this release yet, though, so it's description will appear here
-together with the code in the driver.
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/README.ohci_hcd linux/drivers/usb/README.ohci_hcd
--- v2.3.36/linux/drivers/usb/README.ohci_hcd	Wed Aug 18 16:22:23 1999
+++ linux/drivers/usb/README.ohci_hcd	Wed Dec 31 16:00:00 1969
@@ -1,98 +0,0 @@
-
-The OHCI HCD layer is a simple but nearly complete implementation of what the
-USB people would call a HCD  for the OHCI. 
- (ISO comming soon, Bulk, INT u. CTRL transfers enabled)
-It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
-The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. 
-
-- Roman Weissgaerber <weissg@vienna.at>
-
- * v4.0 1999/08/18 removed all dummy eds, unlink unused eds, code cleanup, bulk transfers 
- * v2.1 1999/05/09 ep_addr correction, code cleanup
- * v0.2.0 1999/05/04 
- * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers)
- * virtual root hub is now an option, 
- * memory allocation based on kmalloc and kfree now, simple Bus error handling, 
- * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
- * 
- * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff
- * from Greg Smith (ohci.c): better reset ohci-controller handling, hub
- * 
- * v0.1.0 1999/04/27 initial release
- 
-to remove the module try:
-rmmod usb-ohci-hcd
-
-Features:
-- virtual root hub, all basic hub descriptors and commands (state: complete) 
-  this is an option now (v0.2.0)
-  #define  CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB)
-  default is with. 
-  (at the moment: the Virtual Root Hub is included automatically)
-  
-  files: ohci-root-hub.c, ohci-root-hub.h 
- 
-
-- Endpoint Descriptor (ED) handling more static approach 
- (EDs should be allocated in parallel to the SET CONFIGURATION command and they live
- as long as the function (device) is alive or another configuration is choosen.
- In the HCD layer the EDs has to be allocated manually either by calling a subroutine
- or by sending a USB root hub vendor specific command to the virtual root hub.
- At the alternate linux usb stack EDs will be added (allocated) at their first use.
- ED will be unlinked from the HC chains if they are not bussy.
- 
- files: ohci-hcd.c ohci-hcd.h
- routines:   (do not use for drivers, use the top layer alternate usb commands instead)
- 
- int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, 
-            int interval, int load, f_handler handler, int ep_size, int speed)
-       adds an endpoint, (if the endpoint already exists some parameters will be updated)
-       
- int usb_ohci_rm_ep( ) 
-       removes an endpoint and all pending TDs of that EP
-       
-  usb_ohci_rm_function( )
-       removes all Endpoints of a function (device)
-
-- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers
-  The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has
-  to take care of buffer allocation.
-  files: ohci-hcd.c ohci-hcd.h 
-
-  There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL):
-  
-  int ohci_trans_req(struct ohci * ohci, hcd_ed, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1)
-  
-  CTRL: ctrl, ctrl_len ... cmd buffer 
-        data, data_len ... data buffer (in or out)
-  INT, BULK:  ctrl = NULL, ctrl_len=0,
-  		data, data_len ... data buffer (in or out)
-  ISO: tbd
-
-  There is no buffer reinsertion done by the internal HCD function. 
-  (The interface layer does this for a INT-pipe on request.)
-  If you want a transfer then you have to 
-  provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED
-  you can send as many as you like. They should come back by the callback f_handler in
-  the same order (for each endpoint, not globally) If an error occurs all
-  queued transfers of an endpoint will return unsent. They will be marked with an error status.
-  
-  e.g double-buffering for int transfers:
-
-   	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
-  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
-  	
-  and when a data0 packet returns by the callback f_handler requeue it:
-  	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
-  and when a data1 packet returns by the callback f_handler requeue it:
-  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
-  	
-  lw0, lw1 are private fields for upper layers for ids or fine grained handlers.
-  The alternate usb uses them for dev_id and usb_device_irq handler.
-
-
-- Done list handling: returns the requests (callback f_handler in ED) and does 
-  some error handling, root-hub request dequeuing
-  (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0))
-
-  
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/README.ov511 linux/drivers/usb/README.ov511
--- v2.3.36/linux/drivers/usb/README.ov511	Tue Jan  4 13:57:17 2000
+++ linux/drivers/usb/README.ov511	Wed Dec 31 16:00:00 1969
@@ -1,70 +0,0 @@
--------------------------------------------------------------------------------
-Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC
--------------------------------------------------------------------------------
-
-INTRODUCTION:
-
-This is a preliminary version of my OV511 Linux device driver. At the moment,
-it does not do much more than detect the chip and initialize it. As trivial
-as this sounds, it represents many hours of my work. Since OmniVision refused
-to release the full specs to me, I had to write code to probe out the register
-read/write commands. Some code is in place to allow a frame to be grabbed, but
-it is nowhere near complete.
-
-SUPPORTED CAMERAS:
-____________________________________________
-Manufacturer     | Model        | Custom ID 
------------------+--------------+-----------
-D-Link           | DSB-C300	    | 3
-Creative Labs    | WebCam 3     | 21
---------------------------------------------
-
-Any camera using the OV511 and the OV7610 CCD should work with this driver. The
-driver only detects known cameras though, based on their custom id number. If
-you have a currently unsupported camera, the ID number should be reported to you
-in the kernel logs. If you have an unsupported camera, please send me the model,
-manufacturer and ID number and I will add it to the detection code. In the
-meantime, you can add to the code yourself in the function ov511_probe()
-
-WHAT YOU NEED:
-
-- If you want to help with the development, get the chip's specification docs at
-  http://www.ovt.com/omniusbp.html
-
-- A Video4Linux compatible frame grabber program (I recommend vidcat)
-  (see: http://www.exploits.org/v4l/ )
-  
-WHAT NEEDS TO BE DONE:
-
-In short, a lot. 
-
-UPDATE:
-Currently, the control messages are working fine ("vendor commands"; for
-reading and writing the OV511 registers.) The I2C bus commands for reading and
-writing the camera (OV7610) registers are implemented and working, with at least
-one person's camera. The isochronous-in endpoint for video data is finally
-producing data, but since ov511_parse_data() is not implemented you will not see
-a picture yet.
-
-Support for specific CCD's will have to be implemented as well (such as the
-OV7610.) 
-
-The rest of the work will involve implementing support for all the different
-resolutions, color depths, etc. Also, while support for the OV511's proprietary
-lossy compression is apparently not necessary (the code currently disables it,)
-it would be a nice addition as it improves performance quite a bit. OmniVision
-wouldn't tell me how the algorithm works, so we can't really work on that yet.
-Please kindly inform OmniVision that you would like them to release their
-specifications to the Linux community.
-
-HOW TO CONTACT ME:
-
-You can email me at mmcclelland@delphi.com . Please prefix the subject line
-with "OV511: " so that I am certain to notice your message.
-
-CREDITS:
-
-The code is based in no small part on the CPiA driver by Johannes Erdfelt,
-Randy Dunlap, and others. Big thanks to them for their pioneering work on that
-and the USB stack. Thanks to Bret Wallach for getting camera reg IO and ISOC
-working.
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/README.scanner linux/drivers/usb/README.scanner
--- v2.3.36/linux/drivers/usb/README.scanner	Wed Dec 29 13:13:19 1999
+++ linux/drivers/usb/README.scanner	Wed Dec 31 16:00:00 1969
@@ -1,231 +0,0 @@
-Oct 19, 1999
-
-CHANGES
-
-- Ammended for linux-2.3.22+
-- Appended hp_scan.c to end of this README
-- Removed most references to HP
-
-
-OVERVIEW
-
-This README will address issues regarding how to configure the kernel
-to access a USB scanner.  Although the driver was originally conceived
-for USB HP scanners, it's general enough so that it can be used with
-other scanners.  Also, one can now pass the USB Vendor and
-Product ID's using module parameters for unknown scanners.  Refer to
-the document README.scanner_hp_sane for guidance on how to configure
-SANE to use a USB HP Scanner.
-
-
-ADDITIONAL INFORMATION
-
-http://www.linux-usb.org/
-http://www.dynamine.net/linux-usb/HOWTO/
-
-
-REQUIREMENTS
-
-A host with a USB port.  Ideally, either a UHCI (Intel) or OHCI
-(Compaq and others) hardware port should work.  However, I've only
-been able to really use an OHCI controller.  I did have access to a
-system with a UHCI controller but some very limited testing did not
-produce satisfactory results.  Luke Ordelmans
-<postbus@ordelmans.demon.nl> has reported success using the UHCI host
-controller with kernel 2.3.18 and a ChainTech motherboard.  Here
-lately I've been having better success with the ohci-hcd driver.  But
-since Linux USB support is still in a state of constant development
-that may change at a later date.  I am confident that eventually all
-the host contollers will perform without incident.
-
-A Linux kernel with USB support (preferably linux-2.3.18+)
-
-A Linux kernel with USB Scanner support.
-
-
-CONFIGURATION
-
-Using `make menuconfig` or your prefered method for configuring the
-kernel, select 'Support for USB', 'OHCI/OHCI-HCD/UHCI' depending on
-your hardware, 'USB hub support', and 'USB Scanner support'.  Compile
-and install the modules (you may need to execute `depmod -a` to update
-the module dependencies).  Testing was performed only as modules,
-YMMV.
-
-Add a device for the USB scanner:
-  linux-2.3.22 and above: `mknod /dev/usbscanner c 180 48`
-  linux-2.3.21 and below: `mknod /dev/usbscanner c 16 1`
-
-Set appropriate permissions for /dev/usbscanner (don't forget about
-group and world permissions).  Both read and write permissions are
-required for proper operation.
-
-Load the appropriate modules (if compiled as modules):
-
-  OHCI:
-    modprobe usb-ohci
-    modprobe scanner
-
-  OHCI-HCD:
-    modprobe usb-ohci-hcd
-    modprobe hub
-    modprobe scanner
-
-  UHCI:
-    modprobe usb-uhci
-    modprobe hub (don't know if this is required or not)
-    modprobe scanner
-
-That's it.  SANE should now be able to access the device.  
-
-There is a small test program (hp_scan.c -- appended below) that can
-be used to test the scanner device if it's an HP scanner that supports
-SCL.  Its purpose is to test the driver without having to
-retrieve/configure SANE.  Hp_scan.c will scan the entire bed and put
-the output into a file called 'out.dat' in the current directory.  The
-data in the file is raw data so it's not very useful for imaging.
-
-
-MODULE PARAMETERS
-
-If you have a device that wish to experiment with or try using this
-driver with, but the Vendor and Product ID's are not coded in, don't
-despair.  If the driver was compiled as a module, you can pass options
-to the driver.  Simply add 'options scanner vendor=0x####
-product=0x****' to the conf.modules/modules.conf file replacing the
-#'s and the *'s with the correct ID's.  The ID's can be retrieved from
-the messages file or using `cat /proc/bus/usb/devices` if USB /proc
-support was selected during kernel configuration.
-
-
-BUGS
-
-If you encounter any problems feel free to drop me an email.
-
-David /\/elson
-dnelson@jump.net
-http://www.jump.net/~dnelson
-
---------------- snip -- hp_scan.c -- snip ---------------
-/*
-
-This is a really crude attempt at writing a short test program.  It's
-mostly only to be used to test connectivity with USB HP scanners that
-understand SCL.  Currently, the supported models are 4100C, 5200C,
-6200C, and the 6300C.  Note that the 4200C is *NOT* acceptable.
-
-Copyright (C) David E. Nelson <dnelson@jump.net>, 1999
-
-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.
-
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <error.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-/*
-   Gray Output produces about a 8945400 byte file.
-   Color Output produces a 26836200 byte file. 
-   
-   To compile: gcc -o hp_scan hp_scan.c
-*/
-
-// #define COLOR /* Undef to scan GrayScale */
-
-int send_cmd(int, const char *, int);
-int read_cmd(int, char *, int);
-
-int
-main(void) {
-
-	ssize_t cnt = 0, total_cnt = 0;
-
-	FILE *fpout;
-
-	int fp;
-	int data_size = 32768;
-
-	char *data;
-
-	static char reset_cmd[] = {'\x1b','E'};
-
-#ifdef COLOR
-	static char data_type_cmd[] = {'\x1b','*','a','5','T'}; /* Color */
-	static char data_width_cmd[] = {'\x1b','*','a','2','4','G'}; /* 24 Bit Color */
-#else
-	static char data_type_cmd[] = {'\x1b','*','a','4','T'}; /* Gray */
-	static char data_width_cmd[] = {'\x1b','*','a','8','G'}; /* 8 Bit Gray */
-#endif
-
-	static char query_cmd[] = {'\x1b', '*', 's', '2', '5', '7', 'E'};
-	static char start_scan_cmd[] = {'\x1b','*','f','0','S'};
-	
-	if(!(data=malloc(data_size))) {
-		perror("malloc failed");
-		exit (1);
-	}
-	
-	if((fp=open("/dev/usbscanner", O_RDWR)) < 0) {
-		perror("Unable to open scanner device");
-		exit (1);
-	}
-
-	if((fpout=fopen("out.dat", "w+")) == NULL) {
-		perror("Unable to open ouput file");
-		exit(1);
-	}
-
-	send_cmd(fp, reset_cmd, sizeof(reset_cmd));
-	send_cmd(fp, data_type_cmd, sizeof(data_type_cmd));
-	send_cmd(fp, data_width_cmd, sizeof(data_width_cmd));
-	send_cmd(fp, start_scan_cmd, sizeof(start_scan_cmd));
-
-	while ((cnt = read(fp, data, data_size)) > 0) {
-		printf("Read: %u\n", cnt); 
-		if(fwrite(data, sizeof(char), cnt, fpout) < 0) {
-			perror("Write to output file failed");
-			exit (1);
-		}
-		total_cnt += cnt;
-	}
-	if (cnt < 0) {
-		perror("Read from scanner failed");
-		exit (1);
-	}
-
-	printf("\nRead %lu bytes.\n", total_cnt);
-
-	send_cmd(fp, reset_cmd, sizeof(reset_cmd));
-
-	close(fp);
-	fclose(fpout);
-	return (0);
-}
-
-int
-send_cmd(int fp, const char * cmd, int length) {
-
-	int result;
-	int x;
-
-	if((result = write(fp, cmd, length)) != length) {
-		printf ("Write warning: %d bytes requested, %d written\n");
-	} else if (result < 0) {
-		perror ("send_cmd failure");
-		exit (1);
-	}
-	return (result);
-}
-	
-int
-read_cmd(int fp, char * response, int length) {
-
-	return read(fp, response, length);
-
-}
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/README.scanner_hp_sane linux/drivers/usb/README.scanner_hp_sane
--- v2.3.36/linux/drivers/usb/README.scanner_hp_sane	Wed Dec 29 13:13:19 1999
+++ linux/drivers/usb/README.scanner_hp_sane	Wed Dec 31 16:00:00 1969
@@ -1,69 +0,0 @@
-Oct. 19, 1999
-
-CHANGES
-
-- Ammended for Linux-2.3.22+
-
-
-INTRODUCTION
-
-This document will hopefully provide enough info on how to get SANE
-working with a Hewlett Packard USB capable scanner using the USB
-interface.  The majority of HP Scanners support the Scanner Control
-Language (SCL) which is both published by HP and supported by SANE.
-The only HP Scanner that I'm aware of that does not support SCL is the
-4200C.  All other HP scanners with USB interfaces should work (4100C,
-5200C, 6200C, and 6300C).  Of course as HP releases new scanners this
-information may change.
-
-
-REQUIREMENTS
-
-In order to get this running you'll need USB support in your kernel in
-addition to USB Scanner support.  Please refer to README.scanner
-for issues pertaining to Linux USB and USB Scanner support.
-
-An installed version of SANE which is available from
-http://www.mostang.com/sane/.  Testing has been performed using
-version SANE-1.0.1.  For instructions on building and installing SANE,
-refer to the various README files within the SANE distribution.
-
-
-OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW?
-
-NOTE: $INSTALL_DIR is the location where SANE was installed.  It may
-be /usr/local, /usr, /opt or somewhere else.  If you don't know, ask
-your system administrator.
-
-1) Make sure that you have the libsane-hp.* libraries under the
-$INSTALL_DIR/lib/sane/ directory.  If you don't, then the HP backend
-was either not compiled or installed properly.
-
-2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following
-files: dll.conf, hp.conf.
-
-  dll.conf:  Make sure that the 'hp' entry is present and uncommented.
-
-  hp.conf: This should contain two lines:
-
-    /dev/usbscanner
-    option connect-device
-
-3) You should now be able to use SANE (xscanimage or scanimage).
-
-Don't forget to read any relevant man pages regarding the usage of
-SANE.  If you have other entries uncommented in dll.conf, you may have
-to specify the device to (x)scanimage.  Again, `man` is your friend.
-The xscanimage (1) man page has info on how to get 'The Gimp' to work
-with xscanimage.  Note that Gimp support must be compiled into SANE
-for it work.  If you are dealing with a RedHat system, this means that
-you'll also need to install the gimp-devel rpm package.
-
-NOTE: The issues regarding core dumping by (x)scanimage have (or seem
-to be thus far) been resolved with version 0.2+ of the USB scanner
-driver which should be available in linux-2.3.23.  If you notice
-otherwise, please contact me.
-
-David /\/elson
-dnelson@jump.net
-http://www.jump.net/~dnelson
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/README.serial linux/drivers/usb/README.serial
--- v2.3.36/linux/drivers/usb/README.serial	Mon Dec 20 18:48:22 1999
+++ linux/drivers/usb/README.serial	Wed Dec 31 16:00:00 1969
@@ -1,42 +0,0 @@
-This serial driver currently only works with the Belkin and Peracom USB 
-Serial devices. It should also work for the Etek converter, but I do 
-not know the vendor id and device id of that device (if anyone does, 
-please let me know.)
-
-If your device is not compatible with the above models, you can try
-out the "generic" interface. This interface does not provide any type
-of control messages sent to the device, and does not support any kind
-of device flow control. All that is required of your device is that
-it has at least one bulk in endpoint, or one bulk out endpoint.
-To enable the driver to recognize your device, build the driver as
-a module and load it by the following invocation:
-	insmod usb-serial.o vendor=0x#### product=0x####
-where the #### is replaced with the hex representation of your device's
-vendor id and product id.
-
-The driver can handle enumerating the device, and sending and receiving
-data from the converter. However, since I do not have a spec for the Belkin,
-Peracom, and eTek devices, and the raw dumps from the Win98 driver are 
-confusing, and eTek keeps giving me the run around, no control signals are 
-currently handled, and the data will most likely come through on a baud
-rate that you are not expecting. So if you have these devices, do not 
-expect the correct data to show up at either end. 
-
-The major number that the driver uses is 188 so to use the driver, create
-the following nodes:
-mknod /dev/ttyUSB0 c 188 0
-mknod /dev/ttyUSB1 c 188 1
-mknod /dev/ttyUSB2 c 188 2
-mknod /dev/ttyUSB3 c 188 3
-
-then plug in a device and use your friendly terminal program to see what
-happens.
-
-If anyone has any problems getting the device to enumerate, or data to 
-flow through it, please contact me.
-
-
-
-greg k-h
-greg@kroah.com
-
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/README.uhci linux/drivers/usb/README.uhci
--- v2.3.36/linux/drivers/usb/README.uhci	Mon Dec 20 18:48:22 1999
+++ linux/drivers/usb/README.uhci	Wed Dec 31 16:00:00 1969
@@ -1,165 +0,0 @@
-Specification and Internals for the New UHCI Driver (Whitepaper...)
-
-	brought to you by
-
-	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)
- 
-	$Id: README.uhci,v 1.1 1999/12/14 14:03:02 fliegl Exp $
-
-This document and the new uhci sources can be found on
-		http://hotswap.in.tum.de/usb
-
-1. General issues
-
-1.1 Why a new UHCI driver, we already have one?!?
-
-Correct, but its internal structure got more and more mixed up by the (still
-ongoing) efforts to get isochronous transfers (ISO) to work.
-Since there is an increasing need for reliable ISO-transfers (especially 
-for USB-audio needed by TS and for a DAB-USB-Receiver build by GA and DF), 
-this state was a bit unsatisfying in our opinion, so we've decided (based
-on knowledge and experiences with the old UHCI driver) to start 
-from scratch with a new approach, much simpler but at the same time more 
-powerful.
-It is inspired by the way Win98/Win2000 handles USB requests via URBs,
-but it's definitely 100% free of MS-code and doesn't crash while 
-unplugging an used ISO-device like Win98 ;-)
-Some code for HW setup and root hub management was taken from the 
-original UHCI driver, but heavily modified to fit into the new code.
-The invention of the basic concept, and major coding were completed in two 
-days (and nights) on the 16th and 17th of October 1999, now known as the
-great USB-October-Revolution started by GA, DF, and TS ;-)
-
-Since the concept is in no way UHCI dependant, we hope that it will also be 
-transfered to the OHCI-driver, so both drivers share a common API.
-
-1.2. Advantages and disadvantages
-
-+ All USB transfer types work now!
-+ Asynchronous operation
-+ Simple, but powerful interface (only two calls for start and cancel)
-+ Easy migration to the new API, simplified by a compatibility API
-+ Simple usage of ISO transfers
-+ Automatic linking of requests
-+ ISO transfers allow variable length for each frame and striping
-+ No CPU dependent and non-portable atomic memory access, no asm()-inlines
-+ Tested on x86 and Alpha
-
-- Rewriting for ISO transfers needed
-
-1.3. Is there some compatibility to the old API?
-
-Yes, but only for control, bulk and interrupt transfers. We've implemented 
-some wrapper calls for these transfer types. The usbcore works fine with 
-these wrappers. For ISO there's no compatibility, because the old ISO-API 
-and its semantics were unnecessary complicated in our opinion.
-
-1.4. What's really working?
-
-As said above, CTRL und BULK already work fine even with the wrappers,
-so legacy code wouldn't notice the change.
-Regarding to Thomas, ISO transfers now run stable with USB audio.
-INT transfers (e.g. mouse driver) work fine, too.
-
-1.5. Are there any bugs?
-
-No ;-)
-Hm...
-Well, of course this implementation needs extensive testing on all available
-hardware, but we believe that any fixes shouldn't harm the overall concept.
-
-1.6. What should be done next?
-
-A large part of the request handling seems to be identical for UHCI and 
-OHCI, so it would be a good idea to extract the common parts and have only 
-the HW specific stuff in uhci.c. Furthermore, all other USB device drivers
-should need URBification, if they use isochronous or interrupt transfers.
-One thing missing in the current implementation (and the old UHCI driver) 
-is fair queueing for BULK transfers. Since this would need (in principle) 
-the alteration of already constructed TD chains (to switch from depth to 
-breadth execution), another way has to be found. Maybe some simple 
-heuristics work with the same effect.
-
----------------------------------------------------------------------------
-
-2. Internal structure and mechanisms
-
-To get quickly familiar with the internal structures, here's a short
-description how the new UHCI driver works. However, the ultimate source of
-truth is only uhci.c!
-
-2.1. Descriptor structure (QHs and TDs)
-
-During initialization, the following skeleton is allocated in init_skel:
-
-	 framespecific           |           common chain     
-
-framelist[]
-[  0 ]-----> TD --> TD -------\
-[  1 ]-----> TD --> TD --------> TD ----> QH -------> QH -------> QH ---> NULL
-  ...        TD --> TD -------/
-[1023]-----> TD --> TD ------/
-	     
-	     ^^     ^^           ^^       ^^          ^^          ^^
-   1024 TDs for   7 TDs for    1 TD for   Start of    Start of    End Chain
-	    ISO  INT (2-128ms) 1ms-INT    CTRL Chain  BULK Chain
-
-For each CTRL or BULK transfer a new QH is allocated and the containing data
-transfers are appended as (vertical) TDs. After building the whole QH with its
-dangling TDs, the QH is inserted before the BULK Chain QH (for CTRL) or
-before the End Chain QH (for BULK). Since only the QH->next pointers are
-affected, no atomic memory operation is required. The three QHs in the
-common chain are never equipped with TDs!
-
-For ISO or INT, the TD for each frame is simply inserted into the apropriate
-ISO/INT-TD-chain for the desired frame. The 7 skeleton INT-TDs are scattered
-among the 1024 frames similar to the old UHCI driver.
-
-For CTRL/BULK/ISO, the last TD in the transfer has the IOC-bit set. For INT,
-every TD (there is only one...) has the IOC-bit set.
-
-Besides the data for the UHCI controller (2 or 4 32bit words), the descriptors
-are double-linked through the .vertical and .horizontal elements in the 
-SW data of the descriptor (using the double-linked list structures and 
-operations), but SW-linking occurs only in closed domains, i.e. for each of
-the 1024 ISO-chains and the 8 INT-chains there is a closed cycle. This 
-simplifies all insertions and unlinking operations and avoids costly 
-bus_to_virt()-calls.
-
-2.2. URB structure and linking to QH/TDs
-
-During assembly of the QH and TDs of the requested action, these descriptors
-are stored in urb->urb_list, so the allocated QH/TD descriptors are bound to
-this URB.
-If the assembly was successful and the descriptors were added to the HW chain,
-the corresponding URB is inserted into a global URB list for this controller.
-This list stores all pending URBs.
-
-2.3. Interrupt processing
-
-Since UHCI provides no means to directly detect completed transactions, the
-following is done in each UHCI interrupt (uhci_interrupt()):
-
-For each URB in the pending queue (process_urb()), the ACTIVE-flag of the 
-associated TDs are processed (depending on the transfer type 
-process_{transfer|interrupt|iso}()). If the TDs are not active anymore, 
-they indicate the completion of the transaction and the status is calculated. 
-Inactive QH/TDs are removed from the HW chain (since the host controller
-already removed the TDs from the QH, no atomic access is needed) and 
-eventually the URB is marked as completed (OK or errors) and removed from the 
-pending queue. Then the next linked URB is submitted. After (or immediately 
-before) that, the completion handler is called.
-
-2.4. Unlinking URBs
-
-First, all QH/TDs stored in the URB are unlinked from the HW chain. 
-To ensure that the host controller really left a vertical TD chain, we 
-wait for one frame. After that, the TDs are physically destroyed.
-
-2.5. URB linking and the consequences
-
-Since URBs can be linked and the corresponding submit_urb is called in
-the UHCI-interrupt, all work associated with URB/QH/TD assembly has to be
-interrupt save. This forces kmalloc to use GFP_ATOMIC in the interrupt.
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/ohci-hcd.c linux/drivers/usb/ohci-hcd.c
--- v2.3.36/linux/drivers/usb/ohci-hcd.c	Mon Dec 20 18:48:22 1999
+++ linux/drivers/usb/ohci-hcd.c	Wed Jan  5 08:44:47 2000
@@ -334,7 +334,7 @@
 	/* for ISOC transfers calculate start frame index */
 	if (urb->transfer_flags & USB_ISO_ASAP) { 
 		urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1): 
-								(ohci->hcca.frame_no + 10)) & 0xffff;
+								(le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff;
 	}	
 	
 	td_submit_urb (urb); /* fill the TDs and link it to the ed */
@@ -385,8 +385,10 @@
 			spin_unlock_irqrestore (&usb_ed_lock, flags);
 
 			current->state = TASK_UNINTERRUPTIBLE;
-			schedule_timeout (HZ / 10); /* wait until all TDs are deleted */
-			remove_wait_queue (&op_wakeup, &wait); 
+			if(schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
+				remove_wait_queue (&op_wakeup, &wait); 
+			else
+				printk (KERN_ERR MODSTR "unlink URB timeout!\n");
 		} else 
 			urb_rm_priv (urb);
 		usb_dec_dev_use (urb->dev);		
@@ -463,7 +465,7 @@
 {
 	ohci_t * ohci = usb_dev->bus->hcpriv;
 	
-	return ohci->hcca.frame_no;
+	return le16_to_cpu (ohci->hcca.frame_no);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -775,7 +777,7 @@
 	writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
 	writel (OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */
 
-	frame = ohci->hcca.frame_no & 0x1;
+	frame = le16_to_cpu (ohci->hcca.frame_no) & 0x1;
 	ed->ed_rm_list = ohci->ed_rm_list[frame];
 	ohci->ed_rm_list[frame] = ed;
 
@@ -1486,7 +1488,7 @@
 	writel (0, &ohci->regs->ed_controlhead);
 	writel (0, &ohci->regs->ed_bulkhead);
 	
-	writel (virt_to_bus(&ohci->hcca), &ohci->regs->hcca); /* a reset clears this */
+	writel (virt_to_bus (&ohci->hcca), &ohci->regs->hcca); /* a reset clears this */
    
   	fminterval = 0x2edf;
 	writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
@@ -1527,14 +1529,14 @@
 	struct ohci_regs * regs = ohci->regs;
  	int ints; 
 
-	if ((ohci->hcca.done_head != 0) && !(ohci->hcca.done_head & 0x01)) {
+	if ((ohci->hcca.done_head != 0) && !(le32_to_cpu (ohci->hcca.done_head) & 0x01)) {
 		ints =  OHCI_INTR_WDH;
 	} else { 
  		if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0)
 			return;
 	} 
 
-	dbg (KERN_DEBUG MODSTR "Interrupt: %x frame: %x \n", ints, ohci->hcca.frame_no);
+	dbg (KERN_DEBUG MODSTR "Interrupt: %x frame: %x \n", ints, le16_to_cpu (ohci->hcca.frame_no));
 	
 	if (ints & OHCI_INTR_WDH) {
 		writel (OHCI_INTR_WDH, &regs->intrdisable);	
@@ -1548,7 +1550,7 @@
 	}
 
 	if (ints & OHCI_INTR_SF) { 
-		unsigned int frame = (ohci->hcca.frame_no) & 1;
+		unsigned int frame = le16_to_cpu (ohci->hcca.frame_no) & 1;
 		writel (OHCI_INTR_SF, &regs->intrdisable);	
 		if (ohci->ed_rm_list[!frame] != NULL) {
 			dl_del_list (ohci, !frame);
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- v2.3.36/linux/drivers/usb/ov511.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/usb/ov511.c	Wed Jan  5 08:44:47 2000
@@ -14,7 +14,22 @@
  * Version History:
  *    Version 1.00 - Initial version
  */
- 
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 
 #define __NO_VERSION__
 
@@ -46,13 +61,15 @@
 #include "usb.h"
 #include "ov511.h"
 
+#define OV511_I2C_RETRIES 3
+
 /* Video Size 384 x 288 x 3 bytes for RGB */
-#define MAX_FRAME_SIZE (384 * 288 * 3)
+#define MAX_FRAME_SIZE (320 * 240 * 3)
 
 // FIXME - Force CIF to make some apps happy for the moment. Should find a 
 //         better way to do this.
-#define DEFAULT_WIDTH 384
-#define DEFAULT_HEIGHT 288
+#define DEFAULT_WIDTH 320
+#define DEFAULT_HEIGHT 240
 
 char kernel_version[] = UTS_RELEASE;
 
@@ -173,7 +190,7 @@
 	vfree(mem);
 }
 
-int usb_ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value)
+int ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value)
 {
 	int rc;
 
@@ -183,13 +200,13 @@
 		USB_TYPE_CLASS | USB_RECIP_DEVICE,
 		0, (__u16)reg, &value, 1, HZ);	
 			
-	PDEBUG("reg write: 0x%X:0x%X\n", reg, value);
+	PDEBUG("reg write: 0x%02X:0x%02X\n", reg, value);
 			
 	return rc;
 }
 
 /* returns: negative is error, pos or zero is data */
-int usb_ov511_reg_read(struct usb_device *dev, unsigned char reg)
+int ov511_reg_read(struct usb_device *dev, unsigned char reg)
 {
 	int rc;
 	unsigned char buffer[1];
@@ -200,7 +217,7 @@
 		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE,
 		0, (__u16)reg, buffer, 1, HZ);
                                
-	PDEBUG("reg read: 0x%X:0x%X\n", reg, buffer[0]);
+	PDEBUG("reg read: 0x%02X:0x%02X\n", reg, buffer[0]);
 	
 	if(rc < 0)
 		return rc;
@@ -208,89 +225,116 @@
 		return buffer[0];	
 }
 
-int usb_ov511_cam_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value)
+int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char value)
 {
-	int rc;
-	
-	// Three byte write cycle
-	
-	//    Set slave ID (This might only need to be done once)
-	//    (CAMERA SPECIFIC (OV7610/OV7110))
-	rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
-	                         OV7610_I2C_WRITE_ID);
-	if (rc < 0) return rc;
-	
-	//    Select camera register (I2C sub-address)
-	rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg);
-	if (rc < 0) return rc;
+	int rc, retries;
 
-	//    Write "value" to I2C data port of OV511
-	rc = usb_ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value);	
-	if (rc < 0) return rc;
-	
-	// FIXME - should ensure bus is idle before continuing
-	
-	//    Initiate 3-byte write cycle
-	rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01);	
+	PDEBUG("i2c write: 0x%02X:0x%02X\n", reg, value);
+	/* Three byte write cycle */
+	for(retries = OV511_I2C_RETRIES;;) {
+		/* Select camera register */
+		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg);
+		if (rc < 0) return rc;
+
+		/* Write "value" to I2C data port of OV511 */
+		rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value);	
+		if (rc < 0) return rc;
+
+		/* Initiate 3-byte write cycle */
+		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01);
+		if (rc < 0) return rc;
+
+		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
+		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+		if (rc < 0) return rc;
 
-	return rc;
+		if((rc&2) == 0) /* Ack? */
+			break;
+
+		/* I2C abort */	
+		ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
+
+		if (--retries < 0) return -1;
+	}
+
+	return 0;
 }
 
 /* returns: negative is error, pos or zero is data */
-int usb_ov511_cam_reg_read(struct usb_device *dev, unsigned char reg)
+int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
 {
-	int rc;
+	int rc, value, retries;
 
-	// Two byte write cycle
-	
-	//    Set slave ID (This might only need to be done once)
-	//    (CAMERA SPECIFIC (OV7610/OV7110))
-	rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, 		                         OV7610_I2C_WRITE_ID);
-	if (rc < 0) return rc;
-	
-	//    Select camera register (I2C sub-address)
-	rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);	
-	if (rc < 0) return rc;
-	
-	//    Initiate 2-byte write cycle
-	rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);	
-	if (rc < 0) return rc;
-	
-	// Two byte read cycle
-	
-	//    Set slave ID (This might only need to be done once)
-	//    (CAMERA SPECIFIC (OV7610/OV7110))
-	rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ,
-	                         OV7610_I2C_READ_ID);
-	if (rc < 0) return rc;
-	
-	//    Initiate 2-byte read cycle
-	rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);	
+	/* Two byte write cycle */
+	for(retries = OV511_I2C_RETRIES;;) {
+		/* Select camera register */
+		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
+		if (rc < 0) return rc;
+
+		/* Initiate 2-byte write cycle */
+		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);
+		if (rc < 0) return rc;
+
+		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
+		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+		if (rc < 0) return rc;
+
+		if((rc&2) == 0) /* Ack? */
+			break;
+
+		/* I2C abort */	
+		ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
+
+		if (--retries < 0) return -1;
+	}
+
+	/* Two byte read cycle */
+	for(retries = OV511_I2C_RETRIES;;) {
+		/* Initiate 2-byte read cycle */
+		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
+		if (rc < 0) return rc;
+
+		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
+		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+		if (rc < 0) return rc;
+
+		if((rc&2) == 0) /* Ack? */
+			break;
+
+		/* I2C abort */	
+		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
+		if (rc < 0) return rc;
+
+		if (--retries < 0) return -1;
+	}
+
+	value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
+	PDEBUG("i2c read: 0x%02X:0x%02X\n", reg, value);
+		
+	/* This is needed to make ov511_i2c_write() work */
+	rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
 	if (rc < 0) return rc;
 	
-	// FIXME - should check I2C bus status here before reading data!
-	
-	//    Write "value" to I2C data port of OV511
-	return usb_ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);	
+	return (value);
 }
 
-int usb_ov511_reset(struct usb_device *dev, unsigned char reset_type)
+int ov511_reset(struct usb_device *dev, unsigned char reset_type)
 {
 	int rc;
 	
 	PDEBUG("Reset: type=0x%X\n", reset_type);
-	rc = usb_ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);
+	rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);
 	if (rc < 0)
 		printk(KERN_ERR "ov511: reset: command failed\n");
 
-	rc = usb_ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);
+	rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);
 	if (rc < 0)
 		printk(KERN_ERR "ov511: reset: command failed\n");
 
 	return rc;
 }
 
-int usb_ov511_set_packet_size(struct usb_ov511 *ov511, int size)
+int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
 {
 	int alt, multiplier, err;
 		
@@ -303,7 +347,7 @@
 			break;
 		case 993:
 			alt = 1;
-			multiplier = 32;
+			multiplier = 31;
 			break;
 		case 768:
 			alt = 2;
@@ -311,7 +355,7 @@
 			break;
 		case 769:
 			alt = 3;
-			multiplier = 25;
+			multiplier = 24;
 			break;
 		case 512:
 			alt = 4;
@@ -319,11 +363,11 @@
 			break;
 		case 513:
 			alt = 5;
-			multiplier = 17;
+			multiplier = 16;
 			break;
 		case 257:
 			alt = 6;
-			multiplier = 9;
+			multiplier = 8;
 			break;
 		case 0:
 			alt = 7;
@@ -335,7 +379,7 @@
 			return -EINVAL;
 	}
 
-	err = usb_ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
+	err = ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
 	                          multiplier);
 	if (err < 0) {
 		printk(KERN_ERR "ov511: Set packet size: Set FIFO size ret %d\n",
@@ -349,7 +393,7 @@
 	}
 
 	// FIXME - Should we only reset the FIFO?
-	if (usb_ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0)
+	if (ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0)
 		return -ENOMEM;
 
 	return 0;
@@ -358,43 +402,85 @@
 /* How much data is left in the scratch buf? */
 #define scratch_left(x)	(ov511->scratchlen - (int)((char *)x - (char *)ov511->scratch))
 
-// FIXME - Useless stub
-static void ov511_parse_data(struct usb_ov511 *ov511)
+static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
 {
-	PDEBUG("ov511_parse_data not implemented\n"); // TEMPORARY CODE
-}
-
-static int ov511_compress_isochronous(struct usb_ov511 *ov511, urb_t *urb)
-{
-	unsigned char *cdata, *data;
+	unsigned char *cdata;
 	int i, totlen = 0;
+	int aPackNum[10];
+	struct ov511_frame *frame;
+
+	if (ov511->curframe == -1) {
+	  return 0;
+	}
 
-	data = ov511->scratch + ov511->scratchlen;
 	for (i = 0; i < urb->number_of_packets; i++) {
 		int n = urb->iso_frame_desc[i].actual_length;
 		int st = urb->iso_frame_desc[i].status;
 		
 		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
 
-		if (st) { 
+		if (!n) continue;
+
+		aPackNum[i] = n ? cdata[512] : -1;
+
+		if (st){ 
 			// Macro - must be in braces!
 			PDEBUG("data error: [%d] len=%d, status=%d\n",
 				i, n, st);
-		 }
+		}
+
+		frame = &ov511->frame[ov511->curframe];
+		
+		/* Can we find a frame end */
+		if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] | 
+		     cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
+		    (cdata[8] & 8) && (cdata[8] & 0x80)) {
+
+		    PDEBUG("Found Frame End!, packnum = %d\n", (int)(cdata[512]));
+		    PDEBUG("Current frame = %d\n", ov511->curframe);
+
+		    if (frame->scanstate == STATE_LINES) {
+		        if (waitqueue_active(&frame->wq)) {
+			  PDEBUG("About to wake up waiting processes\n");
+			  frame->grabstate = FRAME_DONE;
+			  wake_up_interruptible(&frame->wq);
+			}
+		    }
+		}
 
-		if ((ov511->scratchlen + n) > SCRATCH_BUF_SIZE) {
-			PDEBUG("scratch buf overflow!scr_len: %d, n: %d\n", ov511->scratchlen, n );
-			return totlen;
+		/* Can we find a frame start */
+		else if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] | 
+			  cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
+			 (cdata[8] & 8)) {
+		    PDEBUG("ov511: Found Frame Start!, packnum = %d\n", (int)(cdata[512]));
+		    frame->scanstate = STATE_LINES;
+		    frame->curpix = 0;
 		}
 
-		if (n) {
-			memmove(data, cdata, n);
-			data += n;
-			totlen += n;
-			ov511->scratchlen += n;
+		/* Are we in a frame? */
+		else if (frame->scanstate == STATE_LINES) {
+		  unsigned char *f = frame->data + 3 * frame->curpix;
+		  int i;
+		  if (frame->curpix <= 320 * 240 - 256) {
+		    for (i=0; i<256; i++) {
+		      *f++ = *cdata;
+		      *f++ = *cdata;
+		      *f++ = *cdata++;
+		      *f++ = *cdata;
+		      *f++ = *cdata;
+		      *f++ = *cdata++;
+		    }
+		    frame->curpix += 512;
+		  } else {
+		    PDEBUG("Too many pixels!\n");
+		  }
 		}
+
 	}
 
+	PDEBUG("pn: %d %d %d %d %d %d %d %d %d %d\n",
+	       aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4],
+	       aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);
 	return totlen;
 }
 
@@ -405,7 +491,17 @@
 	struct ov511_sbuf *sbuf;
 	int i;
 
-	PDEBUG("ov511_isoc_irq: %p status %d, errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length);
+#if 0
+	static int last_status, last_error_count, last_actual_length;
+	if (last_status != urb->status ||
+	    last_error_count != urb->error_count ||
+	    last_actual_length != urb->actual_length) {
+	  PDEBUG("ov511_isoc_irq: %p status %d, errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length);
+	  last_status = urb->status;
+	  last_error_count = urb->error_count;
+	  last_actual_length = urb->actual_length;
+	}
+#endif
 
 	if (!ov511->streaming) {
 		PDEBUG("hmmm... not streaming, but got interrupt\n");
@@ -413,11 +509,10 @@
 	}
 	
 	sbuf = &ov511->sbuf[ov511->cursbuf];
-//	usb_kill_isoc(sbuf->isodesc);
 
 	/* Copy the data received into our scratch buffer */
-	len = ov511_compress_isochronous(ov511, urb);
-
+	len = ov511_move_data(ov511, urb);
+#if 0
 	/* If we don't have a frame we're current working on, complain */
 	if (ov511->scratchlen) {
 		if (ov511->curframe < 0) {
@@ -426,7 +521,7 @@
 		} else
 			ov511_parse_data(ov511);
 	}
-
+#endif
 	for (i = 0; i < FRAMES_PER_DESC; i++) {
 		sbuf->urb->iso_frame_desc[i].status = 0;
 		sbuf->urb->iso_frame_desc[i].actual_length = 0;
@@ -435,9 +530,6 @@
 	/* Move to the next sbuf */
 	ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF;
 
-	/* Reschedule this block of Isochronous desc */
-//	usb_run_isoc(sbuf->isodesc, ov511->sbuf[ov511->cursbuf].isodesc);
-
 	return;
 }
 
@@ -452,9 +544,25 @@
 	ov511->cursbuf = 0;
 	ov511->scratchlen = 0;
 
-	// FIXME - is this the proper size?
-	usb_ov511_set_packet_size(ov511, 512);
+	ov511_set_packet_size(ov511, 512);
 	
+#define OV511_COLOR_BAR_TEST
+#ifdef OV511_COLOR_BAR_TEST
+	{
+	  int rc;
+	  rc = ov511_i2c_read(ov511->dev, 0x12);
+	  rc = ov511_i2c_write(ov511->dev, 0x12, 0x3f);
+	  rc = ov511_i2c_read(ov511->dev, 0x12);
+	  rc = ov511_i2c_read(ov511->dev, 0x13);
+	  rc = ov511_i2c_write(ov511->dev, 0x14, 0x4);
+	  rc = ov511_i2c_read(ov511->dev, 0x14);
+	  rc = ov511_i2c_write(ov511->dev, 0x28, 0x60);
+	  rc = ov511_i2c_read(ov511->dev, 0x28);
+	  ov511_reg_write(ov511->dev, OV511_REG_CAMERA_DATA_INPUT_SELECT,
+			      0);
+	}
+#endif
+
 	/* We double buffer the Iso lists */
 	urb = usb_alloc_urb(FRAMES_PER_DESC);
 	
@@ -494,7 +602,7 @@
  		urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
 		urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
 	}
-	
+
 	ov511->sbuf[1].urb->next = ov511->sbuf[0].urb;
 	ov511->sbuf[0].urb->next = ov511->sbuf[1].urb;
 
@@ -509,7 +617,7 @@
 
 	ov511->streaming = 1;
 
-	return 0; 
+	return 0;
 }
 
 
@@ -518,14 +626,7 @@
 	if (!ov511->streaming)
 		return;
 
-// FIXME - Figure out how to do this with the ov511 (Does the below do it?)
-//	/* Turn off continuous grab */
-//	if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) {
-//		printk(KERN_ERR "cpia_set_grab_mode error\n");
-//		return /* -EBUSY */;
-//	}
-
-	usb_ov511_set_packet_size(ov511, 0);
+	ov511_set_packet_size(ov511, 0);
 	
 	/* Unschedule all of the iso td's */
 	usb_unlink_urb(ov511->sbuf[1].urb);
@@ -570,25 +671,8 @@
 		height = DEFAULT_HEIGHT;
 	height = (height / 4) * 4;	/* Multiple of 4 */
 	
-// FIXME - Don't know how to implement the equivalent of this for the ov511
-//	/* Set the ROI they want */
-//	if (usb_cpia_set_roi(cpia->dev, 0, width / 8, 0, height / 4) < 0)
-//		return -EBUSY;
-
-//	if (usb_cpia_set_compression(cpia->dev, cpia->compress ?
-//			COMP_AUTO : COMP_DISABLED, DONT_DECIMATE) < 0) {
-//		printk(KERN_ERR "cpia_set_compression error\n");
-//		return -EBUSY;
-//	}
-
-	/* We want a fresh frame every 30 we get */
-	ov511->compress = (ov511->compress + 1) % 30;
-
-//	/* Grab the frame */
-//	if (usb_cpia_upload_frame(cpia->dev, WAIT_FOR_NEXT_FRAME) < 0) {
-//		printk(KERN_ERR "cpia_upload_frame error\n");
-//		return -EBUSY;
-//	}
+//	/* We want a fresh frame every 30 we get */
+//	ov511->compress = (ov511->compress + 1) % 30;
 
 	return 0;
 }
@@ -1061,48 +1145,69 @@
 	0
 };
 
-static int usb_ov511_configure(struct usb_ov511 *ov511)
+static int ov511_configure(struct usb_ov511 *ov511)
 {
 	struct usb_device *dev = ov511->dev;
 	int temprc;   // DEBUG CODE
-	
+
 	/* Set altsetting 0 */
 	if (usb_set_interface(dev, ov511->iface, 0) < 0) {
 		printk(KERN_ERR "ov511: usb_set_interface error\n");
 		return -EBUSY;
 	}
-	
+
 	memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template));
 
 	init_waitqueue_head(&ov511->frame[0].wq);
 	init_waitqueue_head(&ov511->frame[1].wq);
-	
+
 	if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) == -1) {
 		printk(KERN_ERR "ov511: video_register_device failed\n");
 		return -EBUSY;
 	}
 
-	// Disable compression
-	if (usb_ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) {
-		printk(KERN_ERR "ov511: disable compression: command failed\n");
+	/* Reset in case driver was unloaded and reloaded without unplug */
+	if (ov511_reset(dev, OV511_RESET_ALL) < 0)
 		goto error;
-	}
-	
-	// Initialize system
-	// FIXME - This should be moved to a function
-	if (usb_ov511_reg_write(dev, OV511_REG_SYSTEM_INIT, 0x01) < 0) {
+
+	/* Initialize system */
+	if (ov511_reg_write(dev, OV511_REG_SYSTEM_INIT, 0x01) < 0) {
 		printk(KERN_ERR "ov511: enable system: command failed\n");
 		goto error;
 	}
+
+	/* This seems to be necessary */
+	if (ov511_reset(dev, OV511_RESET_ALL) < 0)
+		goto error;
+
+	/* Disable compression */
+	if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) {
+		printk(KERN_ERR "ov511: disable compression: command failed\n");
+		goto error;
+	}
+
+// FIXME - error checking needed
+	ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
+	                     OV7610_I2C_WRITE_ID);
+	ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ,
+	                     OV7610_I2C_READ_ID);
+
+// DEBUG CODE
+//	usb_ov511_reg_write(dev, OV511_REG_I2C_CLOCK_PRESCALER,
+//						 OV511_I2C_CLOCK_PRESCALER);
 	
-	if (usb_ov511_reset(dev, OV511_RESET_NOREGS) < 0)
+	if (ov511_reset(dev, OV511_RESET_NOREGS) < 0)
 		goto error;
 	
+	/* Dummy read to sync I2C */
+	ov511_i2c_read(dev, 0x1C);
+	
 // DEBUG - TEST CODE FOR CAMERA REG READ
-     	temprc = usb_ov511_cam_reg_read(dev, 0x1D);
-     	PDEBUG("Camera reg 0x1D: 0x%X\n", temprc);
-// END DEBUG CODE
+	temprc = ov511_i2c_read(dev, 0x1C);
 
+     	temprc = ov511_i2c_read(dev, 0x1D);
+// END DEBUG CODE
+     	
 	ov511->compress = 0;
 	
 	return 0;
@@ -1156,14 +1261,14 @@
 	ov511->dev = dev;
 	ov511->iface = interface->bInterfaceNumber;
 
-	rc = usb_ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
+	rc = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
 	if (rc < 0) {
 		printk("ov511: Unable to read camera bridge registers\n");
 		return NULL;
-	} else if (rc == 3) { // D-Link DSB-C300
+	} else if (rc == 3) {  /* D-Link DSB-C300 */
 		printk("ov511: Camera is a D-Link DSB-C300\n");
 		ov511->customid = 3;
-	} else if (rc == 21) { // Creative Labs WebCam 3
+	} else if (rc == 21) { /* Creative Labs WebCam 3 */
 		printk("ov511: Camera is a Creative Labs WebCam 3\n");
 		ov511->customid = 21;		
 	} else {
@@ -1173,11 +1278,7 @@
 		return NULL;
 	}
 
-	// Reset in case driver was unloaded and reloaded without unplug
-	if (usb_ov511_reset(dev, OV511_RESET_ALL) < 0)
-		return NULL;
-	
-	if (!usb_ov511_configure(ov511)) {
+	if (!ov511_configure(ov511)) {
 		ov511->user=0;
 		init_MUTEX(&ov511->lock);	/* to 1 == available */
 		return ov511;
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/ov511.h linux/drivers/usb/ov511.h
--- v2.3.36/linux/drivers/usb/ov511.h	Tue Jan  4 13:57:17 2000
+++ linux/drivers/usb/ov511.h	Wed Jan  5 08:44:47 2000
@@ -63,7 +63,7 @@
 /* System control register numbers */
 #define OV511_REG_SYSTEM_RESET				0x50
 #define 	OV511_RESET_UDC				0x01
-#define 	OV511_RESET_I2O				0x02
+#define 	OV511_RESET_I2C				0x02
 #define 	OV511_RESET_FIFO			0x04
 #define 	OV511_RESET_OMNICE			0x08
 #define 	OV511_RESET_DRAM_INTF		0x10
@@ -109,7 +109,7 @@
 #define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
 
 #define FRAMES_PER_DESC		10  /* FIXME - What should this be? */
-#define FRAME_SIZE_PER_DESC	960	/* FIXME - Shouldn't be hardcoded */
+#define FRAME_SIZE_PER_DESC	512	/* FIXME - Shouldn't be hardcoded */
 
 // FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)?
 #define OV511_ENDPOINT_ADDRESS 0x81 /* Address of isoc endpoint */
@@ -118,6 +118,7 @@
 // FIXME - these can vary between specific models
 #define OV7610_I2C_WRITE_ID 0x42
 #define OV7610_I2C_READ_ID  0x43
+#define OV511_I2C_CLOCK_PRESCALER 0x03
 
 /* Prototypes */
 int usb_ov511_reg_read(struct usb_device *dev, unsigned char reg);
@@ -164,6 +165,7 @@
 	int scanstate;		/* State of scanning */
 
 	int curline;		/* Line of frame we're working on */
+	int curpix;
 
 	long scanlength;	/* uncompressed, raw data length of frame */
 	long bytes_read;	/* amount of scanlength that has been read from *data */
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c
--- v2.3.36/linux/drivers/usb/usb_scsi.c	Mon Dec 20 18:48:22 1999
+++ linux/drivers/usb/usb_scsi.c	Thu Jan  6 10:36:19 2000
@@ -1,24 +1,22 @@
-/* Driver for USB SCSI-like devices
+/* Driver for USB Mass Storage compliant devices
  *
  * (c) 1999 Michael Gee (michael@linuxspecific.com)
- * (c) 1999 Matthew Dharm (mdharm@one-eyed-alien.net)
- *
- * This driver is schizoid  - it makes a USB device appear as both a SCSI
- * device and a character device. The latter is only available if the device
- * has an interrupt endpoint, and is used specifically to receive interrupt
- * events.
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * In order to support various 'strange' devices, this module supports plug-in
  * device-specific filter modules, which can do their own thing when required.
  *
- * Further reference.
+ * Further reference:
  *	This driver is based on the 'USB Mass Storage Class' document. This
- *	describes in detail the transformation of SCSI command blocks to the
- *	equivalent USB control and data transfer required.
+ *	describes in detail the protocol used to communicate with such
+ *      devices.  Clearly, the designers had SCSI commands in mind when they
+ *      created this document.  The commands are all similar to commands
+ *      in the SCSI-II specification.
+ *
  *	It is important to note that in a number of cases this class exhibits
  *	class-specific exemptions from the USB specification. Notably the
  *	usage of NAK, STALL and ACK differs from the norm, in that they are
- *	used to communicate wait, failed and OK on SCSI commands.
+ *	used to communicate wait, failed and OK on commands.
  *	Also, for certain devices, the interrupt endpoint is used to convey
  *	status of a command.
  *
@@ -47,12 +45,14 @@
 #include "usb.h"
 #include "usb_scsi.h"
 
-/* direction table (what a pain) */
-
+/* direction table -- this indicates the direction of the data
+ * transfer for each command code -- a 1 indicates input
+ */
 unsigned char us_direction[256/8] = {
-
-#include "usb_scsi_dt.c"
-
+	0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, 
+	0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
 #ifdef REWRITE_PROJECT
diff -u --recursive --new-file v2.3.36/linux/drivers/usb/usb_scsi_dt.c linux/drivers/usb/usb_scsi_dt.c
--- v2.3.36/linux/drivers/usb/usb_scsi_dt.c	Mon Jun  7 20:04:01 1999
+++ linux/drivers/usb/usb_scsi_dt.c	Wed Dec 31 16:00:00 1969
@@ -1,4 +0,0 @@
-0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, 
-0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
diff -u --recursive --new-file v2.3.36/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
--- v2.3.36/linux/drivers/video/aty128fb.c	Thu Nov 18 20:25:37 1999
+++ linux/drivers/video/aty128fb.c	Thu Jan  6 09:54:06 2000
@@ -1598,14 +1598,13 @@
 void
 aty128pci_probe(void)
 {
-    struct pci_dev *pdev;
+    struct pci_dev *pdev = NULL;
     struct fb_info_aty128 *info;
     unsigned long fb_addr, reg_addr;
     u16 tmp;
 
-    for (pdev = pci_devices; pdev; pdev = pdev->next) {
-	if (((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
-	    (pdev->vendor == PCI_VENDOR_ID_ATI)) {
+    while ((pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) {
+	if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
 	    struct resource *rp;
 
 	    /* FIXME add other known R128 device ID's */
diff -u --recursive --new-file v2.3.36/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.3.36/linux/drivers/video/atyfb.c	Wed Dec 29 13:13:20 1999
+++ linux/drivers/video/atyfb.c	Thu Jan  6 10:32:49 2000
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.133 1999/12/09 10:23:13 davem Exp $
+/*  $Id: atyfb.c,v 1.134 1999/12/23 21:32:09 geert Exp $
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *	Copyright (C) 1997-1998  Geert Uytterhoeven
@@ -470,9 +470,6 @@
      */
 
 int atyfb_init(void);
-#ifdef CONFIG_FB_OF
-void atyfb_of_init(struct device_node *dp);
-#endif
 #ifndef MODULE
 int atyfb_setup(char*);
 #endif
@@ -3640,13 +3637,10 @@
 
 int __init atyfb_init(void)
 {
-#if defined(CONFIG_FB_OF)
-    /* We don't want to be called like this. */
-    /* We rely on Open Firmware (offb) instead. */
-#elif defined(CONFIG_PCI)
-    struct pci_dev *pdev;
+#if defined(CONFIG_PCI)
+    struct pci_dev *pdev = NULL;
     struct fb_info_aty *info;
-    unsigned long addr;
+    unsigned long addr, res_start, res_size;
 #ifdef __sparc__
     extern void (*prom_palette) (int);
     extern int con_is_present(void);
@@ -3663,9 +3657,8 @@
     u16 tmp;
 #endif
 
-    for (pdev = pci_devices; pdev; pdev = pdev->next) {
-	if (((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
-	    (pdev->vendor == PCI_VENDOR_ID_ATI)) {
+    while ((pdev = pci_find_device(PCI_VENDOR_ID_ATY, PCI_ANY_ID, pdev))) {
+	if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
 	    struct resource *rp;
 
 	    info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
@@ -3682,6 +3675,11 @@
 	    if (!addr)
 		continue;
 
+	    res_start = rp->start;
+	    res_size = rp->end-rp->start+1;
+	    if (!request_mem_region(res_start, res_size, "atyfb"))
+		continue;
+
 #ifdef __sparc__
 	    /*
 	     * Map memory-mapped registers.
@@ -3707,6 +3705,7 @@
 	    if (!info->mmap_map) {
 		printk("atyfb_init: can't alloc mmap_map\n");
 		kfree(info);
+		release_mem_region(res_start, res_size);
 		return -ENXIO;
 	    }
 	    memset(info->mmap_map, 0, j * sizeof(*info->mmap_map));
@@ -3886,6 +3885,7 @@
 
 	    if(!info->ati_regbase) {
 		    kfree(info);
+		    release_mem_region(res_start, res_size);
 		    return -ENOMEM;
 	    }
 
@@ -3913,6 +3913,7 @@
 
 	    if(!info->frame_buffer) {
 		    kfree(info);
+		    release_mem_region(res_start, res_size);
 		    return -ENXIO;
 	    }
 
@@ -3922,6 +3923,7 @@
 		if (info->mmap_map)
 		    kfree(info->mmap_map);
 		kfree(info);
+		release_mem_region(res_start, res_size);
 		return -ENXIO;
 	    }
 
@@ -3943,6 +3945,18 @@
 	    info->mmap_map[1].prot_mask = _PAGE_CACHE;
 	    info->mmap_map[1].prot_flag = _PAGE_E;
 #endif /* __sparc__ */
+
+#ifdef CONFIG_PMAC_PBOOK
+	    if (first_display == NULL)
+		pmu_register_sleep_notifier(&aty_sleep_notifier);
+	    info->next = first_display;
+	    first_display = info;
+#endif
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+	    if (!console_fb_info)
+		console_fb_info = &info->fb_info;
+#endif /* CONFIG_FB_COMPAT_XPMAC */
 	}
     }
 
@@ -4002,114 +4016,6 @@
 #endif /* CONFIG_ATARI */
     return 0;
 }
-
-#ifdef CONFIG_FB_OF
-void __init atyfb_of_init(struct device_node *dp)
-{
-    unsigned long addr;
-    u8 bus, devfn;
-    u16 cmd;
-    struct fb_info_aty *info;
-    int i;
-
-    if (device_is_compatible(dp, "ATY,264LTPro")) {
-	/* XXX kludge for now */
-	if (dp->name == 0 || strcmp(dp->name, "ATY,264LTProA") != 0
-	    || dp->parent == 0)
-	    return;
-	dp = dp->parent;
-    }
-    switch (dp->n_addrs) {
-	case 1:
-	case 2:
-	case 3:
-	    addr = dp->addrs[0].address;
-	    break;
-	case 4:
-	    addr = dp->addrs[1].address;
-	    break;
-	default:
-	    printk("Warning: got %d adresses for ATY:\n", dp->n_addrs);
-	    for (i = 0; i < dp->n_addrs; i++)
-		printk(" %08x-%08x", dp->addrs[i].address,
-		       dp->addrs[i].address+dp->addrs[i].size-1);
-	    if (dp->n_addrs)
-		printk("\n");
-	    return;
-    }
-
-    info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
-    if (!info) {
-	printk("atyfb_of_init: can't alloc fb_info_aty\n");
-	return;
-    }
-    memset(info, 0, sizeof(struct fb_info_aty));
-
-    info->ati_regbase_phys = 0x7ff000+addr;
-    info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys,
-						   0x1000);
-
-    if(! info->ati_regbase) {
-	    printk("atyfb_of_init: ioremap() returned NULL\n");
-	    kfree(info);
-	    return;
-    }
-
-    info->ati_regbase_phys += 0xc00;
-    info->ati_regbase += 0xc00;
-
-    /* enable memory-space accesses using config-space command register */
-    if (pci_device_loc(dp, &bus, &devfn) == 0) {
-	pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
-	if (cmd != 0xffff) {
-	    cmd |= PCI_COMMAND_MEMORY;
-	    pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
-	}
-    }
-
-#ifdef __BIG_ENDIAN
-    /* Use the big-endian aperture */
-    addr += 0x800000;
-#endif
-
-    /* Map in frame buffer */
-    info->frame_buffer_phys = addr;
-    info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
-
-    if(! info->frame_buffer) {
-	    printk("atyfb_of_init: ioremap() returned NULL\n");
-	    kfree(info);
-	    return;
-    }
-
-    if (!aty_init(info, dp->full_name)) {
-	kfree(info);
-	return;
-    }
-
-#ifdef CONFIG_PMAC_PBOOK
-    if (first_display == NULL)
-	pmu_register_sleep_notifier(&aty_sleep_notifier);
-    info->next = first_display;
-    first_display = info;
-#endif
-	
-
-#ifdef CONFIG_PMAC_PBOOK
-    if (first_display == NULL)
-	pmu_register_sleep_notifier(&aty_sleep_notifier);
-    info->next = first_display;
-    first_display = info;
-#endif
-	
-
-#ifdef CONFIG_FB_COMPAT_XPMAC
-    if (!console_fb_info)
-	console_fb_info = &info->fb_info;
-#endif /* CONFIG_FB_COMPAT_XPMAC */
-}
-#endif /* CONFIG_FB_OF */
-
 
 #ifndef MODULE
 int __init atyfb_setup(char *options)
diff -u --recursive --new-file v2.3.36/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c
--- v2.3.36/linux/drivers/video/clgenfb.c	Mon Nov  1 13:56:27 1999
+++ linux/drivers/video/clgenfb.c	Thu Jan  6 10:30:52 2000
@@ -1,7 +1,7 @@
 /*
  * drivers/video/clgenfb.c - driver for Cirrus Logic chipsets
  *
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
  *
  * Contributors (thanks, all!)
  *
@@ -2594,10 +2594,10 @@
 {
 	iounmap (info->fbmem);
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)
-	__release_region (&iomem_resource, info->fbmem_phys, info->size);
-	__release_region (&iomem_resource, 0xA0000, 65535);
+	release_mem_region(info->fbmem_phys, info->size);
+	release_mem_region(0xA0000, 65535);
 	if (release_io_ports)
-		__release_region (&ioport_resource, 0x3C0, 32);
+		release_region(0x3C0, 32);
 #endif
 }
 #endif /* MODULE */
@@ -2679,21 +2679,20 @@
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)
 
-	if (!__request_region (&iomem_resource, board_addr,
-			       board_size, "clgenfb")) {
+	if (!request_mem_region(board_addr, board_size, "clgenfb")) {
 		pci_write_config_word (pdev, PCI_COMMAND, tmp16);
 		printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n",
 		       board_addr);
 		return -1;
 	}
-	if (!__request_region (&iomem_resource, 0xA0000, 65535, "clgenfb")) {
+	if (!request_mem_region(0xA0000, 65535, "clgenfb")) {
 		pci_write_config_word (pdev, PCI_COMMAND, tmp16);
 		printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n",
 		       0xA0000L);
-		__release_region(&iomem_resource, board_addr, board_size);
+		release_mem_region(board_addr, board_size);
 		return -1;
 	}
-	if (__request_region(&ioport_resource, 0x3C0, 32, "clgenfb"))
+	if (request_region(0x3C0, 32, "clgenfb"))
 		release_io_ports = 1;
 
 #endif /* kernel > 2.3.13 */
@@ -2750,7 +2749,7 @@
 static void clgen_zorro_unmap (struct clgenfb_info *info)
 {
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)
-	__release_region(&iomem_resource, info->board_addr, info->board_size);
+	release_mem_region(info->board_addr, info->board_size);
 #endif
 	if (info->btype == BT_PICASSO4) {
 		iounmap (info->board_addr);
@@ -2788,8 +2787,7 @@
 	info->board_addr = board_addr = (unsigned long) cd->cd_BoardAddr;
 	info->board_size = board_size = (unsigned long) cd->cd_BoardSize;
 
-	if (!__request_region(&iomem_resource, board_addr,
-			      board_size, "clgenfb")) {
+	if (!request_mem_region(board_addr, board_size, "clgenfb")) {
 		printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n",
 		       board_addr);
 		return -1;
@@ -3023,7 +3021,7 @@
      */
 
 #ifdef MODULE
-MODULE_AUTHOR("Copyright 1999 Jeff Garzik <jgarzik@pobox.com>");
+MODULE_AUTHOR("Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>");
 MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
 
 int init_module (void)
diff -u --recursive --new-file v2.3.36/linux/drivers/video/clgenfb.h linux/drivers/video/clgenfb.h
--- v2.3.36/linux/drivers/video/clgenfb.h	Wed Aug 18 10:10:06 1999
+++ linux/drivers/video/clgenfb.h	Thu Jan  6 10:23:46 2000
@@ -1,7 +1,7 @@
 /*
  * drivers/video/clgenfb.h - Cirrus Logic chipset constants
  *
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
  *
  * Original clgenfb author:  Frank Neumann
  *
diff -u --recursive --new-file v2.3.36/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.3.36/linux/drivers/video/fbmem.c	Wed Dec 29 13:13:20 1999
+++ linux/drivers/video/fbmem.c	Thu Jan  6 10:31:38 2000
@@ -143,14 +143,18 @@
 #ifdef CONFIG_FB_CLGEN
 	{ "clgen", clgenfb_init, clgenfb_setup },
 #endif
+#ifdef CONFIG_FB_ATY
+	{ "atyfb", atyfb_init, atyfb_setup },
+#endif
 #ifdef CONFIG_FB_OF
+	/*
+	 * Offb must be initialized _after_ all other frame buffer devices
+	 * that use PCI probing and PCI resources! [ Geert ]
+	 */
 	{ "offb", offb_init, offb_setup },
 #endif
 #ifdef CONFIG_FB_SBUS
 	{ "sbus", sbusfb_init, sbusfb_setup },
-#endif
-#ifdef CONFIG_FB_ATY
-	{ "atyfb", atyfb_init, atyfb_setup },
 #endif
 #ifdef CONFIG_FB_ATY128
 	{ "aty128fb", aty128fb_init, aty128fb_setup },
diff -u --recursive --new-file v2.3.36/linux/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- v2.3.36/linux/drivers/video/imsttfb.c	Mon Oct 11 15:38:15 1999
+++ linux/drivers/video/imsttfb.c	Thu Jan  6 09:54:06 2000
@@ -1919,21 +1919,15 @@
 	/* We don't want to be called like this. */
 	/* We rely on Open Firmware (offb) instead. */
 #elif defined(CONFIG_PCI)
-	struct pci_dev *pdev;
+	struct pci_dev *pdev = NULL;
 	struct fb_info_imstt *p;
 	__u32 addr;
 	__u16 cmd;
 
-	for (pdev = pci_devices; pdev; pdev = pdev->next) {
-		if (!(((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
-		      && (pdev->vendor == PCI_VENDOR_ID_IMS)))
+	while ((pdev = pci_find_device(PCI_VENDOR_ID_IMS, PCI_ANY_ID, pdev))) {
+		if ((pdev->class >> 16) != PCI_BASE_CLASS_DISPLAY)
 			continue;
-
-		pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-		if (!(cmd & PCI_COMMAND_MEMORY)) {
-			cmd |= PCI_COMMAND_MEMORY;
-			pci_write_config_word(pdev, PCI_COMMAND, cmd);
-		}
+		pci_enable_device(pdev);
 
 		addr = pdev->resource[0].start;
 		if (!addr)
diff -u --recursive --new-file v2.3.36/linux/drivers/video/matroxfb.c linux/drivers/video/matroxfb.c
--- v2.3.36/linux/drivers/video/matroxfb.c	Tue Nov 23 22:42:21 1999
+++ linux/drivers/video/matroxfb.c	Thu Jan  6 09:54:06 2000
@@ -2559,14 +2559,6 @@
 };
 #endif
 
-static struct pci_dev* pci_find(struct pci_dev* p) {
-	
-	DBG("pci_find")
-	
-	if (p) return p->next;
-	return pci_devices;
-}
-
 static void initMatrox(WPMINFO struct display* p) {
 	struct display_switch *swtmp;
 
@@ -6021,15 +6013,15 @@
 
 	if (disabled)
 		return -ENXIO; 
-	while ((pdev = pci_find(pdev)) != NULL) {
+	while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) {
 		struct board* b;
 		u_int8_t rev;
 		u_int16_t svid;
 		u_int16_t sid;
 
 		pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
-		pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid);
-		pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sid);
+		svid = dev->subsystem_vendor;
+		sid = dev->subsystem_device;
 		for (b = dev_list; b->vendor; b++) {
 			if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue;
 			if (b->svid)
diff -u --recursive --new-file v2.3.36/linux/drivers/video/offb.c linux/drivers/video/offb.c
--- v2.3.36/linux/drivers/video/offb.c	Fri Oct 22 13:21:51 1999
+++ linux/drivers/video/offb.c	Thu Jan  6 10:31:38 2000
@@ -26,6 +26,7 @@
 #include <linux/fb.h>
 #include <linux/selection.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 #ifdef CONFIG_FB_COMPAT_XPMAC
 #include <asm/vc_ioctl.h>
 #endif
@@ -290,9 +291,6 @@
 }
 
 
-#ifdef CONFIG_FB_ATY
-extern void atyfb_of_init(struct device_node *dp);
-#endif /* CONFIG_FB_ATY */
 #ifdef CONFIG_FB_ATY128
 extern void aty128fb_of_init(struct device_node *dp);
 #endif /* CONFIG_FB_ATY */
@@ -414,6 +412,13 @@
     return 0;
 }
 
+
+    /*
+     *  This function is intended to go away as soon as all OF-aware frame
+     *  buffer device drivers have been converted to use PCI probing and PCI
+     *  resources. [ Geert ]
+     */
+
 static int __init offb_init_driver(struct device_node *dp)
 {
 #ifdef CONFIG_FB_ATY128
@@ -422,12 +427,6 @@
 	return 1;
     }
 #endif
-#ifdef CONFIG_FB_ATY
-    if (!strncmp(dp->name, "ATY", 3)) {
-	atyfb_of_init(dp);
-	return 1;
-    }
-#endif /* CONFIG_FB_ATY */
 #ifdef CONFIG_FB_S3TRIO
     if (!strncmp(dp->name, "S3Trio", 6)) {
     	s3triofb_init_of(dp);
@@ -506,7 +505,7 @@
 	address = (u_long)*up;
     else {
 	for (i = 0; i < dp->n_addrs; ++i)
-	    if (dp->addrs[i].size >= len)
+	    if (dp->addrs[i].size >= pitch*height*depth/8)
 		break;
 	if (i >= dp->n_addrs) {
 	    printk(KERN_ERR "no framebuffer address found for %s\n", dp->full_name);
@@ -533,17 +532,25 @@
     struct fb_var_screeninfo *var;
     struct display *disp;
     struct fb_info_offb *info;
+    unsigned long res_start = address;
+    unsigned long res_size = pitch*height*depth/8;
+
+    if (!request_mem_region(res_start, res_size, "offb"))
+	return;
 
     printk(KERN_INFO "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
 	   width, height, name, address, depth, pitch);
     if (depth != 8 && depth != 16 && depth != 32) {
 	printk(KERN_ERR "%s: can't use depth = %d\n", full_name, depth);
+	release_mem_region(res_start, res_size);
 	return;
     }
 
     info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
-    if (info == 0)
+    if (info == 0) {
+	release_mem_region(res_start, res_size);
 	return;
+    }
     memset(info, 0, sizeof(*info));
 
     fix = &info->fix;
@@ -707,6 +714,7 @@
 
     if (register_framebuffer(&info->info) < 0) {
 	kfree(info);
+	release_mem_region(res_start, res_size);
 	return;
     }
 
diff -u --recursive --new-file v2.3.36/linux/drivers/video/pm2fb.c linux/drivers/video/pm2fb.c
--- v2.3.36/linux/drivers/video/pm2fb.c	Wed Dec 29 13:13:20 1999
+++ linux/drivers/video/pm2fb.c	Thu Jan  6 10:30:52 2000
@@ -921,8 +921,8 @@
 	DPRINTK("found board: %s\n", board_table[p->board].name);
 
 	p->regions.p_fb=p->regions.fb_base;
-	if (!__request_region(&iomem_resource, p->regions.p_fb,
-			      p->regions.fb_size, "pm2fb")) {
+	if (!request_mem_region(p->regions.p_fb, p->regions.fb_size,
+		    		"pm2fb")) {
 		printk (KERN_ERR "pm2fb: cannot reserve fb memory, abort\n");
 		return 0;
 	}
@@ -933,8 +933,7 @@
 #else
 	p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE;
 #endif
-	if (!__request_region(&iomem_resource, p->regions.p_regs,
-			      PM2_REGS_SIZE, "pm2fb")) {
+	if (!request_mem_region(p->regions.p_regs, PM2_REGS_SIZE, "pm2fb")) {
 		printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abort\n");
 		UNMAP(p->regions.v_fb, p->regions.fb_size);
 		return 0;
@@ -1047,7 +1046,7 @@
 	}
 	DPRINTK("scanning PCI bus for known chipsets...\n");
 
-	for (dev = pci_devices; !pci->dev && dev; dev = dev->next) {
+	pci_for_each_dev(dev) {
 		for (i = 0; pm2pci_cards[i].vendor; i++)
 			if (pm2pci_cards[i].vendor == dev->vendor &&
 			    pm2pci_cards[i].device == dev->device) {
@@ -1056,6 +1055,8 @@
 				DPRINTK("... found %s\n", pm2pci_cards[i].name);
 				break;
 			}
+		if (pci->dev)
+			break;
 	}
 	if (!pci->dev) {
 		DPRINTK("no PCI board found.\n");
@@ -2036,10 +2037,10 @@
 	pm2fb_reset(i);
 
 	UNMAP(i->regions.v_fb, i->regions.fb_size);
-	__release_region(&iomem_resource, i->regions.p_fb, i->regions.fb_size);
+	release_mem_region(i->regions.p_fb, i->regions.fb_size);
 
 	UNMAP(i->regions.v_regs, PM2_REGS_SIZE);
-	__release_region(&iomem_resource, i->regions.p_regs, PM2_REGS_SIZE);
+	release_mem_region(i->regions.p_regs, PM2_REGS_SIZE);
 
 	if (board_table[i->board].cleanup)
 		board_table[i->board].cleanup(i);
diff -u --recursive --new-file v2.3.36/linux/drivers/video/rivafb.c linux/drivers/video/rivafb.c
--- v2.3.36/linux/drivers/video/rivafb.c	Thu Nov 18 20:25:37 1999
+++ linux/drivers/video/rivafb.c	Thu Jan  6 10:30:52 2000
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/video/rivafb.c - nVidia RIVA 128/TNT/TNT2 fb driver
  *
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
  *
  * Contributors:
  *
@@ -622,12 +622,12 @@
 	rinfo->ctrl_base_phys = rinfo->pd->resource[0].start;
 	rinfo->fb_base_phys = rinfo->pd->resource[1].start;
 
-	__request_region(&ioport_resource, 0x3C0, 32, "rivafb");
+	request_region(0x3C0, 32, "rivafb");
 
-	if (!__request_region (&iomem_resource, rinfo->ctrl_base_phys,
-			       rinfo->base0_region_size, "rivafb") ||
-	    !__request_region (&iomem_resource, rinfo->fb_base_phys,
-			       rinfo->base1_region_size, "rivafb")) {
+	if (!request_mem_region(rinfo->ctrl_base_phys,
+				rinfo->base0_region_size, "rivafb") ||
+	    !request_mem_region(rinfo->fb_base_phys, rinfo->base1_region_size,
+				"rivafb")) {
 		printk (KERN_ERR PFX "cannot reserve MMIO region\n");
 		return -ENXIO;
 	}
diff -u --recursive --new-file v2.3.36/linux/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c
--- v2.3.36/linux/drivers/video/tdfxfb.c	Sun Nov  7 16:37:34 1999
+++ linux/drivers/video/tdfxfb.c	Thu Jan  6 09:54:06 2000
@@ -1969,9 +1969,8 @@
   if(!pcibios_present()) return -ENXIO;
 #endif
 
-  for(pdev = pci_devices; pdev; pdev = pdev->next) {
+  while ((pdev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_ANY_ID, pdev))) {
     if(((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
-       (pdev->vendor == PCI_VENDOR_ID_3DFX) &&
        ((pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE) ||
 	(pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3))) {
       char* name = pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE
diff -u --recursive --new-file v2.3.36/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- v2.3.36/linux/drivers/video/vesafb.c	Mon Oct 11 15:38:15 1999
+++ linux/drivers/video/vesafb.c	Thu Jan  6 10:30:52 2000
@@ -541,8 +541,7 @@
 	video_visual = (video_bpp == 8) ?
 		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
 
-	if (!__request_region(&iomem_resource, video_base, video_size,
-			      "vesafb")) {
+	if (!request_mem_region(video_base, video_size, "vesafb")) {
 		printk(KERN_ERR
 		       "vesafb: abort, cannot reserve video memory at 0x%lu\n",
 			video_base);
@@ -647,7 +646,7 @@
 
 	/* request failure does not faze us, as vgacon probably has this
 	 * region already (FIXME) */
-	__request_region(&ioport_resource, 0x3c0, 32, "vesafb");
+	request_region(0x3c0, 32, "vesafb");
 
 	if (mtrr)
 		mtrr_add(video_base, video_size, MTRR_TYPE_WRCOMB, 1);
diff -u --recursive --new-file v2.3.36/linux/drivers/video/vga.h linux/drivers/video/vga.h
--- v2.3.36/linux/drivers/video/vga.h	Thu Aug 26 13:05:40 1999
+++ linux/drivers/video/vga.h	Thu Jan  6 10:23:46 2000
@@ -1,7 +1,7 @@
 /*
  * linux/include/video/vga.h -- standard VGA chipset interaction
  *
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
  * 
  * Copyright history from vga16fb.c:
  *	Copyright 1999 Ben Pfaff and Petr Vandrovec
diff -u --recursive --new-file v2.3.36/linux/drivers/video/vga16fb.c linux/drivers/video/vga16fb.c
--- v2.3.36/linux/drivers/video/vga16fb.c	Thu Aug 26 13:05:40 1999
+++ linux/drivers/video/vga16fb.c	Thu Jan  6 10:30:52 2000
@@ -924,8 +924,7 @@
 
 	printk(KERN_DEBUG "vga16fb: initializing\n");
 
-	if (!__request_region(&iomem_resource, VGA_FB_PHYS, VGA_FB_PHYS_LEN,
-			      "vga16fb")) {
+	if (!request_mem_region(VGA_FB_PHYS, VGA_FB_PHYS_LEN, "vga16fb")) {
 		printk (KERN_ERR "vga16fb: unable to reserve VGA memory, exiting\n");
 		return -1;
 	}
@@ -951,7 +950,7 @@
 
 	/* note - does not cause failure, b/c vgacon probably still owns this 
 	 * region (FIXME) */
-	if (__request_region(&ioport_resource, 0x3C0, 32, "vga16fb"))
+	if (request_region(0x3C0, 32, "vga16fb"))
 		release_io_ports = 1;
 
 	disp.var = vga16fb_defined;
@@ -994,9 +993,9 @@
 {
     unregister_framebuffer(&vga16fb.fb_info);
     iounmap(vga16fb.video_vbase);
-    __release_region(&iomem_resource, VGA_FB_PHYS, VGA_FB_PHYS_LEN);
+    release_mem_region(VGA_FB_PHYS, VGA_FB_PHYS_LEN);
     if (release_io_ports)
-    	__release_region(&ioport_resource, 0x3c0, 32);
+    	release_region(0x3c0, 32);
 }
 
 #endif
diff -u --recursive --new-file v2.3.36/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.3.36/linux/fs/block_dev.c	Tue Jun 22 10:45:40 1999
+++ linux/fs/block_dev.c	Thu Jan  6 10:14:36 2000
@@ -7,6 +7,8 @@
 #include <linux/mm.h>
 #include <linux/locks.h>
 #include <linux/fcntl.h>
+#include <linux/malloc.h>
+#include <linux/kmod.h>
 
 #include <asm/uaccess.h>
 
@@ -299,3 +301,351 @@
 {
 	return fsync_dev(dentry->d_inode->i_rdev);
 }
+
+/*
+ * bdev cache handling - shamelessly stolen from inode.c
+ * We use smaller hashtable, though.
+ */
+
+#define HASH_BITS	6
+#define HASH_SIZE	(1UL << HASH_BITS)
+#define HASH_MASK	(HASH_SIZE-1)
+static struct list_head bdev_hashtable[HASH_SIZE];
+static spinlock_t bdev_lock = SPIN_LOCK_UNLOCKED;
+static kmem_cache_t * bdev_cachep;
+
+#define alloc_bdev() \
+	 ((struct block_device *) kmem_cache_alloc(bdev_cachep, SLAB_KERNEL))
+#define destroy_bdev(bdev) kmem_cache_free(bdev_cachep, (bdev))
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct block_device * bdev = (struct block_device *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+	{
+		memset(bdev, 0, sizeof(*bdev));
+		sema_init(&bdev->bd_sem, 1);
+	}
+}
+
+void bdev_init(void)
+{
+	int i;
+	struct list_head *head = bdev_hashtable;
+
+	i = HASH_SIZE;
+	do {
+		INIT_LIST_HEAD(head);
+		head++;
+		i--;
+	} while (i);
+
+	bdev_cachep = kmem_cache_create("bdev_cache",
+					 sizeof(struct block_device),
+					 0, SLAB_HWCACHE_ALIGN, init_once,
+					 NULL);
+	if (!bdev_cachep)
+		panic("cannot create bdev slab cache");
+}
+
+/*
+ * Most likely _very_ bad one - but then it's hardly critical for small
+ * /dev and can be fixed when somebody will need really large one.
+ */
+static inline unsigned long hash(dev_t dev)
+{
+	unsigned long tmp = dev;
+	tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
+	return tmp & HASH_MASK;
+}
+
+static struct block_device *bdfind(dev_t dev, struct list_head *head)
+{
+	struct list_head *p;
+	struct block_device *bdev;
+	for (p=head->next; p!=head; p=p->next) {
+		bdev = list_entry(p, struct block_device, bd_hash);
+		if (bdev->bd_dev != dev)
+			continue;
+		atomic_inc(&bdev->bd_count);
+		return bdev;
+	}
+	return NULL;
+}
+
+struct block_device *bdget(dev_t dev)
+{
+	struct list_head * head = bdev_hashtable + hash(dev);
+	struct block_device *bdev, *new_bdev;
+	spin_lock(&bdev_lock);
+	bdev = bdfind(dev, head);
+	spin_unlock(&bdev_lock);
+	if (bdev)
+		return bdev;
+	new_bdev = alloc_bdev();
+	if (!new_bdev)
+		return NULL;
+	atomic_set(&new_bdev->bd_count,1);
+	new_bdev->bd_dev = dev;
+	spin_lock(&bdev_lock);
+	bdev = bdfind(dev, head);
+	if (!bdev) {
+		list_add(&new_bdev->bd_hash, head);
+		spin_unlock(&bdev_lock);
+		return new_bdev;
+	}
+	spin_unlock(&bdev_lock);
+	destroy_bdev(new_bdev);
+	return bdev;
+}
+
+void bdput(struct block_device *bdev)
+{
+	if (atomic_dec_and_test(&bdev->bd_count)) {
+		spin_lock(&bdev_lock);
+		if (atomic_read(&bdev->bd_openers))
+			BUG();
+		list_del(&bdev->bd_hash);
+		spin_unlock(&bdev_lock);
+		destroy_bdev(bdev);
+	}
+}
+
+static struct {
+	const char *name;
+	struct file_operations *bdops;
+} blkdevs[MAX_BLKDEV] = {
+	{ NULL, NULL },
+};
+
+int get_blkdev_list(char * p)
+{
+	int i;
+	int len;
+
+	len = sprintf(p, "\nBlock devices:\n");
+	for (i = 0; i < MAX_BLKDEV ; i++) {
+		if (blkdevs[i].bdops) {
+			len += sprintf(p+len, "%3d %s\n", i, blkdevs[i].name);
+		}
+	}
+	return len;
+}
+
+/*
+	Return the function table of a device.
+	Load the driver if needed.
+*/
+struct file_operations * get_blkfops(unsigned int major)
+{
+	const struct file_operations *ret = NULL;
+
+	/* major 0 is used for non-device mounts */
+	if (major && major < MAX_BLKDEV) {
+#ifdef CONFIG_KMOD
+		if (!blkdevs[major].bdops) {
+			char name[20];
+			sprintf(name, "block-major-%d", major);
+			request_module(name);
+		}
+#endif
+		ret = blkdevs[major].bdops;
+	}
+	return ret;
+}
+
+int register_blkdev(unsigned int major, const char * name, struct file_operations *bdops)
+{
+	if (major == 0) {
+		for (major = MAX_BLKDEV-1; major > 0; major--) {
+			if (blkdevs[major].bdops == NULL) {
+				blkdevs[major].name = name;
+				blkdevs[major].bdops = bdops;
+				return major;
+			}
+		}
+		return -EBUSY;
+	}
+	if (major >= MAX_BLKDEV)
+		return -EINVAL;
+	if (blkdevs[major].bdops && blkdevs[major].bdops != bdops)
+		return -EBUSY;
+	blkdevs[major].name = name;
+	blkdevs[major].bdops = bdops;
+	return 0;
+}
+
+int unregister_blkdev(unsigned int major, const char * name)
+{
+	if (major >= MAX_BLKDEV)
+		return -EINVAL;
+	if (!blkdevs[major].bdops)
+		return -EINVAL;
+	if (strcmp(blkdevs[major].name, name))
+		return -EINVAL;
+	blkdevs[major].name = NULL;
+	blkdevs[major].bdops = NULL;
+	return 0;
+}
+
+/*
+ * This routine checks whether a removable media has been changed,
+ * and invalidates all buffer-cache-entries in that case. This
+ * is a relatively slow routine, so we have to try to minimize using
+ * it. Thus it is called only upon a 'mount' or 'open'. This
+ * is the best way of combining speed and utility, I think.
+ * People changing diskettes in the middle of an operation deserve
+ * to lose :-)
+ */
+int check_disk_change(kdev_t dev)
+{
+	int i;
+	const struct file_operations * bdops;
+	struct super_block * sb;
+
+	i = MAJOR(dev);
+	if (i >= MAX_BLKDEV || (bdops = blkdevs[i].bdops) == NULL)
+		return 0;
+	if (bdops->check_media_change == NULL)
+		return 0;
+	if (!bdops->check_media_change(dev))
+		return 0;
+
+	printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
+		bdevname(dev));
+
+	sb = get_super(dev);
+	if (sb && invalidate_inodes(sb))
+		printk("VFS: busy inodes on changed media.\n");
+
+	invalidate_buffers(dev);
+
+	if (bdops->revalidate)
+		bdops->revalidate(dev);
+	return 1;
+}
+
+int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
+{
+	kdev_t rdev = to_kdev_t(bdev->bd_dev);
+	struct file_operations *fops = get_blkfops(MAJOR(rdev));
+	struct inode inode_fake;
+	int res;
+	mm_segment_t old_fs = get_fs();
+
+	if (!fops || !fops->ioctl)
+		return -EINVAL;
+	inode_fake.i_rdev=rdev;
+	init_waitqueue_head(&inode_fake.i_wait);
+	set_fs(KERNEL_DS);
+	res = fops->ioctl(&inode_fake, NULL, cmd, arg);
+	set_fs(old_fs);
+	return res;
+}
+
+int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind)
+{
+	int ret = -ENODEV;
+	kdev_t rdev = to_kdev_t(bdev->bd_dev); /* this should become bdev */
+	struct file_operations *fops = get_blkfops(MAJOR(rdev));
+	down(&bdev->bd_sem);
+	if (fops) {
+		/*
+		 * This crockload is due to bad choice of ->open() type.
+		 * It will go away.
+		 */
+		struct file fake_file = {};
+		struct dentry fake_dentry = {};
+		struct inode *fake_inode = get_empty_inode();
+		ret = -ENOMEM;
+		if (fake_inode) {
+			fake_file.f_mode = mode;
+			fake_file.f_flags = flags;
+			fake_file.f_dentry = &fake_dentry;
+			fake_dentry.d_inode = fake_inode;
+			fake_inode->i_rdev = rdev;
+			ret = 0;
+			if (fops->open)
+				ret = fops->open(fake_inode, &fake_file);
+			if (!ret)
+				atomic_inc(&bdev->bd_openers);
+			iput(fake_inode);
+		}
+	}
+	up(&bdev->bd_sem);
+	return ret;
+}
+
+int blkdev_put(struct block_device *bdev, int kind)
+{
+	int ret = 0;
+	kdev_t rdev = to_kdev_t(bdev->bd_dev); /* this should become bdev */
+	struct file_operations *fops = get_blkfops(MAJOR(rdev));
+	down(&bdev->bd_sem);
+	/* syncing will go here */
+	if (atomic_dec_and_test(&bdev->bd_openers)) {
+		/* invalidating buffers will go here */
+	}
+	if (fops->release) {
+		struct inode * fake_inode = get_empty_inode();
+		ret = -ENOMEM;
+		if (fake_inode) {
+			fake_inode->i_rdev = rdev;
+			ret = fops->release(fake_inode, NULL);
+			iput(fake_inode);
+		}
+	}
+	up(&bdev->bd_sem);
+	return ret;
+}
+
+char * bdevname(kdev_t dev)
+{
+	static char buffer[32];
+	const char * name = blkdevs[MAJOR(dev)].name;
+
+	if (!name)
+		name = "unknown-block";
+
+	sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
+	return buffer;
+}
+
+/*
+ * Called every time a block special file is opened
+ */
+int blkdev_open(struct inode * inode, struct file * filp)
+{
+	int ret = -ENODEV;
+	filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
+	if (filp->f_op != NULL){
+		ret = 0;
+		if (filp->f_op->open != NULL)
+			ret = filp->f_op->open(inode,filp);
+	}	
+	return ret;
+}	
+
+/*
+ * Dummy default file-operations: the only thing this does
+ * is contain the open that then fills in the correct operations
+ * depending on the special file...
+ */
+struct file_operations def_blk_fops = {
+	NULL,		/* lseek */
+	NULL,		/* read */
+	NULL,		/* write */
+	NULL,		/* readdir */
+	NULL,		/* poll */
+	NULL,		/* ioctl */
+	NULL,		/* mmap */
+	blkdev_open,	/* open */
+	NULL,		/* flush */
+	NULL,		/* release */
+};
+
+struct inode_operations blkdev_inode_operations = {
+	&def_blk_fops,		/* default file operations */
+};
diff -u --recursive --new-file v2.3.36/linux/fs/devices.c linux/fs/devices.c
--- v2.3.36/linux/fs/devices.c	Tue Jan  4 13:57:17 2000
+++ linux/fs/devices.c	Thu Jan  6 10:14:36 2000
@@ -37,9 +37,7 @@
 	{ NULL, NULL },
 };
 
-static struct device_struct blkdevs[MAX_BLKDEV] = {
-	{ NULL, NULL },
-};
+extern int get_blkdev_list(char *);
 
 int get_device_list(char * page)
 {
@@ -52,12 +50,7 @@
 			len += sprintf(page+len, "%3d %s\n", i, chrdevs[i].name);
 		}
 	}
-	len += sprintf(page+len, "\nBlock devices:\n");
-	for (i = 0; i < MAX_BLKDEV ; i++) {
-		if (blkdevs[i].fops) {
-			len += sprintf(page+len, "%3d %s\n", i, blkdevs[i].name);
-		}
-	}
+	len += get_blkdev_list(page+len);
 	return len;
 }
 
@@ -103,16 +96,6 @@
 	return ret;
 }
 
-
-/*
-	Return the function table of a device.
-	Load the driver if needed.
-*/
-struct file_operations * get_blkfops(unsigned int major)
-{
-	return get_fops (major,0,MAX_BLKDEV,"block-major-%d",blkdevs);
-}
-
 struct file_operations * get_chrfops(unsigned int major, unsigned int minor)
 {
 	return get_fops (major,minor,MAX_CHRDEV,"char-major-%d",chrdevs);
@@ -139,27 +122,6 @@
 	return 0;
 }
 
-int register_blkdev(unsigned int major, const char * name, struct file_operations *fops)
-{
-	if (major == 0) {
-		for (major = MAX_BLKDEV-1; major > 0; major--) {
-			if (blkdevs[major].fops == NULL) {
-				blkdevs[major].name = name;
-				blkdevs[major].fops = fops;
-				return major;
-			}
-		}
-		return -EBUSY;
-	}
-	if (major >= MAX_BLKDEV)
-		return -EINVAL;
-	if (blkdevs[major].fops && blkdevs[major].fops != fops)
-		return -EBUSY;
-	blkdevs[major].name = name;
-	blkdevs[major].fops = fops;
-	return 0;
-}
-
 int unregister_chrdev(unsigned int major, const char * name)
 {
 	if (major >= MAX_CHRDEV)
@@ -173,119 +135,6 @@
 	return 0;
 }
 
-int unregister_blkdev(unsigned int major, const char * name)
-{
-	if (major >= MAX_BLKDEV)
-		return -EINVAL;
-	if (!blkdevs[major].fops)
-		return -EINVAL;
-	if (strcmp(blkdevs[major].name, name))
-		return -EINVAL;
-	blkdevs[major].name = NULL;
-	blkdevs[major].fops = NULL;
-	return 0;
-}
-
-/*
- * This routine checks whether a removable media has been changed,
- * and invalidates all buffer-cache-entries in that case. This
- * is a relatively slow routine, so we have to try to minimize using
- * it. Thus it is called only upon a 'mount' or 'open'. This
- * is the best way of combining speed and utility, I think.
- * People changing diskettes in the middle of an operation deserve
- * to lose :-)
- */
-int check_disk_change(kdev_t dev)
-{
-	int i;
-	struct file_operations * fops;
-	struct super_block * sb;
-
-	i = MAJOR(dev);
-	if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
-		return 0;
-	if (fops->check_media_change == NULL)
-		return 0;
-	if (!fops->check_media_change(dev))
-		return 0;
-
-	printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
-		bdevname(dev));
-
-	sb = get_super(dev);
-	if (sb && invalidate_inodes(sb))
-		printk("VFS: busy inodes on changed media.\n");
-
-	invalidate_buffers(dev);
-
-	if (fops->revalidate)
-		fops->revalidate(dev);
-	return 1;
-}
-
-/*
- * Called every time a block special file is opened
- */
-int blkdev_open(struct inode * inode, struct file * filp)
-{
-	int ret = -ENODEV;
-	filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
-	if (filp->f_op != NULL){
-		ret = 0;
-		if (filp->f_op->open != NULL)
-			ret = filp->f_op->open(inode,filp);
-	}	
-	return ret;
-}	
-
-int blkdev_release(struct inode * inode)
-{
-	struct file_operations *fops = get_blkfops(MAJOR(inode->i_rdev));
-	if (fops && fops->release)
-		return fops->release(inode,NULL);
-	return 0;
-}
-
-
-/*
- * Dummy default file-operations: the only thing this does
- * is contain the open that then fills in the correct operations
- * depending on the special file...
- */
-struct file_operations def_blk_fops = {
-	NULL,		/* lseek */
-	NULL,		/* read */
-	NULL,		/* write */
-	NULL,		/* readdir */
-	NULL,		/* poll */
-	NULL,		/* ioctl */
-	NULL,		/* mmap */
-	blkdev_open,	/* open */
-	NULL,		/* flush */
-	NULL,		/* release */
-};
-
-static struct inode_operations blkdev_inode_operations = {
-	&def_blk_fops,		/* default file operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow_link */
-	NULL,			/* get_block */
-	NULL,			/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* truncate */
-	NULL,			/* permission */
-	NULL			/* revalidate */
-};
-
 /*
  * Called every time a character special file is opened
  */
@@ -307,38 +156,12 @@
  * is contain the open that then fills in the correct operations
  * depending on the special file...
  */
-struct file_operations def_chr_fops = {
-	NULL,		/* lseek */
-	NULL,		/* read */
-	NULL,		/* write */
-	NULL,		/* readdir */
-	NULL,		/* poll */
-	NULL,		/* ioctl */
-	NULL,		/* mmap */
-	chrdev_open,	/* open */
-	NULL,		/* flush */
-	NULL,		/* release */
+static struct file_operations def_chr_fops = {
+	open:	chrdev_open
 };
 
 static struct inode_operations chrdev_inode_operations = {
-	&def_chr_fops,		/* default file operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow_link */
-	NULL,			/* get_block */
-	NULL,			/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* truncate */
-	NULL,			/* permission */
-	NULL			/* revalidate */
+	&def_chr_fops		/* default file operations */
 };
 
 /*
@@ -352,18 +175,6 @@
 	return buffer;
 }
 
-char * bdevname(kdev_t dev)
-{
-	static char buffer[32];
-	const char * name = blkdevs[MAJOR(dev)].name;
-
-	if (!name)
-		name = "unknown-block";
-
-	sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
-	return buffer;
-}
-
 char * cdevname(kdev_t dev)
 {
 	static char buffer[32];
@@ -385,8 +196,9 @@
 	} else if (S_ISBLK(mode)) {
 		inode->i_op = &blkdev_inode_operations;
 		inode->i_rdev = to_kdev_t(rdev);
+		inode->i_bdev = bdget(rdev);
 	} else if (S_ISFIFO(mode))
-		init_fifo(inode);
+		inode->i_op = &fifo_inode_operations;
 	else if (S_ISSOCK(mode))
 		;
 	else
diff -u --recursive --new-file v2.3.36/linux/fs/fifo.c linux/fs/fifo.c
--- v2.3.36/linux/fs/fifo.c	Tue Dec  7 09:32:47 1999
+++ linux/fs/fifo.c	Thu Jan  6 10:14:36 2000
@@ -170,11 +170,3 @@
 struct inode_operations fifo_inode_operations = {
 	&def_fifo_fops,		/* default file operations */
 };
-
-
-/* Goner. Filesystems do not use it anymore. */
-
-void init_fifo(struct inode * inode)
-{
-	inode->i_op = &fifo_inode_operations;
-}
diff -u --recursive --new-file v2.3.36/linux/fs/inode.c linux/fs/inode.c
--- v2.3.36/linux/fs/inode.c	Tue Nov 23 22:42:21 1999
+++ linux/fs/inode.c	Thu Jan  6 10:14:36 2000
@@ -257,7 +257,10 @@
 		DQUOT_DROP(inode);
 	if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->clear_inode)
 		inode->i_sb->s_op->clear_inode(inode);
-
+	if (inode->i_bdev) {
+		bdput(inode->i_bdev);
+		inode->i_bdev = NULL;
+	}
 	inode->i_state = 0;
 }
 
@@ -472,6 +475,7 @@
 	inode->i_generation = 0;
 	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
 	inode->i_pipe = NULL;
+	inode->i_bdev = NULL;
 }
 
 /*
diff -u --recursive --new-file v2.3.36/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.3.36/linux/fs/isofs/inode.c	Mon Dec 20 18:48:22 1999
+++ linux/fs/isofs/inode.c	Thu Jan  6 10:14:36 2000
@@ -425,71 +425,54 @@
  */
 #define WE_OBEY_THE_WRITTEN_STANDARDS 1
 
-static unsigned int isofs_get_last_session(kdev_t dev,s32 session )
+static unsigned int isofs_get_last_session(struct super_block *sb,s32 session )
 {
-  struct cdrom_multisession ms_info;
-  unsigned int vol_desc_start;
-  struct inode inode_fake;
-  struct file_operations *fops;
-  extern struct file_operations * get_blkfops(unsigned int);
-  int i;
-
-  vol_desc_start=0;
-  fops = get_blkfops(MAJOR(dev));
-  if (fops && fops->ioctl)
-    {
-      /* Whoops.  We must save the old FS, since otherwise
-       * we would destroy the kernels idea about FS on root
-       * mount in read_super... [chexum]
-       */
-      mm_segment_t old_fs=get_fs();
-      inode_fake.i_rdev=dev;
-      init_waitqueue_head(&inode_fake.i_wait);
-      ms_info.addr_format=CDROM_LBA;
-      /* If a minor device was explicitly opened, set session to the
-       * minor number. For instance, if /dev/hdc1 is mounted, session
-       * 1 on the CD-ROM is selected. CD_PART_MAX gives access to
-       * a max of 64 sessions on IDE. SCSI drives must still use
-       * the session option to mount.
-       */
-      if ((MINOR(dev) % CD_PART_MAX) && (MAJOR(dev) != SCSI_CDROM_MAJOR))
+	struct cdrom_multisession ms_info;
+	unsigned int vol_desc_start;
+	struct block_device *bdev = sb->s_bdev;
+	kdev_t dev = sb->s_dev;
+	int i;
+
+	vol_desc_start=0;
+	ms_info.addr_format=CDROM_LBA;
+	/* If a minor device was explicitly opened, set session to the
+	 * minor number. For instance, if /dev/hdc1 is mounted, session
+	 * 1 on the CD-ROM is selected. CD_PART_MAX gives access to
+	 * a max of 64 sessions on IDE. SCSI drives must still use
+	 * the session option to mount.
+	 */
+	if ((MINOR(dev) % CD_PART_MAX) && (MAJOR(dev) != SCSI_CDROM_MAJOR))
 		session = MINOR(dev) % CD_PART_MAX;
-      set_fs(KERNEL_DS);
-      if(session >= 0 && session <= 99) {
-	      struct cdrom_tocentry Te;
-	      Te.cdte_track=session;
-	      Te.cdte_format=CDROM_LBA;
-	      i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
-				       NULL,
-				       CDROMREADTOCENTRY,
-				       (unsigned long) &Te);
-	      set_fs(old_fs);
-	      if(!i) printk(KERN_ERR"Session %d start %d type %d\n",session,Te.cdte_addr.lba,Te.cdte_ctrl&CDROM_DATA_TRACK);
-	      if(i || (Te.cdte_ctrl&CDROM_DATA_TRACK) != 4)
-			printk(KERN_ERR"Invalid session number or type of track\n");
-		else return Te.cdte_addr.lba;
-      }
-      i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
-				       NULL,
-				       CDROMMULTISESSION,
-				       (unsigned long) &ms_info);
-      set_fs(old_fs);
-      if(session > 0) printk(KERN_ERR"Invalid session number\n");
+	if(session >= 0 && session <= 99) {
+		struct cdrom_tocentry Te;
+		Te.cdte_track=session;
+		Te.cdte_format=CDROM_LBA;
+		i = ioctl_by_bdev(bdev, CDROMREADTOCENTRY, (unsigned long) &Te);
+		if (!i) {
+			printk(KERN_DEBUG "Session %d start %d type %d\n",
+			       session, Te.cdte_addr.lba,
+			       Te.cdte_ctrl&CDROM_DATA_TRACK);
+			if ((Te.cdte_ctrl&CDROM_DATA_TRACK) == 4)
+				return Te.cdte_addr.lba;
+		}
+			
+		printk(KERN_ERR "Invalid session number or type of track\n");
+	}
+	i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
+	if(session > 0) printk(KERN_ERR "Invalid session number\n");
 #if 0
-      printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
-      if (i==0)
-	{
-	  printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no");
-	  printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
+	printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
+	if (i==0) {
+		printk("isofs.inode: XA disk: %s\n",ms_info.xa_flag?"yes":"no");
+		printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
 	}
 #endif
-      if (i==0)
+	if (i==0)
 #if WE_OBEY_THE_WRITTEN_STANDARDS
         if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
 #endif
-          vol_desc_start=ms_info.addr.lba;
-    }
-  return vol_desc_start;
+		vol_desc_start=ms_info.addr.lba;
+	return vol_desc_start;
 }
 
 /*
@@ -569,7 +552,7 @@
 	s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */
 
 	vol_desc_start = (opt.sbsector != -1) ?
-		opt.sbsector : isofs_get_last_session(dev,opt.session);
+		opt.sbsector : isofs_get_last_session(s,opt.session);
 
   	for (iso_blknum = vol_desc_start+16;
              iso_blknum < vol_desc_start+100; iso_blknum++)
diff -u --recursive --new-file v2.3.36/linux/fs/super.c linux/fs/super.c
--- v2.3.36/linux/fs/super.c	Tue Jan  4 13:57:18 2000
+++ linux/fs/super.c	Thu Jan  6 10:14:36 2000
@@ -45,7 +45,6 @@
 static DECLARE_MUTEX(mount_sem);
 
 extern void wait_for_keypress(void);
-extern struct file_operations * get_blkfops(unsigned int major);
 
 extern int root_mountflags;
 
@@ -530,7 +529,8 @@
 	return s;
 }
 
-static struct super_block * read_super(kdev_t dev,const char *name,int flags,
+static struct super_block * read_super(kdev_t dev, struct block_device *bdev,
+				       const char *name, int flags,
 				       void *data, int silent)
 {
 	struct super_block * s;
@@ -541,7 +541,7 @@
 	check_disk_change(dev);
 	s = get_super(dev);
 	if (s)
-		goto out;
+		goto found;	/* ought to set ->s_bdev */
 
 	type = get_fs_type(name);
 	if (!type) {
@@ -553,23 +553,30 @@
 	if (!s)
 		goto out;
 	s->s_dev = dev;
+	s->s_bdev = bdev;
 	s->s_flags = flags;
 	s->s_dirt = 0;
 	sema_init(&s->s_vfs_rename_sem,1);
 	/* N.B. Should lock superblock now ... */
 	if (!type->read_super(s, data, silent))
 		goto out_fail;
-	s->s_dev = dev; /* N.B. why do this again?? */
 	s->s_type = type;
+bd_get:
+	/* tell bdcache that we are going to keep this one */
+	if (bdev)
+		atomic_inc(&bdev->bd_count);
 out:
 	return s;
 
-	/* N.B. s_dev should be cleared in type->read_super */
 out_fail:
 	s->s_dev = 0;
+	s->s_bdev = 0;
 out_null:
 	s = NULL;
 	goto out;
+found:
+	s->s_bdev = bdev;
+	goto bd_get;
 }
 
 /*
@@ -632,9 +639,10 @@
 	dentry->d_covers = covered;
 }
 
-static int do_umount(kdev_t dev, int unmount_root, int flags)
+static struct block_device *do_umount(kdev_t dev, int unmount_root, int flags)
 {
 	struct super_block * sb;
+	struct block_device *bdev;
 	int retval;
 	
 	retval = -ENOENT;
@@ -681,7 +689,7 @@
 		retval = 0;
 		if (!(sb->s_flags & MS_RDONLY))
 			retval = do_remount_sb(sb, MS_RDONLY, 0);
-		return retval;
+		return ERR_PTR(retval);
 	}
 
 	retval = d_umount(sb);
@@ -706,43 +714,44 @@
 	}
 
 	sb->s_dev = 0;		/* Free the superblock */
+	bdev = sb->s_bdev;
+	sb->s_bdev = NULL;
 	unlock_super(sb);
 
 	remove_vfsmnt(dev);
+
+	return bdev;
+
 out:
-	return retval;
+	return ERR_PTR(retval);
 }
 
 static int umount_dev(kdev_t dev, int flags)
 {
 	int retval;
-	struct inode * inode = get_empty_inode();
-
-	retval = -ENOMEM;
-	if (!inode)
-		goto out;
+	struct block_device *bdev;
 
-	inode->i_rdev = dev;
 	retval = -ENXIO;
 	if (MAJOR(dev) >= MAX_BLKDEV)
-		goto out_iput;
+		goto out;
 
 	fsync_dev(dev);
 
 	down(&mount_sem);
 
-	retval = do_umount(dev, 0, flags);
-	if (!retval) {
-		fsync_dev(dev);
-		if (dev != ROOT_DEV) {
-			blkdev_release(inode);
+	bdev = do_umount(dev, 0, flags);
+	if (IS_ERR(bdev))
+		retval = PTR_ERR(bdev);
+	else {
+		retval = 0;
+		if (bdev) {
+			blkdev_put(bdev, BDEV_FS);
+			bdput(bdev);
+		} else {
 			put_unnamed_dev(dev);
 		}
 	}
-
 	up(&mount_sem);
-out_iput:
-	iput(inode);
 out:
 	return retval;
 }
@@ -751,12 +760,6 @@
  * Now umount can handle mount points as well as block devices.
  * This is important for filesystems which use unnamed block devices.
  *
- * There is a little kludge here with the dummy_inode.  The current
- * vfs release functions only use the r_dev field in the inode so
- * we give them the info they need without using a real inode.
- * If any other fields are ever needed by any block device release
- * functions, they should be faked here.  -- jrs
- *
  * We now support a flag for forced unmount like the other 'big iron'
  * unixes. Our API is identical to OSF/1 to avoid making a mess of AMD
  */
@@ -840,14 +843,29 @@
  * Anyone using this new feature must know what he/she is doing.
  */
 
-int do_mount(kdev_t dev, const char * dev_name, const char * dir_name,
-	     const char * type, int flags, void * data)
+int do_mount(struct block_device *bdev, const char *dev_name,
+	     const char *dir_name, const char * type, int flags, void * data)
 {
+	kdev_t dev;
 	struct dentry * dir_d;
 	struct super_block * sb;
 	struct vfsmount *vfsmnt;
 	int error;
 
+	if (bdev) {
+		mode_t mode = FMODE_READ; /* we always need it ;-) */
+		if (!(flags & MS_RDONLY))
+			mode |= FMODE_WRITE;
+		dev = to_kdev_t(bdev->bd_dev);
+		error = blkdev_get(bdev, mode, 0, BDEV_FS);
+		if (error)
+			return error;
+	} else {
+		dev = get_unnamed_dev();
+		if (!dev)
+			return -EMFILE;	/* huh? */
+	}
+
 	error = -EACCES;
 	if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
 		goto out;
@@ -874,7 +892,7 @@
 	 * read_super just does a get_super().
 	 */
 	error = -EINVAL;
-	sb = read_super(dev, type, flags, data, 0);
+	sb = read_super(dev, bdev, type, flags, data, 0);
 	if (!sb)
 		goto dput_and_out;
 
@@ -884,20 +902,30 @@
 	 */
 	error = -EBUSY;
 	if (!fs_may_mount(dev))
-		goto dput_and_out;
+		goto bdput_and_out;
 
 	error = -ENOMEM;
 	vfsmnt = add_vfsmnt(sb, dev_name, dir_name);
 	if (vfsmnt) {
 		d_mount(dget(dir_d), sb->s_root);
-		error = 0;
+		dput(dir_d);
+		up(&mount_sem);
+		return 0;
 	}
 
+bdput_and_out:
+	sb->s_bdev = NULL;
+	if (bdev)
+		bdput(bdev);
 dput_and_out:
 	dput(dir_d);
 	up(&mount_sem);
 out:
-	return error;	
+	if (bdev)
+		blkdev_put(bdev, BDEV_FS);
+	else
+		put_unnamed_dev(dev);
+	return error;
 }
 
 
@@ -1017,11 +1045,10 @@
 	struct file_system_type * fstype;
 	struct dentry * dentry = NULL;
 	struct inode * inode = NULL;
-	kdev_t dev;
+	struct block_device *bdev = NULL;
 	int retval;
 	unsigned long flags = 0;
 	unsigned long page = 0;
-	struct file dummy;	/* allows read-write or read-only flag */
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -1047,7 +1074,6 @@
 	if (!fstype)		
 		goto out;
 
-	memset(&dummy, 0, sizeof(dummy));
 	if (fstype->fs_flags & FS_REQUIRES_DEV) {
 		dentry = namei(dev_name);
 		retval = PTR_ERR(dentry);
@@ -1063,28 +1089,7 @@
 		if (IS_NODEV(inode))
 			goto dput_and_out;
 
-		dev = inode->i_rdev;
-		retval = -ENXIO;
-		if (MAJOR(dev) >= MAX_BLKDEV)
-			goto dput_and_out;
-
-		retval = -ENOTBLK;
-		dummy.f_op = get_blkfops(MAJOR(dev));
-		if (!dummy.f_op)
-			goto dput_and_out;
-
-		if (dummy.f_op->open) {
-			dummy.f_dentry = dentry;
-			dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
-			retval = dummy.f_op->open(inode, &dummy);
-			if (retval)
-				goto dput_and_out;
-		}
-
-	} else {
-		retval = -EMFILE;
-		if (!(dev = get_unnamed_dev()))
-			goto out;
+		bdev = inode->i_bdev;
 	}
 
 	page = 0;
@@ -1092,27 +1097,17 @@
 		flags = new_flags & ~MS_MGC_MSK;
 		retval = copy_mount_options(data, &page);
 		if (retval < 0)
-			goto clean_up;
+			goto dput_and_out;
 	}
-	retval = do_mount(dev, dev_name, dir_name, fstype->name, flags,
+	retval = do_mount(bdev, dev_name, dir_name, fstype->name, flags,
 				(void *) page);
 	free_page(page);
-	if (retval)
-		goto clean_up;
 
 dput_and_out:
 	dput(dentry);
 out:
 	unlock_kernel();
 	return retval;
-
-clean_up:
-	if (dummy.f_op) {
-		if (dummy.f_op->release)
-			dummy.f_op->release(inode, NULL);
-	} else
-		put_unnamed_dev(dev);
-	goto dput_and_out;
 }
 
 void __init mount_root(void)
@@ -1120,8 +1115,8 @@
 	struct file_system_type * fs_type;
 	struct super_block * sb;
 	struct vfsmount *vfsmnt;
-	struct inode * d_inode = NULL;
-	struct file filp;
+	struct block_device *bdev = NULL;
+	mode_t mode;
 	int retval;
 
 #ifdef CONFIG_ROOT_NFS
@@ -1130,6 +1125,7 @@
 		if ((fs_type = get_fs_type("nfs"))) {
 			sb = get_empty_super(); /* "can't fail" */
 			sb->s_dev = get_unnamed_dev();
+			sb->s_bdev = NULL;
 			sb->s_flags = root_mountflags;
 			sema_init(&sb->s_vfs_rename_sem,1);
 			vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
@@ -1177,23 +1173,17 @@
 	}
 #endif
 
-	memset(&filp, 0, sizeof(filp));
-	d_inode = get_empty_inode();
-	if (!d_inode)
-		panic(__FUNCTION__ ": unable to allocate root inode");
-	d_inode->i_rdev = ROOT_DEV;
-	filp.f_dentry = NULL;
-	if ( root_mountflags & MS_RDONLY)
-		filp.f_mode = 1; /* read only */
-	else
-		filp.f_mode = 3; /* read write */
-	retval = blkdev_open(d_inode, &filp);
+	bdev = bdget(kdev_t_to_nr(ROOT_DEV));
+	if (!bdget)
+		panic(__FUNCTION__ ": unable to allocate root device");
+	mode = FMODE_READ;
+	if (!(root_mountflags & MS_RDONLY))
+		mode |= FMODE_WRITE;
+	retval = blkdev_get(bdev, mode, 0, BDEV_FS);
 	if (retval == -EROFS) {
 		root_mountflags |= MS_RDONLY;
-		filp.f_mode = 1;
-		retval = blkdev_open(d_inode, &filp);
+		retval = blkdev_get(bdev, FMODE_READ, 0, BDEV_FS);
 	}
-	iput(d_inode);
 	if (retval)
 	        /*
 		 * Allow the user to distinguish between failed open
@@ -1204,7 +1194,7 @@
 	else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
   		if (!(fs_type->fs_flags & FS_REQUIRES_DEV))
   			continue;
-  		sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
+  		sb = read_super(ROOT_DEV,bdev,fs_type->name,root_mountflags,NULL,1);
 		if (sb) {
 			sb->s_flags = root_mountflags;
 			current->fs->root = dget(sb->s_root);
@@ -1213,8 +1203,10 @@
 				fs_type->name,
 				(sb->s_flags & MS_RDONLY) ? " readonly" : "");
 			vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
-			if (vfsmnt)
+			if (vfsmnt) {
+				bdput(bdev); /* sb holds a reference */
 				return;
+			}
 			panic("VFS: add_vfsmnt failed for root fs");
 		}
 	}
@@ -1268,16 +1260,20 @@
 		error = -ENOTDIR;
 	}
 	if (error) {
-		int umount_error;
+		struct block_device *bdev;
 
 		printk(KERN_NOTICE "Trying to unmount old root ... ");
-		umount_error = do_umount(old_root_dev,1, 0);
-		if (!umount_error) {
+		bdev = do_umount(old_root_dev,1, 0);
+		if (!IS_ERR(bdev)) {
 			printk("okay\n");
 			invalidate_buffers(old_root_dev);
+			if (bdev) {
+				blkdev_put(bdev, BDEV_FS);
+				bdput(bdev);
+			}
 			return 0;
 		}
-		printk(KERN_ERR "error %d\n",umount_error);
+		printk(KERN_ERR "error %d\n",PTR_ERR(bdev));
 		return error;
 	}
 	remove_vfsmnt(old_root_dev);
diff -u --recursive --new-file v2.3.36/linux/fs/udf/inode.c linux/fs/udf/inode.c
--- v2.3.36/linux/fs/udf/inode.c	Tue Jan  4 13:57:18 2000
+++ linux/fs/udf/inode.c	Thu Jan  6 10:14:36 2000
@@ -1157,7 +1157,7 @@
 		}
 		case FILE_TYPE_FIFO:
 		{
-			init_special_inode(inode, inode->i_mode|S_FIFO, 0);
+			init_special_inode(inode, inode->i_mode | S_IFIFO, 0);
 			break;
 		}
 		case FILE_TYPE_SYMLINK:
diff -u --recursive --new-file v2.3.36/linux/fs/udf/lowlevel.c linux/fs/udf/lowlevel.c
--- v2.3.36/linux/fs/udf/lowlevel.c	Tue Nov 23 22:42:21 1999
+++ linux/fs/udf/lowlevel.c	Thu Jan  6 10:14:36 2000
@@ -38,60 +38,36 @@
 #include "udf_sb.h"
 
 unsigned int 
-udf_get_last_session(kdev_t dev)
+udf_get_last_session(struct super_block *sb)
 {
 	struct cdrom_multisession ms_info;
 	unsigned int vol_desc_start;
-	struct inode inode_fake;
-	extern struct file_operations * get_blkfops(unsigned int);
+	struct block_device *bdev = sb->s_bdev;
 	int i;
 
 	vol_desc_start=0;
-	if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
-	{
-		/* Whoops.  We must save the old FS, since otherwise
-		 * we would destroy the kernels idea about FS on root
-		 * mount in read_super... [chexum]
-		 */
-		mm_segment_t old_fs=get_fs();
-		inode_fake.i_rdev=dev;
-		ms_info.addr_format=CDROM_LBA;
-		set_fs(KERNEL_DS);
-		i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
-						NULL,
-						CDROMMULTISESSION,
-						(unsigned long) &ms_info);
-		set_fs(old_fs);
-
+	ms_info.addr_format=CDROM_LBA;
+	i=ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
 #define WE_OBEY_THE_WRITTEN_STANDARDS 1
-
-		if (i == 0)
-		{
-			udf_debug("XA disk: %s, vol_desc_start=%d\n",
-				(ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
+	if (i == 0) {
+		udf_debug("XA disk: %s, vol_desc_start=%d\n",
+			(ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
 #if WE_OBEY_THE_WRITTEN_STANDARDS
-			if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
+		if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
 #endif
-				vol_desc_start = ms_info.addr.lba;
-		}
-		else
-		{
-			udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i);
-		}
-	}
-	else
-	{
-		udf_debug("Device doesn't know how to ioctl?\n");
+			vol_desc_start = ms_info.addr.lba;
+	} else {
+		udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i);
 	}
 	return vol_desc_start;
 }
 
 unsigned int
-udf_get_last_block(kdev_t dev, int *flags)
+udf_get_last_block(struct super_block *sb, int *flags)
 {
 	extern int *blksize_size[];
-	struct inode inode_fake;
-	extern struct file_operations * get_blkfops(unsigned int);
+	kdev_t dev = sb->s_dev;
+	struct block_device *bdev = sb->s_bdev;
 	int ret;
 	unsigned long lblock;
 	unsigned int hbsize = get_hardblocksize(dev);
@@ -107,44 +83,20 @@
 	else if (hbsize > secsize)
 		div = hbsize / secsize;
 
-	if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
-	{
-      /* Whoops.  We must save the old FS, since otherwise
-       * we would destroy the kernels idea about FS on root
-       * mount in read_super... [chexum]
-       */
-		mm_segment_t old_fs=get_fs();
-		inode_fake.i_rdev=dev;
-		set_fs(KERNEL_DS);
-
-		lblock = 0;
-		ret = get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
-			NULL,
-			BLKGETSIZE,
-			(unsigned long) &lblock);
-
-		if (!ret && lblock != 0x7FFFFFFF) /* Hard Disk */
-		{
-			if (mult)
-				lblock *= mult;
-			else if (div)
-				lblock /= div;
-		}
-		else /* CDROM */
-		{
-			ret = get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
-				NULL,
-				CDROM_LAST_WRITTEN,
-				(unsigned long) &lblock);
-		}
-
-		set_fs(old_fs);
-		if (!ret && lblock)
-			return lblock - 1;
-	}
-	else
-	{
-		udf_debug("Device doesn't know how to ioctl?\n");
+	lblock = 0;
+	ret = ioctl_by_bdev(bdev, BLKGETSIZE, (unsigned long) &lblock);
+
+	if (!ret && lblock != 0x7FFFFFFF) {
+		/* Hard Disk */
+		if (mult)
+			lblock *= mult;
+		else if (div)
+			lblock /= div;
+	} else {
+		/* CDROM */
+		ret = ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock);
 	}
+	if (!ret && lblock)
+		return lblock - 1;
 	return 0;
 }
diff -u --recursive --new-file v2.3.36/linux/fs/udf/super.c linux/fs/udf/super.c
--- v2.3.36/linux/fs/udf/super.c	Tue Nov 23 22:42:21 1999
+++ linux/fs/udf/super.c	Thu Jan  6 10:14:36 2000
@@ -1335,14 +1335,14 @@
 		goto error_out;
 
 	if ( uopt.session == 0xFFFFFFFF )
-		UDF_SB_SESSION(sb) = udf_get_last_session(sb->s_dev);
+		UDF_SB_SESSION(sb) = udf_get_last_session(sb);
 	else
 		UDF_SB_SESSION(sb) = uopt.session;
 
 	udf_debug("Multi-session=%d\n", UDF_SB_SESSION(sb));
 
 	if ( uopt.lastblock == 0xFFFFFFFF )
-		UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb->s_dev, &(UDF_SB(sb)->s_flags));
+		UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb, &(UDF_SB(sb)->s_flags));
 	else
 		UDF_SB_LASTBLOCK(sb) = uopt.lastblock;
 
diff -u --recursive --new-file v2.3.36/linux/fs/udf/udfdecl.h linux/fs/udf/udfdecl.h
--- v2.3.36/linux/fs/udf/udfdecl.h	Tue Nov 23 22:42:21 1999
+++ linux/fs/udf/udfdecl.h	Thu Jan  6 10:14:36 2000
@@ -158,8 +158,8 @@
 extern void udf_release_data(struct buffer_head *);
 
 /* lowlevel.c */
-extern unsigned int udf_get_last_session(kdev_t);
-extern unsigned int udf_get_last_block(kdev_t, int *);
+extern unsigned int udf_get_last_session(struct super_block *);
+extern unsigned int udf_get_last_block(struct super_block *, int *);
 
 /* partition.c */
 extern Uint32 udf_get_pblock(struct super_block *, Uint32, Uint16, Uint32);
diff -u --recursive --new-file v2.3.36/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h
--- v2.3.36/linux/include/asm-i386/semaphore.h	Tue Dec  7 09:32:49 1999
+++ linux/include/asm-i386/semaphore.h	Thu Jan  6 11:42:19 2000
@@ -258,9 +258,9 @@
 }
 
 /* we use FASTCALL convention for the helpers */
-extern struct rw_semaphore *FASTCALL(down_read_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(down_write_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *sem));
+extern struct rw_semaphore *FASTCALL(__down_read_failed(struct rw_semaphore *sem));
+extern struct rw_semaphore *FASTCALL(__down_write_failed(struct rw_semaphore *sem));
+extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem));
 
 extern inline void down_read(struct rw_semaphore *sem)
 {
diff -u --recursive --new-file v2.3.36/linux/include/linux/acpi.h linux/include/linux/acpi.h
--- v2.3.36/linux/include/linux/acpi.h	Wed Dec 29 13:13:21 1999
+++ linux/include/linux/acpi.h	Thu Jan  6 11:43:17 2000
@@ -174,6 +174,8 @@
 	}
 }
 
+extern int acpi_active;
+
 #else /* CONFIG_ACPI */
 
 extern inline struct acpi_dev*
diff -u --recursive --new-file v2.3.36/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.36/linux/include/linux/fs.h	Tue Jan  4 13:57:21 2000
+++ linux/include/linux/fs.h	Thu Jan  6 11:42:19 2000
@@ -340,6 +340,16 @@
 	unsigned long		nrpages;
 };
 
+struct block_device {
+	struct list_head	bd_hash;
+	atomic_t		bd_count;
+/*	struct address_space	bd_data; */
+	dev_t			bd_dev;  /* not a kdev_t - it's a search key */
+	atomic_t		bd_openers;
+/*	struct bdev_operations *bd_op; */
+	struct semaphore	bd_sem;	/* open/close mutex */
+};
+
 struct inode {
 	struct list_head	i_hash;
 	struct list_head	i_list;
@@ -370,6 +380,7 @@
 	spinlock_t		i_shared_lock;
 	struct dquot		*i_dquot[MAXQUOTAS];
 	struct pipe_inode_info	*i_pipe;
+	struct block_device	*i_bdev;
 
 	unsigned long		i_state;
 
@@ -559,6 +570,8 @@
 	struct list_head	s_dirty;	/* dirty inodes */
 	struct list_head	s_files;
 
+	struct block_device	*s_bdev;
+
 	union {
 		struct minix_sb_info	minix_sb;
 		struct ext2_sb_info	ext2_sb;
@@ -743,12 +756,17 @@
 #define __getname()	((char *) __get_free_page(GFP_KERNEL))
 #define putname(name)	free_page((unsigned long)(name))
 
+enum {BDEV_FILE, BDEV_SWAP, BDEV_FS, BDEV_RAW};
 extern void kill_fasync(struct fasync_struct *, int, int);
 extern int register_blkdev(unsigned int, const char *, struct file_operations *);
 extern int unregister_blkdev(unsigned int, const char *);
+extern struct block_device *bdget(dev_t);
+extern void bdput(struct block_device *);
 extern int blkdev_open(struct inode *, struct file *);
-extern int blkdev_release (struct inode *);
 extern struct file_operations def_blk_fops;
+extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
+extern int blkdev_get(struct block_device *, mode_t, unsigned, int);
+extern int blkdev_put(struct block_device *, int);
 
 /* fs/devices.c */
 extern int register_chrdev(unsigned int, const char *, struct file_operations *);
@@ -760,8 +778,8 @@
 extern char * kdevname(kdev_t);
 extern void init_special_inode(struct inode *, umode_t, int);
 
-extern void init_fifo(struct inode *);
 extern struct inode_operations fifo_inode_operations;
+extern struct inode_operations blkdev_inode_operations;
 
 /* Invalid inode operations -- fs/bad_inode.c */
 extern void make_bad_inode(struct inode *);
diff -u --recursive --new-file v2.3.36/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.36/linux/include/linux/pci.h	Tue Jan  4 13:57:21 2000
+++ linux/include/linux/pci.h	Thu Jan  6 11:42:18 2000
@@ -283,6 +283,7 @@
 #include <linux/types.h>
 #include <linux/config.h>
 #include <linux/ioport.h>
+#include <linux/list.h>
 
 #include <asm/pci.h>
 
@@ -295,13 +296,10 @@
  * The pci_dev structure is used to describe both PCI and ISAPnP devices.
  */
 struct pci_dev {
-	int active;			/* device is active */
-	int ro;				/* Read/Only */
-
+	struct list_head global_list;	/* node in list of all PCI devices */
+	struct list_head bus_list;	/* node in per-bus list */
 	struct pci_bus	*bus;		/* bus this device is on */
 	struct pci_bus	*subordinate;	/* bus this device bridges to */
-	struct pci_dev	*sibling;	/* next device on this bus */
-	struct pci_dev	*next;		/* chain of all devices */
 
 	void		*sysdata;	/* hook for sys-specific extension */
 	struct proc_dir_entry *procent;	/* device entry in /proc/bus/pci */
@@ -332,12 +330,17 @@
 
 	char		name[48];	/* Device name */
 	char		slot_name[8];	/* Slot name */
+	int active;			/* device is active */
+	int ro;				/* Read/Only */
 
 	int (*prepare)(struct pci_dev *dev);
 	int (*activate)(struct pci_dev *dev);
 	int (*deactivate)(struct pci_dev *dev);
 };
 
+#define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)
+#define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list)
+
 /*
  *  For PCI devices, the region numbers are assigned this way:
  *
@@ -353,16 +356,14 @@
 #define PCI_REGION_FLAG_MASK 0x0f	/* These bits of resource flags tell us the PCI region flags */
 
 struct pci_bus {
+	struct list_head node;		/* node in list of buses */
 	struct pci_bus	*parent;	/* parent bus this bridge is on */
-	struct pci_bus	*children;	/* chain of P2P bridges on this bus */
-	struct pci_bus	*next;		/* chain of all PCI buses */
-	struct pci_ops	*ops;		/* configuration access functions */
-
+	struct list_head children;	/* list of child buses */
+	struct list_head devices;	/* list of devices on this bus */
 	struct pci_dev	*self;		/* bridge device as seen by parent */
-	struct pci_dev	*devices;	/* devices behind this bridge */
-	struct pci_dev	**last_dev_p;	/* where should next device be linked to */
 	struct resource	*resource[4];	/* address space routed to this bus */
 
+	struct pci_ops	*ops;		/* configuration access functions */
 	void		*sysdata;	/* hook for sys-specific extension */
 	struct proc_dir_entry *procdir;	/* directory entry in /proc/bus/pci */
 
@@ -381,8 +382,10 @@
 	unsigned char	pad1;
 };
 
-extern struct pci_bus	*pci_root;	/* root bus */
-extern struct pci_dev	*pci_devices;	/* list of all devices */
+#define pci_bus_b(n) list_entry(n, struct pci_bus, node)
+
+extern struct list_head pci_root_buses;	/* list of all known PCI buses */
+extern struct list_head pci_devices;	/* list of all devices */
 
 /*
  * Error values that may be returned by PCI functions.
@@ -458,6 +461,7 @@
 char *pci_class_name(u32 class);
 void pci_read_bridge_bases(struct pci_bus *child);
 struct resource *pci_find_parent_resource(struct pci_dev *dev, struct resource *res);
+int pci_setup_device(struct pci_dev * dev);
 
 /* Generic PCI functions exported to card drivers */
 
@@ -478,11 +482,15 @@
 int pci_write_config_word(struct pci_dev *dev, int where, u16 val);
 int pci_write_config_dword(struct pci_dev *dev, int where, u32 val);
 
-int pci_setup_device(struct pci_dev * dev);
 int pci_enable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
 int pci_set_power_state(struct pci_dev *dev, int state);
 int pci_assign_resource(struct pci_dev *dev, int i);
+
+#define __pcidev(entry)	list_entry(entry, struct pci_dev, global_list)
+
+#define pci_for_each_dev(dev) \
+	for(dev = __pcidev(pci_devices.next); dev != __pcidev(&pci_devices); dev = __pcidev(dev->global_list.next))
 
 /* Helper functions for low-level code (drivers/pci/setup.c) */
 
diff -u --recursive --new-file v2.3.36/linux/include/linux/random.h linux/include/linux/random.h
--- v2.3.36/linux/include/linux/random.h	Tue Aug 31 17:29:14 1999
+++ linux/include/linux/random.h	Thu Jan  6 10:14:36 2000
@@ -54,6 +54,7 @@
 extern void get_random_bytes(void *buf, int nbytes);
 void generate_random_uuid(unsigned char uuid_out[16]);
 
+extern __u32 secure_ip_id(__u32 daddr);
 extern __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
 					__u16 sport, __u16 dport);
 extern __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr,
@@ -64,6 +65,10 @@
 				  __u32 daddr, __u16 sport,
 				  __u16 dport, __u32 sseq,
 				  __u32 count, __u32 maxdiff);
+extern __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr,
+					  __u16 sport, __u16 dport);
+
+extern __u32 secure_ipv6_id(__u32 *daddr);
 
 #ifndef MODULE
 extern struct file_operations random_fops, urandom_fops;
diff -u --recursive --new-file v2.3.36/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
--- v2.3.36/linux/include/linux/rtnetlink.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/rtnetlink.h	Thu Jan  6 10:14:36 2000
@@ -249,6 +249,11 @@
 	__s32	rta_expires;
 	__u32	rta_error;
 	__u32	rta_used;
+
+#define RTNETLINK_HAVE_PEERINFO 1
+	__u32	rta_id;
+	__u32	rta_ts;
+	__u32	rta_tsage;
 };
 
 /* RTM_METRICS --- array of struct rtattr with types of RTAX_* */
diff -u --recursive --new-file v2.3.36/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.3.36/linux/include/linux/sysctl.h	Tue Dec  7 09:32:51 1999
+++ linux/include/linux/sysctl.h	Thu Jan  6 10:14:36 2000
@@ -245,6 +245,11 @@
 	NET_TCP_TW_RECYCLE=66,
 	NET_IPV4_ALWAYS_DEFRAG=67,
 	NET_IPV4_TCP_KEEPALIVE_INTVL=68,
+	NET_IPV4_INET_PEER_THRESHOLD=69,
+	NET_IPV4_INET_PEER_MINTTL=70,
+	NET_IPV4_INET_PEER_MAXTTL=71,
+	NET_IPV4_INET_PEER_GC_MINTIME=72,
+	NET_IPV4_INET_PEER_GC_MAXTIME=73
 };
 
 enum {
diff -u --recursive --new-file v2.3.36/linux/include/net/inetpeer.h linux/include/net/inetpeer.h
--- v2.3.36/linux/include/net/inetpeer.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/inetpeer.h	Thu Jan  6 11:43:38 2000
@@ -0,0 +1,66 @@
+/*
+ *		INETPEER - A storage for permanent information about peers
+ *
+ *  Version:	$Id: inetpeer.h,v 1.1 2000/01/06 00:41:51 davem Exp $
+ *
+ *  Authors:	Andrey V. Savochkin <saw@msu.ru>
+ */
+
+#ifndef _NET_INETPEER_H
+#define _NET_INETPEER_H
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+
+struct inet_peer
+{
+	struct inet_peer	*avl_left, *avl_right;
+	struct inet_peer	*unused_next, **unused_prevp;
+	atomic_t		refcnt;
+	unsigned long		dtime;		/* the time of last use of not
+						 * referenced entries */
+	__u32			v4daddr;	/* peer's address */
+	__u16			avl_height;
+	__u16			ip_id_count;	/* IP ID for the next packet */
+	__u32			tcp_ts;
+	unsigned long		tcp_ts_stamp;
+};
+
+void			inet_initpeers(void) __init;
+
+/* can be called with or without local BH being disabled */
+struct inet_peer	*inet_getpeer(__u32 daddr, int create);
+
+extern spinlock_t inet_peer_unused_lock;
+extern struct inet_peer *inet_peer_unused_head;
+extern struct inet_peer **inet_peer_unused_tailp;
+/* can be called from BH context or outside */
+extern inline void	inet_putpeer(struct inet_peer *p)
+{
+	spin_lock_bh(&inet_peer_unused_lock);
+	if (atomic_dec_and_test(&p->refcnt)) {
+		p->unused_prevp = inet_peer_unused_tailp;
+		p->unused_next = NULL;
+		*inet_peer_unused_tailp = p;
+		inet_peer_unused_tailp = &p->unused_next;
+		p->dtime = jiffies;
+	}
+	spin_unlock_bh(&inet_peer_unused_lock);
+}
+
+extern spinlock_t inet_peer_idlock;
+/* can be called with or without local BH being disabled */
+extern inline __u16	inet_getid(struct inet_peer *p)
+{
+	__u16 id;
+
+	spin_lock_bh(&inet_peer_idlock);
+	id = p->ip_id_count++;
+	spin_unlock_bh(&inet_peer_idlock);
+	return id;
+}
+
+#endif /* _NET_INETPEER_H */
diff -u --recursive --new-file v2.3.36/linux/include/net/ip.h linux/include/net/ip.h
--- v2.3.36/linux/include/net/ip.h	Tue Nov 23 22:42:21 1999
+++ linux/include/net/ip.h	Thu Jan  6 11:43:46 2000
@@ -96,7 +96,6 @@
 extern int		ip_fragment(struct sk_buff *skb, int (*out)(struct sk_buff*));
 extern int		ip_do_nat(struct sk_buff *skb);
 extern void		ip_send_check(struct iphdr *ip);
-extern int		ip_id_count;			  
 extern int		ip_queue_xmit(struct sk_buff *skb);
 extern void		ip_init(void);
 extern int		ip_build_xmit(struct sock *sk,
@@ -179,6 +178,16 @@
 	return (sk->protinfo.af_inet.pmtudisc == IP_PMTUDISC_DO ||
 		(sk->protinfo.af_inet.pmtudisc == IP_PMTUDISC_WANT &&
 		 !(dst->mxlock&(1<<RTAX_MTU))));
+}
+
+extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst);
+
+extern __inline__ void ip_select_ident(struct iphdr *iph, struct dst_entry *dst)
+{
+	if (iph->frag_off&__constant_htons(IP_DF))
+		iph->id = 0;
+	else
+		__ip_select_ident(iph, dst);
 }
 
 /*
diff -u --recursive --new-file v2.3.36/linux/include/net/route.h linux/include/net/route.h
--- v2.3.36/linux/include/net/route.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/route.h	Thu Jan  6 11:43:38 2000
@@ -25,6 +25,7 @@
 
 #include <linux/config.h>
 #include <net/dst.h>
+#include <net/inetpeer.h>
 #include <linux/in_route.h>
 #include <linux/rtnetlink.h>
 #include <linux/route.h>
@@ -53,6 +54,7 @@
 	__u8			scope;
 };
 
+struct inet_peer;
 struct rtable
 {
 	union
@@ -76,6 +78,7 @@
 
 	/* Miscellaneous cached information */
 	__u32			rt_spec_dst; /* RFC1122 specific destination */
+	struct inet_peer	*peer; /* long-living peer info */
 
 #ifdef CONFIG_IP_ROUTE_NAT
 	__u32			rt_src_map;
@@ -136,6 +139,17 @@
 	ip_rt_put(*rp);
 	*rp = NULL;
 	return ip_route_output(rp, dst, src, tos, oif);
+}
+
+extern void rt_bind_peer(struct rtable *rt, int create);
+
+extern __inline__ struct inet_peer *rt_get_peer(struct rtable *rt)
+{
+	if (rt->peer)
+		return rt->peer;
+
+	rt_bind_peer(rt, 0);
+	return rt->peer;
 }
 
 #endif	/* _ROUTE_H */
diff -u --recursive --new-file v2.3.36/linux/init/main.c linux/init/main.c
--- v2.3.36/linux/init/main.c	Wed Dec 29 13:13:21 1999
+++ linux/init/main.c	Thu Jan  6 10:14:36 2000
@@ -509,6 +509,7 @@
 	page_cache_init(mempages);
 	kiobuf_init();
 	signals_init();
+	bdev_init();
 	inode_init();
 	file_table_init();
 #if defined(CONFIG_SYSVIPC)
diff -u --recursive --new-file v2.3.36/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.36/linux/kernel/ksyms.c	Tue Jan  4 13:57:21 2000
+++ linux/kernel/ksyms.c	Thu Jan  6 10:14:36 2000
@@ -52,8 +52,6 @@
 
 extern int console_loglevel;
 extern void set_device_ro(kdev_t dev,int flag);
-extern struct file_operations * get_blkfops(unsigned int);
-extern int blkdev_release(struct inode * inode);
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 extern int (*do_nfsservctl)(int, void *, void *);
 #endif
@@ -258,9 +256,10 @@
 EXPORT_SYMBOL(set_device_ro);
 EXPORT_SYMBOL(bmap);
 EXPORT_SYMBOL(sync_dev);
-EXPORT_SYMBOL(get_blkfops);
 EXPORT_SYMBOL(blkdev_open);
-EXPORT_SYMBOL(blkdev_release);
+EXPORT_SYMBOL(blkdev_get);
+EXPORT_SYMBOL(blkdev_put);
+EXPORT_SYMBOL(ioctl_by_bdev);
 EXPORT_SYMBOL(gendisk_head);
 EXPORT_SYMBOL(resetup_one_dev);
 EXPORT_SYMBOL(unplug_device);
@@ -417,7 +416,6 @@
 EXPORT_SYMBOL(nr_async_pages);
 EXPORT_SYMBOL(___strtok);
 EXPORT_SYMBOL(init_special_inode);
-EXPORT_SYMBOL(fifo_inode_operations);
 EXPORT_SYMBOL(read_ahead);
 EXPORT_SYMBOL(get_hash_table);
 EXPORT_SYMBOL(get_empty_inode);
diff -u --recursive --new-file v2.3.36/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.3.36/linux/mm/swapfile.c	Tue Dec 14 01:27:24 1999
+++ linux/mm/swapfile.c	Thu Jan  6 10:14:36 2000
@@ -444,7 +444,6 @@
 {
 	struct swap_info_struct * p = NULL;
 	struct dentry * dentry;
-	struct file filp;
 	int i, type, prev;
 	int err = -EPERM;
 	
@@ -508,17 +507,8 @@
 		p->flags = SWP_WRITEOK;
 		goto out_dput;
 	}
-	if(p->swap_device){
-		memset(&filp, 0, sizeof(filp));		
-		filp.f_dentry = dentry;
-		filp.f_mode = 3; /* read write */
-		/* open it again to get fops */
-		if( !blkdev_open(dentry->d_inode, &filp) &&
-		   filp.f_op && filp.f_op->release){
-			filp.f_op->release(dentry->d_inode,&filp);
-			filp.f_op->release(dentry->d_inode,&filp);
-		}
-	}
+	if (p->swap_device)
+		blkdev_put(dentry->d_inode->i_bdev, BDEV_SWAP);
 	dput(dentry);
 
 	dentry = p->swap_file;
@@ -598,18 +588,17 @@
 	unsigned int type;
 	int i, j, prev;
 	int error = -EPERM;
-	struct file filp;
 	static int least_priority = 0;
 	union swap_header *swap_header = 0;
 	int swap_header_version;
 	int nr_good_pages = 0;
 	unsigned long maxpages;
 	int swapfilesize;
+	struct block_device *bdev = NULL;
 	
 	lock_kernel();
 	if (!capable(CAP_SYS_ADMIN))
 		goto out;
-	memset(&filp, 0, sizeof(filp));
 	p = swap_info;
 	for (type = 0 ; type < nr_swapfiles ; type++,p++)
 		if (!(p->flags & SWP_USED))
@@ -648,9 +637,9 @@
 		p->swap_device = dev;
 		set_blocksize(dev, PAGE_SIZE);
 		
-		filp.f_dentry = swap_dentry;
-		filp.f_mode = 3; /* read write */
-		error = blkdev_open(swap_dentry->d_inode, &filp);
+		bdev = swap_dentry->d_inode->i_bdev;
+
+		error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP);
 		if (error)
 			goto bad_swap_2;
 		set_blocksize(dev, PAGE_SIZE);
@@ -812,8 +801,8 @@
 	error = 0;
 	goto out;
 bad_swap:
-	if(filp.f_op && filp.f_op->release)
-		filp.f_op->release(filp.f_dentry->d_inode,&filp);
+	if (bdev)
+		blkdev_put(bdev, BDEV_SWAP);
 bad_swap_2:
 	if (p->swap_map)
 		vfree(p->swap_map);
diff -u --recursive --new-file v2.3.36/linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- v2.3.36/linux/net/ipv4/Config.in	Mon Dec 20 18:48:22 1999
+++ linux/net/ipv4/Config.in	Thu Jan  6 10:15:52 2000
@@ -8,7 +8,9 @@
    define_bool CONFIG_NETLINK y
    bool '    IP: policy routing' CONFIG_IP_MULTIPLE_TABLES
    if [ "$CONFIG_IP_MULTIPLE_TABLES" = "y" ]; then
-      bool '      IP: use FWMARK value as routing key' CONFIG_IP_ROUTE_FWMARK
+      if [ "$CONFIG_NETFILTER" = "y" ]; then
+         bool '      IP: use FWMARK value as routing key' CONFIG_IP_ROUTE_FWMARK
+      fi
       bool '      IP: fast network address translation' CONFIG_IP_ROUTE_NAT
    fi
    bool '    IP: equal cost multipath' CONFIG_IP_ROUTE_MULTIPATH
diff -u --recursive --new-file v2.3.36/linux/net/ipv4/Makefile linux/net/ipv4/Makefile
--- v2.3.36/linux/net/ipv4/Makefile	Thu Aug 26 13:05:45 1999
+++ linux/net/ipv4/Makefile	Thu Jan  6 10:14:36 2000
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := ipv4.o
-IPV4_OBJS := utils.o route.o proc.o protocol.o \
+IPV4_OBJS := utils.o route.o inetpeer.o proc.o protocol.o \
 	     ip_input.o ip_fragment.o ip_forward.o ip_options.o \
 	     ip_output.o ip_sockglue.o \
 	     tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o\
diff -u --recursive --new-file v2.3.36/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- v2.3.36/linux/net/ipv4/igmp.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv4/igmp.c	Thu Jan  6 10:14:36 2000
@@ -8,7 +8,7 @@
  *	the older version didn't come out right using gcc 2.5.8, the newer one
  *	seems to fall out with gcc 2.6.2.
  *
- *	Version: $Id: igmp.c,v 1.35 1999/12/15 22:39:10 davem Exp $
+ *	Version: $Id: igmp.c,v 1.36 2000/01/06 00:41:54 davem Exp $
  *
  *	Authors:
  *		Alan Cox <Alan.Cox@linux.org>
@@ -224,13 +224,13 @@
 	iph->version  = 4;
 	iph->ihl      = (sizeof(struct iphdr)+4)>>2;
 	iph->tos      = 0;
-	iph->frag_off = 0;
+	iph->frag_off = __constant_htons(IP_DF);
 	iph->ttl      = 1;
 	iph->daddr    = dst;
 	iph->saddr    = rt->rt_src;
 	iph->protocol = IPPROTO_IGMP;
 	iph->tot_len  = htons(IGMP_SIZE);
-	iph->id	      = htons(ip_id_count++);
+	ip_select_ident(iph, &rt->u.dst);
 	((u8*)&iph[1])[0] = IPOPT_RA;
 	((u8*)&iph[1])[1] = 4;
 	((u8*)&iph[1])[2] = 0;
diff -u --recursive --new-file v2.3.36/linux/net/ipv4/inetpeer.c linux/net/ipv4/inetpeer.c
--- v2.3.36/linux/net/ipv4/inetpeer.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/inetpeer.c	Thu Jan  6 10:14:36 2000
@@ -0,0 +1,447 @@
+/*
+ *		INETPEER - A storage for permanent information about peers
+ *
+ *  This source is covered by the GNU GPL, the same as all kernel sources.
+ *
+ *  Version:	$Id: inetpeer.c,v 1.1 2000/01/06 00:41:55 davem Exp $
+ *
+ *  Authors:	Andrey V. Savochkin <saw@msu.ru>
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/time.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <net/inetpeer.h>
+
+/*
+ *  Theory of operations.
+ *  We keep one entry for each peer IP address.  The nodes contains long-living
+ *  information about the peer which doesn't depend on routes.
+ *  At this moment this information consists only of ID field for the next
+ *  outgoing IP packet.  This field is incremented with each packet as encoded
+ *  in inet_getid() function (include/net/inetpeer.h).
+ *  At the moment of writing this notes identifier of IP packets is generated
+ *  to be unpredictable using this code only for packets subjected
+ *  (actually or potentially) to defragmentation.  I.e. DF packets less than
+ *  PMTU in size uses a constant ID and do not use this code (see
+ *  ip_select_ident() in include/net/ip.h).
+ *
+ *  Route cache entries hold references to our nodes.
+ *  New cache entries get references via lookup by destination IP address in
+ *  the avl tree.  The reference is grabbed only when it's needed i.e. only
+ *  when we try to output IP packet which needs an unpredictable ID (see
+ *  __ip_select_ident() in net/ipv4/route.c).
+ *  Nodes are removed only when reference counter goes to 0.
+ *  When it's happened the node may be removed when a sufficient amount of
+ *  time has been passed since its last use.  The less-recently-used entry can
+ *  also be removed if the pool is overloaded i.e. if the total amount of
+ *  entries is greater-or-equal than the threshold.
+ *
+ *  Node pool is organised as an AVL tree.
+ *  Such an implementation has been chosen not just for fun.  It's a way to
+ *  prevent easy and efficient DoS attacks by creating hash collisions.  A huge
+ *  amount of long living nodes in a single hash slot would significantly delay
+ *  lookups performed with disabled BHs.
+ *
+ *  Serialisation issues.
+ *  1.  Nodes may appear in the tree only with the pool write lock held.
+ *  2.  Nodes may disappear from the tree only with the pool write lock held
+ *      AND reference count being 0.
+ *  3.  Nodes appears and disappears from unused node list only under
+ *      "inet_peer_unused_lock".
+ *  4.  Global variable peer_total is modified under the pool lock.
+ *  5.  struct inet_peer fields modification:
+ *		avl_left, avl_right, avl_parent, avl_height: pool lock
+ *		unused_next, unused_prevp: unused node list lock
+ *		refcnt: atomically against modifications on other CPU;
+ *		   usually under some other lock to prevent node disappearing
+ *		dtime: unused node list lock
+ *		v4daddr: unchangeable
+ *		ip_id_count: idlock
+ */
+
+spinlock_t inet_peer_idlock = SPIN_LOCK_UNLOCKED;
+
+static kmem_cache_t *peer_cachep;
+
+#define node_height(x) x->avl_height
+static struct inet_peer peer_fake_node = {
+	avl_left : &peer_fake_node,
+	avl_right : &peer_fake_node,
+	avl_height : 0
+};
+#define peer_avl_empty (&peer_fake_node)
+static struct inet_peer *peer_root = peer_avl_empty;
+static rwlock_t peer_pool_lock = RW_LOCK_UNLOCKED;
+#define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */
+
+static volatile int peer_total = 0;
+int inet_peer_threshold = 65536 + 128;	/* start to throw entries more
+					 * aggressively at this stage */
+int inet_peer_minttl = 120 * HZ;	/* TTL under high load: 120 sec */
+int inet_peer_maxttl = 10 * 60 * HZ;	/* usual time to live: 10 min */
+struct inet_peer *inet_peer_unused_head = NULL,
+		**inet_peer_unused_tailp = &inet_peer_unused_head;
+spinlock_t inet_peer_unused_lock = SPIN_LOCK_UNLOCKED;
+#define PEER_MAX_CLEANUP_WORK 30
+
+static void peer_check_expire(unsigned long dummy);
+static struct timer_list peer_periodic_timer =
+	{ NULL, NULL, 0, 0, &peer_check_expire };
+int inet_peer_gc_mintime = 10 * HZ,
+    inet_peer_gc_maxtime = 120 * HZ;
+
+
+void __init inet_initpeers(void)
+{
+	struct sysinfo si;
+
+	/* Use the straight interface to information about memory. */
+	si_meminfo(&si);
+	/* The values below were suggested by Alexey Kuznetsov
+	 * <kuznet@ms2.inr.ac.ru>.  I don't have any opinion about the values
+	 * myself.  --SAW
+	 */
+	if (si.totalram <= 32768*1024)
+		inet_peer_threshold >>= 1; /* max pool size about 1MB on IA32 */
+	if (si.totalram <= 16384*1024)
+		inet_peer_threshold >>= 1; /* about 512KB */
+	if (si.totalram <= 8192*1024)
+		inet_peer_threshold >>= 2; /* about 128KB */
+
+	peer_cachep = kmem_cache_create("inet_peer_cache",
+			sizeof(struct inet_peer),
+			0, SLAB_HWCACHE_ALIGN,
+			NULL, NULL);
+
+	/* All the timers, started at system startup tend
+	   to synchronize. Perturb it a bit.
+	 */
+	peer_periodic_timer.expires = jiffies
+		+ net_random() % inet_peer_gc_maxtime
+		+ inet_peer_gc_maxtime;
+	add_timer(&peer_periodic_timer);
+}
+
+/* Called with or without local BH being disabled. */
+static void unlink_from_unused(struct inet_peer *p)
+{
+	spin_lock_bh(&inet_peer_unused_lock);
+	if (p->unused_prevp != NULL) {
+		/* On unused list. */
+		*p->unused_prevp = p->unused_next;
+		if (p->unused_next != NULL)
+			p->unused_next->unused_prevp = p->unused_prevp;
+		else
+			inet_peer_unused_tailp = p->unused_prevp;
+		p->unused_prevp = NULL; /* mark it as removed */
+	}
+	spin_unlock_bh(&inet_peer_unused_lock);
+}
+
+/* Called with local BH disabled and the pool lock held. */
+#define lookup(daddr) 						\
+({								\
+	struct inet_peer *u, **v;				\
+	stackptr = stack;					\
+	*stackptr++ = &peer_root;				\
+	for (u = peer_root; u != peer_avl_empty; ) {		\
+		if (daddr == u->v4daddr)			\
+			break;					\
+		if (daddr < u->v4daddr)				\
+			v = &u->avl_left;			\
+		else						\
+			v = &u->avl_right;			\
+		*stackptr++ = v;				\
+		u = *v;						\
+	}							\
+	u;							\
+})
+
+/* Called with local BH disabled and the pool write lock held. */
+#define lookup_rightempty(start)				\
+({								\
+	struct inet_peer *u, **v;				\
+	*stackptr++ = &start->avl_left;				\
+	v = &start->avl_left;					\
+	for (u = *v; u->avl_right != peer_avl_empty; ) {	\
+		v = &u->avl_right;				\
+		*stackptr++ = v;				\
+		u = *v;						\
+	}							\
+	u;							\
+})
+
+/* Called with local BH disabled and the pool write lock held.
+ * Variable names are the proof of operation correctness.
+ * Look into mm/map_avl.c for more detail description of the ideas.  */
+static void peer_avl_rebalance(struct inet_peer **stack[],
+		struct inet_peer ***stackend)
+{
+	struct inet_peer **nodep, *node, *l, *r;
+	int lh, rh;
+
+	while (stackend > stack) {
+		nodep = *--stackend;
+		node = *nodep;
+		l = node->avl_left;
+		r = node->avl_right;
+		lh = node_height(l);
+		rh = node_height(r);
+		if (lh > rh + 1) { /* l: RH+2 */
+			struct inet_peer *ll, *lr, *lrl, *lrr;
+			int lrh;
+			ll = l->avl_left;
+			lr = l->avl_right;
+			lrh = node_height(lr);
+			if (lrh <= node_height(ll)) {	/* ll: RH+1 */
+				node->avl_left = lr;	/* lr: RH or RH+1 */
+				node->avl_right = r;	/* r: RH */
+				node->avl_height = lrh + 1; /* RH+1 or RH+2 */
+				l->avl_left = ll;	/* ll: RH+1 */
+				l->avl_right = node;	/* node: RH+1 or RH+2 */
+				l->avl_height = node->avl_height + 1;
+				*nodep = l;
+			} else { /* ll: RH, lr: RH+1 */
+				lrl = lr->avl_left;	/* lrl: RH or RH-1 */
+				lrr = lr->avl_right;	/* lrr: RH or RH-1 */
+				node->avl_left = lrr;	/* lrr: RH or RH-1 */
+				node->avl_right = r;	/* r: RH */
+				node->avl_height = rh + 1; /* node: RH+1 */
+				l->avl_left = ll;	/* ll: RH */
+				l->avl_right = lrl;	/* lrl: RH or RH-1 */
+				l->avl_height = rh + 1;	/* l: RH+1 */
+				lr->avl_left = l;	/* l: RH+1 */
+				lr->avl_right = node;	/* node: RH+1 */
+				lr->avl_height = rh + 2;
+				*nodep = lr;
+			}
+		} else if (rh > lh + 1) { /* r: LH+2 */
+			struct inet_peer *rr, *rl, *rlr, *rll;
+			int rlh;
+			rr = r->avl_right;
+			rl = r->avl_left;
+			rlh = node_height(rl);
+			if (rlh <= node_height(rr)) {	/* rr: LH+1 */
+				node->avl_right = rl;	/* rl: LH or LH+1 */
+				node->avl_left = l;	/* l: LH */
+				node->avl_height = rlh + 1; /* LH+1 or LH+2 */
+				r->avl_right = rr;	/* rr: LH+1 */
+				r->avl_left = node;	/* node: LH+1 or LH+2 */
+				r->avl_height = node->avl_height + 1;
+				*nodep = r;
+			} else { /* rr: RH, rl: RH+1 */
+				rlr = rl->avl_right;	/* rlr: LH or LH-1 */
+				rll = rl->avl_left;	/* rll: LH or LH-1 */
+				node->avl_right = rll;	/* rll: LH or LH-1 */
+				node->avl_left = l;	/* l: LH */
+				node->avl_height = lh + 1; /* node: LH+1 */
+				r->avl_right = rr;	/* rr: LH */
+				r->avl_left = rlr;	/* rlr: LH or LH-1 */
+				r->avl_height = lh + 1;	/* r: LH+1 */
+				rl->avl_right = r;	/* r: LH+1 */
+				rl->avl_left = node;	/* node: LH+1 */
+				rl->avl_height = lh + 2;
+				*nodep = rl;
+			}
+		} else {
+			node->avl_height = (lh > rh ? lh : rh) + 1;
+		}
+	}
+}
+
+/* Called with local BH disabled and the pool write lock held. */
+#define link_to_pool(n)						\
+do {								\
+	n->avl_height = 1;					\
+	n->avl_left = peer_avl_empty;				\
+	n->avl_right = peer_avl_empty;				\
+	**--stackptr = n;					\
+	peer_avl_rebalance(stack, stackptr);			\
+} while(0)
+
+/* May be called with local BH enabled. */
+static void unlink_from_pool(struct inet_peer *p)
+{
+	int do_free;
+
+	do_free = 0;
+
+	write_lock_bh(&peer_pool_lock);
+	/* Check the reference counter.  It was artificially incremented by 1
+	 * in cleanup() function to prevent sudden disappearing.  If the
+	 * reference count is still 1 then the node is referenced only as `p'
+	 * here and from the pool.  So under the exclusive pool lock it's safe
+	 * to remove the node and free it later. */
+	if (atomic_read(&p->refcnt) == 1) {
+		struct inet_peer **stack[PEER_MAXDEPTH];
+		struct inet_peer ***stackptr, ***delp;
+		if (lookup(p->v4daddr) != p)
+			BUG();
+		delp = stackptr - 1; /* *delp[0] == p */
+		if (p->avl_left == peer_avl_empty) {
+			*delp[0] = p->avl_right;
+			--stackptr;
+		} else {
+			/* look for a node to insert instead of p */
+			struct inet_peer *t;
+			t = lookup_rightempty(p);
+			if (*stackptr[-1] != t)
+				BUG();
+			**--stackptr = t->avl_left;
+			/* t is removed, t->v4daddr > x->v4daddr for any
+			 * x in p->avl_left subtree.
+			 * Put t in the old place of p. */
+			*delp[0] = t;
+			t->avl_left = p->avl_left;
+			t->avl_right = p->avl_right;
+			t->avl_height = p->avl_height;
+			if (delp[1] != &p->avl_left)
+				BUG();
+			delp[1] = &t->avl_left; /* was &p->avl_left */
+		}
+		peer_avl_rebalance(stack, stackptr);
+		peer_total--;
+		do_free = 1;
+	}
+	write_unlock_bh(&peer_pool_lock);
+
+	if (do_free)
+		kmem_cache_free(peer_cachep, p);
+	else
+		/* The node is used again.  Decrease the reference counter
+		 * back.  The loop "cleanup -> unlink_from_unused
+		 *   -> unlink_from_pool -> putpeer -> link_to_unused
+		 *   -> cleanup (for the same node)"
+		 * doesn't really exist because the entry will have a
+		 * recent deletion time and will not be cleaned again soon. */
+		inet_putpeer(p);
+}
+
+/* May be called with local BH enabled. */
+static int cleanup_once(unsigned long ttl)
+{
+	struct inet_peer *p;
+
+	/* Remove the first entry from the list of unused nodes. */
+	spin_lock_bh(&inet_peer_unused_lock);
+	p = inet_peer_unused_head;
+	if (p != NULL) {
+		if (time_after(p->dtime + ttl, jiffies)) {
+			/* Do not prune fresh entries. */
+			spin_unlock_bh(&inet_peer_unused_lock);
+			return -1;
+		}
+		inet_peer_unused_head = p->unused_next;
+		if (p->unused_next != NULL)
+			p->unused_next->unused_prevp = p->unused_prevp;
+		else
+			inet_peer_unused_tailp = p->unused_prevp;
+		p->unused_prevp = NULL; /* mark as not on the list */
+		/* Grab an extra reference to prevent node disappearing
+		 * before unlink_from_pool() call. */
+		atomic_inc(&p->refcnt);
+	}
+	spin_unlock_bh(&inet_peer_unused_lock);
+
+	if (p == NULL)
+		/* It means that the total number of USED entries has
+		 * grown over inet_peer_threshold.  It shouldn't really
+		 * happen because of entry limits in route cache. */
+		return -1;
+
+	unlink_from_pool(p);
+	return 0;
+}
+
+/* Called with or without local BH being disabled. */
+struct inet_peer *inet_getpeer(__u32 daddr, int create)
+{
+	struct inet_peer *p, *n;
+	struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr;
+
+	/* Look up for the address quickly. */
+	read_lock_bh(&peer_pool_lock);
+	p = lookup(daddr);
+	if (p != peer_avl_empty)
+		atomic_inc(&p->refcnt);
+	read_unlock_bh(&peer_pool_lock);
+
+	if (p != peer_avl_empty) {
+		/* The existing node has been found. */
+		/* Remove the entry from unused list if it was there. */
+		unlink_from_unused(p);
+		return p;
+	}
+
+	if (!create)
+		return NULL;
+
+	/* Allocate the space outside the locked region. */
+	n = kmem_cache_alloc(peer_cachep, GFP_ATOMIC);
+	if (n == NULL)
+		return NULL;
+	n->v4daddr = daddr;
+	atomic_set(&n->refcnt, 1);
+	n->ip_id_count = secure_ip_id(daddr);
+	n->tcp_ts_stamp = 0;
+
+	write_lock_bh(&peer_pool_lock);
+	/* Check if an entry has suddenly appeared. */
+	p = lookup(daddr);
+	if (p != peer_avl_empty)
+		goto out_free;
+
+	/* Link the node. */
+	link_to_pool(n);
+	n->unused_prevp = NULL; /* not on the list */
+	peer_total++;
+	write_unlock_bh(&peer_pool_lock);
+
+	if (peer_total >= inet_peer_threshold)
+		/* Remove one less-recently-used entry. */
+		cleanup_once(0);
+
+	return n;
+
+out_free:
+	/* The appropriate node is already in the pool. */
+	atomic_inc(&p->refcnt);
+	write_unlock_bh(&peer_pool_lock);
+	/* Remove the entry from unused list if it was there. */
+	unlink_from_unused(p);
+	/* Free preallocated the preallocated node. */
+	kmem_cache_free(peer_cachep, n);
+	return p;
+}
+
+/* Called with local BH disabled. */
+static void peer_check_expire(unsigned long dummy)
+{
+	int i;
+	int ttl;
+
+	if (peer_total >= inet_peer_threshold)
+		ttl = inet_peer_minttl;
+	else
+		ttl = inet_peer_maxttl
+				- (inet_peer_maxttl - inet_peer_minttl) / HZ *
+					peer_total / inet_peer_threshold * HZ;
+	for (i = 0; i < PEER_MAX_CLEANUP_WORK && !cleanup_once(ttl); i++);
+
+	/* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime
+	 * interval depending on the total number of entries (more entries,
+	 * less interval). */
+	peer_periodic_timer.expires = jiffies
+		+ inet_peer_gc_maxtime
+		- (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ *
+			peer_total / inet_peer_threshold * HZ;
+	add_timer(&peer_periodic_timer);
+}
diff -u --recursive --new-file v2.3.36/linux/net/ipv4/ip_gre.c linux/net/ipv4/ip_gre.c
--- v2.3.36/linux/net/ipv4/ip_gre.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv4/ip_gre.c	Thu Jan  6 10:14:36 2000
@@ -815,7 +815,7 @@
 	}
 
 	iph->tot_len		=	htons(skb->len);
-	iph->id			=	htons(ip_id_count++);
+	ip_select_ident(iph, &rt->u.dst);
 	ip_send_check(iph);
 
 	stats->tx_bytes += skb->len;
diff -u --recursive --new-file v2.3.36/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.3.36/linux/net/ipv4/ip_output.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv4/ip_output.c	Thu Jan  6 10:14:36 2000
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) output module.
  *
- * Version:	$Id: ip_output.c,v 1.75 1999/12/21 04:05:04 davem Exp $
+ * Version:	$Id: ip_output.c,v 1.76 2000/01/06 00:41:57 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -71,6 +71,7 @@
 #include <net/icmp.h>
 #include <net/raw.h>
 #include <net/checksum.h>
+#include <net/inetpeer.h>
 #include <linux/igmp.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/mroute.h>
@@ -82,8 +83,6 @@
 
 int sysctl_ip_dynaddr = 0;
 
-int ip_id_count = 0;
-
 /* Generate a checksum for an outgoing IP datagram. */
 __inline__ void ip_send_check(struct iphdr *iph)
 {
@@ -154,7 +153,7 @@
 {
 	struct rtable *rt = (struct rtable *)skb->dst;
 	struct iphdr *iph;
-	
+
 	/* Build the IP header. */
 	if (opt)
 		iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr) + opt->optlen);
@@ -172,7 +171,7 @@
 	iph->saddr    = rt->rt_src;
 	iph->protocol = sk->protocol;
 	iph->tot_len  = htons(skb->len);
-	iph->id       = htons(ip_id_count++);
+	ip_select_ident(iph, &rt->u.dst);
 	skb->nh.iph   = iph;
 
 	if (opt && opt->optlen) {
@@ -356,6 +355,8 @@
 	if (ip_dont_fragment(sk, &rt->u.dst))
 		iph->frag_off |= __constant_htons(IP_DF);
 
+	ip_select_ident(iph, &rt->u.dst);
+
 	/* Add an IP checksum. */
 	ip_send_check(iph);
 
@@ -375,6 +376,7 @@
 		kfree_skb(skb);
 		return -EMSGSIZE;
 	}
+	ip_select_ident(iph, &rt->u.dst);
 	return ip_fragment(skb, skb->dst->output);
 }
 
@@ -429,7 +431,6 @@
 	}
 
 	iph->tot_len = htons(skb->len);
-	iph->id = htons(ip_id_count++);
 
 	return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
 		       ip_queue_xmit2);
@@ -475,7 +476,7 @@
 	int err;
 	int offset, mf;
 	int mtu;
-	unsigned short id;
+	u16 id = 0;
 
 	int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
 	int nfrags=0;
@@ -485,7 +486,7 @@
 	mtu = rt->u.dst.pmtu;
 	if (ip_dont_fragment(sk, &rt->u.dst))
 		df = htons(IP_DF);
-  
+
 	length -= sizeof(struct iphdr);
 
 	if (opt) {
@@ -493,12 +494,12 @@
 		maxfraglen = ((mtu-sizeof(struct iphdr)-opt->optlen) & ~7) + fragheaderlen;
 	} else {
 		fragheaderlen = sizeof(struct iphdr);
-		
+
 		/*
 		 *	Fragheaderlen is the size of 'overhead' on each buffer. Now work
 		 *	out the size of the frames to send.
 		 */
-	 
+
 		maxfraglen = ((mtu-sizeof(struct iphdr)) & ~7) + fragheaderlen;
 	}
 
@@ -510,15 +511,15 @@
 	/*
 	 *	Start at the end of the frame by handling the remainder.
 	 */
-	 
+
 	offset = length - (length % (maxfraglen - fragheaderlen));
-	
+
 	/*
 	 *	Amount of memory to allocate for final fragment.
 	 */
-	 
+
 	fraglen = length - offset + fragheaderlen;
-	
+
 	if (length-offset==0) {
 		fraglen = maxfraglen;
 		offset -= maxfraglen-fragheaderlen;
@@ -527,14 +528,14 @@
 	/*
 	 *	The last fragment will not have MF (more fragments) set.
 	 */
-	 
+
 	mf = 0;
 
 	/*
 	 *	Don't fragment packets for path mtu discovery.
 	 */
-	 
-	if (offset > 0 && df) { 
+
+	if (offset > 0 && sk->protinfo.af_inet.pmtudisc==IP_PMTUDISC_DO) { 
 		ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu);
  		return -EMSGSIZE;
 	}
@@ -542,15 +543,9 @@
 		goto out;
 
 	/*
-	 *	Get an identifier
-	 */
-	 
-	id = htons(ip_id_count++);
-
-	/*
 	 *	Begin outputting the bytes.
 	 */
-	 
+
 	do {
 		char *data;
 		struct sk_buff * skb;
@@ -566,7 +561,7 @@
 		/*
 		 *	Fill in the control structures
 		 */
-		 
+
 		skb->priority = sk->priority;
 		skb->dst = dst_clone(&rt->u.dst);
 		skb_reserve(skb, hh_len);
@@ -574,14 +569,14 @@
 		/*
 		 *	Find where to start putting bytes.
 		 */
-		 
+
 		data = skb_put(skb, fraglen);
 		skb->nh.iph = (struct iphdr *)data;
 
 		/*
 		 *	Only write IP header onto non-raw packets 
 		 */
-		 
+
 		{
 			struct iphdr *iph = (struct iphdr *)data;
 
@@ -594,9 +589,23 @@
 			}
 			iph->tos = sk->protinfo.af_inet.tos;
 			iph->tot_len = htons(fraglen - fragheaderlen + iph->ihl*4);
+			iph->frag_off = htons(offset>>3)|mf|df;
 			iph->id = id;
-			iph->frag_off = htons(offset>>3);
-			iph->frag_off |= mf|df;
+			if (!mf) {
+				if (offset || !df) {
+					/* Select an unpredictable ident only
+					 * for packets without DF or having
+					 * been fragmented.
+					 */
+					__ip_select_ident(iph, &rt->u.dst);
+					id = iph->id;
+				}
+
+				/*
+				 *	Any further fragments will have MF set.
+				 */
+				mf = htons(IP_MF);
+			}
 			if (rt->rt_type == RTN_MULTICAST)
 				iph->ttl = sk->protinfo.af_inet.mc_ttl;
 			else
@@ -607,14 +616,8 @@
 			iph->daddr = rt->rt_dst;
 			iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 			data += iph->ihl*4;
-			
-			/*
-			 *	Any further fragments will have MF set.
-			 */
-			 
-			mf = htons(IP_MF);
 		}
-		
+
 		/*
 		 *	User data callback
 		 */
@@ -712,20 +715,20 @@
 		goto error; 
 	skb_reserve(skb, hh_len);
 	}
-	
+
 	skb->priority = sk->priority;
 	skb->dst = dst_clone(&rt->u.dst);
 
 	skb->nh.iph = iph = (struct iphdr *)skb_put(skb, length);
-	
+
 	if(!sk->protinfo.af_inet.hdrincl) {
 		iph->version=4;
 		iph->ihl=5;
 		iph->tos=sk->protinfo.af_inet.tos;
 		iph->tot_len = htons(length);
-		iph->id=htons(ip_id_count++);
 		iph->frag_off = df;
 		iph->ttl=sk->protinfo.af_inet.mc_ttl;
+		ip_select_ident(iph, &rt->u.dst);
 		if (rt->rt_type != RTN_MULTICAST)
 			iph->ttl=sk->protinfo.af_inet.ttl;
 		iph->protocol=sk->protocol;
@@ -757,8 +760,6 @@
 	ip_statistics.IpOutDiscards++;
 	return err; 
 }
-		       
-
 
 /*
  *	This IP datagram is too large to be sent in one piece.  Break it up into
@@ -905,7 +906,7 @@
 	kfree_skb(skb);
 	ip_statistics.IpFragOKs++;
 	return err;
-	
+
 fail:
 	kfree_skb(skb); 
 	ip_statistics.IpFragFails++;
@@ -1006,7 +1007,6 @@
 	NULL,
 };
 
-
 /*
  *	IP registers the packet type and then calls the subprotocol initialisers
  */
@@ -1016,9 +1016,9 @@
 	dev_add_pack(&ip_packet_type);
 
 	ip_rt_init();
+	inet_initpeers();
 
 #ifdef CONFIG_IP_MULTICAST
 	proc_net_create("igmp", 0, ip_mc_procinfo);
 #endif
 }
-
diff -u --recursive --new-file v2.3.36/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c
--- v2.3.36/linux/net/ipv4/ipip.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv4/ipip.c	Thu Jan  6 10:14:36 2000
@@ -1,7 +1,7 @@
 /*
  *	Linux NET3:	IP/IP protocol decoder. 
  *
- *	Version: $Id: ipip.c,v 1.29 1999/08/31 07:03:42 davem Exp $
+ *	Version: $Id: ipip.c,v 1.30 2000/01/06 00:41:55 davem Exp $
  *
  *	Authors:
  *		Sam Lantinga (slouken@cs.ucdavis.edu)  02/01/95
@@ -616,7 +616,7 @@
 		iph->ttl	=	old_iph->ttl;
 
 	iph->tot_len		=	htons(skb->len);
-	iph->id			=	htons(ip_id_count++);
+	ip_select_ident(iph, &rt->u.dst);
 	ip_send_check(iph);
 
 	stats->tx_bytes += skb->len;
diff -u --recursive --new-file v2.3.36/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.3.36/linux/net/ipv4/ipmr.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv4/ipmr.c	Thu Jan  6 10:14:36 2000
@@ -9,7 +9,7 @@
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  *
- *	Version: $Id: ipmr.c,v 1.48 1999/12/15 22:39:16 davem Exp $
+ *	Version: $Id: ipmr.c,v 1.49 2000/01/06 00:41:56 davem Exp $
  *
  *	Fixes:
  *	Michael Chastain	:	Incorrect size of copying.
@@ -1095,7 +1095,7 @@
 	iph->protocol	=	IPPROTO_IPIP;
 	iph->ihl	=	5;
 	iph->tot_len	=	htons(skb->len);
-	iph->id		=	htons(ip_id_count++);
+	ip_select_ident(iph, skb->dst);
 	ip_send_check(iph);
 
 	skb->h.ipiph = skb->nh.iph;
diff -u --recursive --new-file v2.3.36/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.3.36/linux/net/ipv4/raw.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv4/raw.c	Thu Jan  6 10:14:36 2000
@@ -5,7 +5,7 @@
  *
  *		RAW - implementation of IP "raw" sockets.
  *
- * Version:	$Id: raw.c,v 1.44 1999/12/15 22:39:21 davem Exp $
+ * Version:	$Id: raw.c,v 1.45 2000/01/06 00:41:58 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -257,6 +257,7 @@
 {
 	struct  iovec *iov;
 	u32	saddr;
+	struct dst_entry *dst;
 };
 
 /*
@@ -296,7 +297,7 @@
 	 	 *	ip_build_xmit clean (well less messy).
 		 */
 		if (!iph->id)
-			iph->id = htons(ip_id_count++);
+			ip_select_ident(iph, rfh->dst);
 		iph->check=ip_fast_csum((unsigned char *)iph, iph->ihl);
 	}
 	return 0;
@@ -416,6 +417,7 @@
 
 	rfh.iov = msg->msg_iov;
 	rfh.saddr = rt->rt_src;
+	rfh.dst = &rt->u.dst;
 	if (!ipc.addr)
 		ipc.addr = rt->rt_dst;
 	err=ip_build_xmit(sk, sk->protinfo.af_inet.hdrincl ? raw_getrawfrag : raw_getfrag,
diff -u --recursive --new-file v2.3.36/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.3.36/linux/net/ipv4/route.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv4/route.c	Thu Jan  6 10:14:36 2000
@@ -83,9 +83,11 @@
 #include <linux/pkt_sched.h>
 #include <linux/mroute.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/random.h>
 #include <net/protocol.h>
 #include <net/ip.h>
 #include <net/route.h>
+#include <net/inetpeer.h>
 #include <net/sock.h>
 #include <net/ip_fib.h>
 #include <net/arp.h>
@@ -134,6 +136,7 @@
 static struct dst_entry * ipv4_dst_check(struct dst_entry * dst, u32);
 static struct dst_entry * ipv4_dst_reroute(struct dst_entry * dst,
 					   struct sk_buff *);
+static void		  ipv4_dst_destroy(struct dst_entry * dst);
 static struct dst_entry * ipv4_negative_advice(struct dst_entry *);
 static void		  ipv4_link_failure(struct sk_buff *skb);
 static int rt_garbage_collect(void);
@@ -148,7 +151,7 @@
 	rt_garbage_collect,
 	ipv4_dst_check,
 	ipv4_dst_reroute,
-	NULL,
+	ipv4_dst_destroy,
 	ipv4_negative_advice,
 	ipv4_link_failure,
 	sizeof(struct rtable),
@@ -626,6 +629,65 @@
 	return 0;
 }
 
+void rt_bind_peer(struct rtable *rt, int create)
+{
+	static spinlock_t rt_peer_lock = SPIN_LOCK_UNLOCKED;
+	struct inet_peer *peer;
+
+	peer = inet_getpeer(rt->rt_dst, create);
+
+	spin_lock_bh(&rt_peer_lock);
+	if (rt->peer == NULL) {
+		rt->peer = peer;
+		peer = NULL;
+	}
+	spin_unlock_bh(&rt_peer_lock);
+	if (peer)
+		inet_putpeer(peer);
+}
+
+/*
+ * Peer allocation may fail only in serious out-of-memory conditions.  However
+ * we still can generate some output.
+ * Random ID selection looks a bit dangerous because we have no chances to
+ * select ID being unique in a reasonable period of time.
+ * But broken packet identifier may be better than no packet at all.
+ */
+static void ip_select_fb_ident(struct iphdr *iph)
+{
+	static spinlock_t ip_fb_id_lock = SPIN_LOCK_UNLOCKED;
+	static u32 ip_fallback_id;
+	u32 salt;
+
+	spin_lock_bh(&ip_fb_id_lock);
+	salt = secure_ip_id(ip_fallback_id ^ iph->daddr);
+	iph->id = salt & 0xFFFF;
+	ip_fallback_id = salt;
+	spin_unlock_bh(&ip_fb_id_lock);
+}
+
+void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst)
+{
+	struct rtable *rt = (struct rtable *) dst;
+
+	if (rt) {
+		if (rt->peer == NULL)
+			rt_bind_peer(rt, 1);
+
+		/* If peer is attached to destination, it is never detached,
+		   so that we need not to grab a lock to dereference it.
+		 */
+		if (rt->peer) {
+			iph->id = inet_getid(rt->peer);
+			return;
+		}
+	} else {
+		printk(KERN_DEBUG "rt_bind_peer(0) @%p\n", NET_CALLER(iph));
+	}
+
+	ip_select_fb_ident(iph);
+}
+
 static void rt_del(unsigned hash, struct rtable *rt)
 {
 	struct rtable **rthp;
@@ -727,6 +789,9 @@
 				/* Redirect received -> path was valid */
 				dst_confirm(&rth->u.dst);
 
+				if (rt->peer)
+					atomic_inc(&rt->peer->refcnt);
+
 				if (!arp_bind_neighbour(&rt->u.dst) ||
 				    !(rt->u.dst.neighbour->nud_state&NUD_VALID)) {
 					if (rt->u.dst.neighbour)
@@ -973,6 +1038,17 @@
 	return NULL;
 }
 
+static void ipv4_dst_destroy(struct dst_entry * dst)
+{
+	struct rtable *rt = (struct rtable *) dst;
+	struct inet_peer *peer = rt->peer;
+
+	if (peer) {
+		rt->peer = NULL;
+		inet_putpeer(peer);
+	}
+}
+
 static void ipv4_link_failure(struct sk_buff *skb)
 {
 	struct rtable *rt;
@@ -1885,6 +1961,16 @@
 	else
 		ci.rta_expires = 0;
 	ci.rta_error = rt->u.dst.error;
+	ci.rta_id = 0;
+	ci.rta_ts = 0;
+	ci.rta_tsage = 0;
+	if (rt->peer) {
+		ci.rta_id = rt->peer->ip_id_count;
+		if (rt->peer->tcp_ts_stamp) {
+			ci.rta_ts = rt->peer->tcp_ts;
+			ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp;
+		}
+	}
 #ifdef CONFIG_IP_MROUTE
 	eptr = (struct rtattr*)skb->tail;
 #endif
diff -u --recursive --new-file v2.3.36/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c
--- v2.3.36/linux/net/ipv4/sysctl_net_ipv4.c	Fri Sep 10 23:57:38 1999
+++ linux/net/ipv4/sysctl_net_ipv4.c	Thu Jan  6 10:14:36 2000
@@ -1,7 +1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.40 1999/09/07 02:31:17 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.41 2000/01/06 00:42:03 davem Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -70,6 +70,13 @@
 /* From igmp.c */
 extern int sysctl_igmp_max_memberships;
 
+/* From inetpeer.c */
+extern int inet_peer_threshold;
+extern int inet_peer_minttl;
+extern int inet_peer_maxttl;
+extern int inet_peer_gc_mintime;
+extern int inet_peer_gc_maxtime;
+
 int tcp_retr1_max = 255; 
 
 struct ipv4_config ipv4_config;
@@ -200,6 +207,20 @@
 	{NET_IPV4_IGMP_MAX_MEMBERSHIPS, "igmp_max_memberships",
 	 &sysctl_igmp_max_memberships, sizeof(int), 0644, NULL, &proc_dointvec},
 #endif
+	{NET_IPV4_INET_PEER_THRESHOLD, "inet_peer_threshold",
+	 &inet_peer_threshold, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV4_INET_PEER_MINTTL, "inet_peer_minttl",
+	 &inet_peer_minttl, sizeof(int), 0644, NULL,
+	 &proc_dointvec_jiffies, &sysctl_jiffies},
+	{NET_IPV4_INET_PEER_MAXTTL, "inet_peer_maxttl",
+	 &inet_peer_maxttl, sizeof(int), 0644, NULL,
+	 &proc_dointvec_jiffies, &sysctl_jiffies},
+	{NET_IPV4_INET_PEER_GC_MINTIME, "inet_peer_gc_mintime",
+	 &inet_peer_gc_mintime, sizeof(int), 0644, NULL,
+	 &proc_dointvec_jiffies, &sysctl_jiffies},
+	{NET_IPV4_INET_PEER_GC_MAXTIME, "inet_peer_gc_maxtime",
+	 &inet_peer_gc_maxtime, sizeof(int), 0644, NULL,
+	 &proc_dointvec_jiffies, &sysctl_jiffies},
 	{0}
 };
 
diff -u --recursive --new-file v2.3.36/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.3.36/linux/net/ipv4/tcp_ipv4.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv4/tcp_ipv4.c	Thu Jan  6 10:14:36 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.192 1999/12/23 02:04:50 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.193 2000/01/06 00:42:01 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -595,7 +595,8 @@
 
 static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
 {
-	return secure_tcp_sequence_number(sk->saddr, sk->daddr,
+	return secure_tcp_sequence_number(skb->nh.iph->daddr,
+					  skb->nh.iph->saddr,
 					  skb->h.th->dest,
 					  skb->h.th->source);
 }
diff -u --recursive --new-file v2.3.36/linux/net/ipv6/ip6_output.c linux/net/ipv6/ip6_output.c
--- v2.3.36/linux/net/ipv6/ip6_output.c	Thu Aug 26 13:05:46 1999
+++ linux/net/ipv6/ip6_output.c	Thu Jan  6 10:14:36 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_output.c,v 1.22 1999/08/20 11:06:21 davem Exp $
+ *	$Id: ip6_output.c,v 1.23 2000/01/06 00:42:07 davem Exp $
  *
  *	Based on linux/net/ipv4/ip_output.c
  *
@@ -45,7 +45,17 @@
 #include <net/rawv6.h>
 #include <net/icmp.h>
 
-static u32	ipv6_fragmentation_id = 1;
+static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
+{
+	static u32 ipv6_fragmentation_id = 1;
+	static spinlock_t ip6_id_lock = SPIN_LOCK_UNLOCKED;
+
+	spin_lock_bh(&ip6_id_lock);
+	fhdr->identification = ipv6_fragmentation_id;
+	if (++ipv6_fragmentation_id == 0)
+		ipv6_fragmentation_id = 1;
+	spin_unlock_bh(&ip6_id_lock);
+}
 
 int ip6_output(struct sk_buff *skb)
 {
@@ -224,7 +234,7 @@
 
 	fhdr->reserved = 0;
 	fhdr->frag_off = htons(offset);
-	fhdr->identification = ipv6_fragmentation_id++;
+	ipv6_select_ident(skb, fhdr);
 	return &fhdr->nexthdr;
 }
 
diff -u --recursive --new-file v2.3.36/linux/net/ipv6/route.c linux/net/ipv6/route.c
--- v2.3.36/linux/net/ipv6/route.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv6/route.c	Thu Jan  6 10:14:36 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: route.c,v 1.42 1999/12/15 22:39:53 davem Exp $
+ *	$Id: route.c,v 1.43 2000/01/06 00:42:08 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -1544,6 +1544,9 @@
 	ci.rta_used = rt->u.dst.__use;
 	ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt);
 	ci.rta_error = rt->u.dst.error;
+	ci.rta_id = 0;
+	ci.rta_ts = 0;
+	ci.rta_tsage = 0;
 	RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
 	nlh->nlmsg_len = skb->tail - b;
 	return skb->len;
diff -u --recursive --new-file v2.3.36/linux/net/ipv6/sit.c linux/net/ipv6/sit.c
--- v2.3.36/linux/net/ipv6/sit.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv6/sit.c	Thu Jan  6 10:14:36 2000
@@ -6,7 +6,7 @@
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
- *	$Id: sit.c,v 1.34 1999/08/31 07:04:16 davem Exp $
+ *	$Id: sit.c,v 1.35 2000/01/06 00:42:08 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -544,7 +544,7 @@
 		iph->ttl	=	iph6->hop_limit;
 
 	iph->tot_len		=	htons(skb->len);
-	iph->id			=	htons(ip_id_count++);
+	ip_select_ident(iph, &rt->u.dst);
 	ip_send_check(iph);
 
 	stats->tx_bytes += skb->len;
diff -u --recursive --new-file v2.3.36/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.3.36/linux/net/ipv6/tcp_ipv6.c	Tue Jan  4 13:57:21 2000
+++ linux/net/ipv6/tcp_ipv6.c	Thu Jan  6 10:14:36 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.114 2000/01/03 17:19:17 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.115 2000/01/06 00:42:09 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -343,20 +343,17 @@
 
 static __u32 tcp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
 {
-	__u32 si;
-	__u32 di;
-
 	if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
-		si = skb->nh.ipv6h->saddr.s6_addr32[3];
-		di = skb->nh.ipv6h->daddr.s6_addr32[3];
+		return secure_tcpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32,
+						    skb->nh.ipv6h->saddr.s6_addr32,
+						    skb->h.th->dest,
+						    skb->h.th->source);
 	} else {
-		si = skb->nh.iph->saddr;
-		di = skb->nh.iph->daddr;
+		return secure_tcp_sequence_number(skb->nh.iph->daddr,
+						  skb->nh.iph->saddr,
+						  skb->h.th->dest,
+						  skb->h.th->source);
 	}
-
-	return secure_tcp_sequence_number(di, si,
-					  skb->h.th->dest,
-					  skb->h.th->source);
 }
 
 static int tcp_v6_check_established(struct sock *sk)
@@ -622,9 +619,9 @@
 	 */
 
 	if (!tp->write_seq)
-		tp->write_seq = secure_tcp_sequence_number(np->saddr.s6_addr32[3],
-							   np->daddr.s6_addr32[3],
-							   sk->sport, sk->dport);
+		tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
+							     np->daddr.s6_addr32,
+							     sk->sport, sk->dport);
 
 	err = tcp_connect(sk, buff);
 	if (err == 0)
diff -u --recursive --new-file v2.3.36/linux/net/netsyms.c linux/net/netsyms.c
--- v2.3.36/linux/net/netsyms.c	Tue Jan  4 13:57:21 2000
+++ linux/net/netsyms.c	Thu Jan  6 10:14:36 2000
@@ -28,6 +28,7 @@
 #endif
 #include <net/pkt_sched.h>
 #include <net/scm.h>
+#include <linux/random.h>
 
 #ifdef CONFIG_BRIDGE
 #include <net/br.h>
@@ -235,7 +236,7 @@
 EXPORT_SYMBOL(ip_options_undo);
 EXPORT_SYMBOL(arp_send);
 EXPORT_SYMBOL(arp_broken_ops);
-EXPORT_SYMBOL(ip_id_count);
+EXPORT_SYMBOL(__ip_select_ident);
 EXPORT_SYMBOL(ip_send_check);
 EXPORT_SYMBOL(ip_fragment);
 EXPORT_SYMBOL(inet_family_ops);
@@ -376,6 +377,12 @@
 #ifdef CONFIG_SYSCTL
 EXPORT_SYMBOL(sysctl_max_syn_backlog);
 #endif
+
+#if defined (CONFIG_IPV6_MODULE)
+EXPORT_SYMBOL(secure_tcpv6_sequence_number);
+EXPORT_SYMBOL(secure_ipv6_id);
+#endif
+
 #endif
 
 #ifdef CONFIG_NETLINK
