diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	Wed May 29 11:43:02 2002
+++ b/CREDITS	Wed May 29 11:43:02 2002
@@ -1513,6 +1513,13 @@
 S: 602 00 Brno
 S: Czech Republic
 
+N: Jakob Kemi
+E: jakob.kemi@telia.com
+D: V4L W9966 Webcam driver
+S: Forsbyvägen 33
+S: 74143 Knivsta
+S: Sweden
+
 N: Fred N. van Kempen
 E: waltje@linux.com
 D: NET-2
@@ -1682,13 +1689,6 @@
 S: ul. Matemblewska 1B/10
 S: 80-283 Gdansk
 S: Poland
-
-N: Jakob Kemi
-E: jakob.kemi@telia.com
-D: V4L W9966 Webcam driver
-S: Forsbyvägen 33
-S: 74143 Knivsta
-S: Sweden
 
 N: Gero Kuhlmann
 E: gero@gkminix.han.de
diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
--- a/Documentation/DocBook/Makefile	Wed May 29 11:43:03 2002
+++ b/Documentation/DocBook/Makefile	Wed May 29 11:43:03 2002
@@ -12,17 +12,12 @@
 PNG-parportbook := $(patsubst %.fig, %.png, $(IMG-parportbook))
 C-procfs-example = procfs_example.sgml
 
-$(TOPDIR)/scripts/docgen: dummy
-	chmod 755 $(TOPDIR)/scripts/docgen
+$(TOPDIR)/scripts/docgen $(TOPDIR)/scripts/gen-all-syms \
+$(TOPDIR)/scripts/kernel-doc $(TOPDIR)/scripts/docproc: doc-progs ;
 
-$(TOPDIR)/scripts/gen-all-syms: dummy
-	chmod 755 $(TOPDIR)/scripts/gen-all-syms
-
-$(TOPDIR)/scripts/kernel-doc: dummy
-	chmod 755 $(TOPDIR)/scripts/kernel-doc
-
-$(TOPDIR)/scripts/docproc: dummy
-	$(MAKE) -C $(TOPDIR)/scripts docproc
+.PHONY: doc-progs
+doc-progs:
+	@$(MAKE) -C $(TOPDIR)/scripts doc-progs
 
 $(BOOKS): $(TOPDIR)/scripts/docgen $(TOPDIR)/scripts/gen-all-syms \
 	  $(TOPDIR)/scripts/kernel-doc $(TOPDIR)/scripts/docproc
diff -Nru a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/block/biodoc.txt	Wed May 29 11:43:03 2002
@@ -0,0 +1,1190 @@
+	Notes on the Generic Block Layer Rewrite in Linux 2.5
+	=====================================================
+
+Notes Written on Jan 15, 2002:
+	Jens Axboe <axboe@suse.de>
+	Suparna Bhattacharya <suparna@in.ibm.com>
+
+Last Updated May 2, 2002
+
+Introduction:
+
+These are some notes describing some aspects of the 2.5 block layer in the
+context of the bio rewrite. The idea is to bring out some of the key
+changes and a glimpse of the rationale behind those changes.
+
+Please mail corrections & suggestions to suparna@in.ibm.com.
+
+Credits:
+---------
+
+2.5 bio rewrite:
+	Jens Axboe <axboe@suse.de>
+
+Many aspects of the generic block layer redesign were driven by and evolved
+over discussions, prior patches and the collective experience of several
+people. See sections 8 and 9 for a list of some related references.
+
+The following people helped with review comments and inputs for this
+document:
+	Christoph Hellwig <hch@infradead.org>
+	Arjan van de Ven <arjanv@redhat.com>
+	Randy Dunlap <rddunlap@osdl.org>
+	Andre Hedrick <andre@linux-ide.org>
+
+The following people helped with fixes/contributions to the bio patches
+while it was still work-in-progress:
+	David S. Miller <davem@redhat.com>
+
+
+Description of Contents:
+------------------------
+
+1. Scope for tuning of logic to various needs
+  1.1 Tuning based on device or low level driver capabilities
+	- Per-queue parameters
+	- Highmem I/O support
+	- I/O scheduler modularization
+  1.2 Tuning based on high level requirements/capabilities
+	1.2.1 I/O Barriers
+	1.2.2 Request Priority/Latency
+  1.3 Direct access/bypass to lower layers for diagnostics and special
+      device operations
+	1.3.1 Pre-built commands
+2. New flexible and generic but minimalist i/o structure or descriptor
+   (instead of using buffer heads at the i/o layer)
+  2.1 Requirements/Goals addressed
+  2.2 The bio struct in detail (multi-page io unit)
+  2.3 Changes in the request structure
+3. Using bios
+  3.1 Setup/teardown (allocation, splitting)
+  3.2 Generic bio helper routines
+    3.2.1 Traversing segments and completion units in a request
+    3.2.2 Setting up DMA scatterlists
+    3.2.3 I/O completion
+    3.2.4 Implications for drivers that do not interpret bios (don't handle
+ 	  multiple segments)
+    3.2.5 Request command tagging
+  3.3 I/O submission
+4. The I/O scheduler
+5. Scalability related changes
+  5.1 Granular locking: Removal of io_request_lock
+  5.2 Prepare for transition to 64 bit sector_t
+6. Other Changes/Implications
+  6.1 Partition re-mapping handled by the generic block layer
+7. A few tips on migration of older drivers
+8. A list of prior/related/impacted patches/ideas
+9. Other References/Discussion Threads
+
+---------------------------------------------------------------------------
+
+Bio Notes
+--------
+
+Let us discuss the changes in the context of how some overall goals for the
+block layer are addressed.
+
+1. Scope for tuning the generic logic to satisfy various requirements
+
+The block layer design supports adaptable abstractions to handle common
+processing with the ability to tune the logic to an appropriate extent
+depending on the nature of the device and the requirements of the caller.
+One of the objectives of the rewrite was to increase the degree of tunability
+and to enable higher level code to utilize underlying device/driver
+capabilities to the maximum extent for better i/o performance. This is
+important especially in the light of ever improving hardware capabilities
+and application/middleware software designed to take advantage of these
+capabilities.
+
+1.1 Tuning based on low level device / driver capabilities
+
+Sophisticated devices with large built-in caches, intelligent i/o scheduling
+optimizations, high memory DMA support, etc may find some of the
+generic processing an overhead, while for less capable devices the
+generic functionality is essential for performance or correctness reasons.
+Knowledge of some of the capabilities or parameters of the device should be
+used at the generic block layer to take the right decisions on
+behalf of the driver.
+
+How is this achieved ?
+
+Tuning at a per-queue level:
+
+i. Per-queue limits/values exported to the generic layer by the driver
+
+Various parameters that the generic i/o scheduler logic uses are set at
+a per-queue level (e.g maximum request size, maximum number of segments in
+a scatter-gather list, hardsect size)
+
+Some parameters that were earlier available as global arrays indexed by
+major/minor are now directly associated with the queue. Some of these may
+move into the block device structure in the future. Some characteristics
+have been incorporated into a queue flags field rather than separate fields
+in themselves.  There are blk_queue_xxx functions to set the parameters,
+rather than update the fields directly
+
+Some new queue property settings:
+
+	blk_queue_bounce_limit(q, u64 dma_address)
+		Enable I/O to highmem pages, dma_address being the
+		limit. No highmem default.
+
+	blk_queue_max_sectors(q, max_sectors)
+		Maximum size request you can handle in units of 512 byte
+		sectors. 255 default.
+
+	blk_queue_max_phys_segments(q, max_segments)
+		Maximum physical segments you can handle in a request. 128
+		default (driver limit). (See 3.2.2)
+
+	blk_queue_max_hw_segments(q, max_segments)
+		Maximum dma segments the hardware can handle in a request. 128
+		default (host adapter limit, after dma remapping).
+		(See 3.2.2)
+
+	blk_queue_max_segment_size(q, max_seg_size)
+		Maximum size of a clustered segment, 64kB default.
+
+	blk_queue_hardsect_size(q, hardsect_size)
+		Lowest possible sector size that the hardware can operate
+		on, 512 bytes default.
+
+New queue flags:
+
+	QUEUE_FLAG_CLUSTER (see 3.2.2)
+	QUEUE_FLAG_QUEUED (see 3.2.4)
+
+
+ii. High-mem i/o capabilities are now considered the default
+
+The generic bounce buffer logic, present in 2.4, where the block layer would
+by default copyin/out i/o requests on high-memory buffers to low-memory buffers
+assuming that the driver wouldn't be able to handle it directly, has been
+changed in 2.5. The bounce logic is now applied only for memory ranges
+for which the device cannot handle i/o. A driver can specify this by
+setting the queue bounce limit for the request queue for the device
+(blk_queue_bounce_limit()). This avoids the inefficiencies of the copyin/out
+where a device is capable of handling high memory i/o.
+
+In order to enable high-memory i/o where the device is capable of supporting
+it, the pci dma mapping routines and associated data structures have now been
+modified to accomplish a direct page -> bus translation, without requiring
+a virtual address mapping (unlike the earlier scheme of virtual address
+-> bus translation). So this works uniformly for high-memory pages (which
+do not have a correponding kernel virtual address space mapping) and
+low-memory pages.
+
+Note: Please refer to DMA-mapping.txt for a discussion on PCI high mem DMA
+aspects and mapping of scatter gather lists, and support for 64 bit PCI.
+
+Special handling is required only for cases where i/o needs to happen on
+pages at physical memory addresses beyond what the device can support. In these
+cases, a bounce bio representing a buffer from the supported memory range
+is used for performing the i/o with copyin/copyout as needed depending on
+the type of the operation.  For example, in case of a read operation, the
+data read has to be copied to the original buffer on i/o completion, so a
+callback routine is set up to do this, while for write, the data is copied
+from the original buffer to the bounce buffer prior to issuing the
+operation. Since an original buffer may be in a high memory area that's not
+mapped in kernel virtual addr, a kmap operation may be required for
+performing the copy, and special care may be needed in the completion path
+as it may not be in irq context. Special care is also required (by way of
+GFP flags) when allocating bounce buffers, to avoid certain highmem
+deadlock possibilities.
+
+It is also possible that a bounce buffer may be allocated from high-memory
+area that's not mapped in kernel virtual addr, but within the range that the
+device can use directly; so the bounce page may need to be kmapped during
+copy operations. [Note: This does not hold in the current implementation,
+though]
+
+There are some situations when pages from high memory may need to
+be kmapped, even if bounce buffers are not necessary. For example a device
+may need to abort DMA operations and revert to PIO for the transfer, in
+which case a virtual mapping of the page is required. For SCSI it is also
+done in some scenarios where the low level driver cannot be trusted to
+handle a single sg entry correctly. The driver is expected to perform the
+kmaps as needed on such occasions using the bio_kmap and bio_kmap_irq
+routines as appropriate. A driver could also use the blk_queue_bounce()
+routine on its own to bounce highmem i/o to low memory for specific requests
+if so desired.
+
+iii. The i/o scheduler algorithm itself can be replaced/set as appropriate
+
+As in 2.4, it is possible to plugin a brand new i/o scheduler for a particular
+queue or pick from (copy) existing generic schedulers and replace/override
+certain portions of it. The 2.5 rewrite provides improved modularization
+of the i/o scheduler. There are more pluggable callbacks, e.g for init,
+add request, extract request, which makes it possible to abstract specific
+i/o scheduling algorithm aspects and details outside of the generic loop.
+It also makes it possible to completely hide the implementation details of
+the i/o scheduler from block drivers.
+
+New routines to be used instead of accessing the queue directly:
+
+elv_add_request: Should be called to queue a request
+elv_next_request: Should be called to pull of the next request to be serviced
+  of the queue. It takes care of several things like skipping active requests,
+  invoking the command pre-builder etc.
+
+Some new plugins:
+e->elevator_next_req_fn
+	Plugin called to extract the next request to service from the
+	queue
+e->elevator_add_req_fn
+	Plugin called to add a new request to the queue
+e->elevator_init_fn
+	Plugin called when initializing the queue
+e->elevator_exit_fn
+	Plugin called when destrying the queue
+
+Elevator Linus and Elevator noop are the existing combinations that can be
+directly used, but a driver can provide relevant callbacks, in case
+it needs to do something different.
+
+Elevator noop only attempts to merge requests, but doesn't reorder (sort)
+them. Even merging requires a linear scan today (except for the last merged
+hint case discussed later) though, which takes take up some CPU cycles.
+
+[Note: Merging usually helps in general, because there's usually non-trivial
+command overhead associated with setting up and starting a command. Sorting,
+on the other hand, may not be relevant for intelligent devices that reorder
+requests anyway]
+
+Elevator Linus attempts merging as well as sorting of requests on the queue.
+The sorting happens via an insert scan whenever a request comes in.
+Often some sorting still makes sense as the depth which most hardware can
+handle may be less than the queue lengths during i/o loads.
+
+
+1.2 Tuning Based on High level code capabilities
+
+i. Application capabilities for raw i/o
+
+This comes from some of the high-performance database/middleware
+requirements where an application prefers to make its own i/o scheduling
+decisions based on an understanding of the access patterns and i/o
+characteristics
+
+ii. High performance filesystems or other higher level kernel code's
+capabilities
+
+Kernel components like filesystems could also take their own i/o scheduling
+decisions for optimizing performance. Journalling filesystems may need
+some control over i/o ordering.
+
+What kind of support exists at the generic block layer for this ?
+
+The flags and rw fields in the bio structure can be used for some tuning
+from above e.g indicating that an i/o is just a readahead request, or for
+marking  barrier requests (discussed next), or priority settings (currently
+unused). As far as user applications are concerned they would need an
+additional mechanism either via open flags or ioctls, or some other upper
+level mechanism to communicate such settings to block.
+
+1.2.1 I/O Barriers
+
+There is a way to enforce strict ordering for i/os through barriers.
+All requests before a barrier point must be serviced before the barrier
+request and any other requests arriving after the barrier will not be
+serviced until after the barrier has completed. This is useful for higher
+level control on write ordering, e.g flushing a log of committed updates
+to disk before the corresponding updates themselves.
+
+A flag in the bio structure, BIO_BARRIER is used to identify a barrier i/o.
+The generic i/o scheduler would make sure that it places the barrier request and
+all other requests coming after it after all the previous requests in the
+queue. Barriers may be implemented in different ways depending on the
+driver. A SCSI driver for example could make use of ordered tags to
+preserve the necessary ordering with a lower impact on throughput. For IDE
+this might be two sync cache flush: a pre and post flush when encountering
+a barrier write.
+
+There is a provision for queues to indicate what kind of barriers they
+can provide. This is as of yet unmerged, details will be added here once it
+is in the kernel.
+
+1.2.2 Request Priority/Latency
+
+Todo/Under discussion:
+Arjan's proposed request priority scheme allows higher levels some broad
+  control (high/med/low) over the priority  of an i/o request vs other pending
+  requests in the queue. For example it allows reads for bringing in an
+  executable page on demand to be given a higher priority over pending write
+  requests which haven't aged too much on the queue. Potentially this priority
+  could even be exposed to applications in some manner, providing higher level
+  tunability. Time based aging avoids starvation of lower priority
+  requests. Some bits in the bi_rw flags field in the bio structure are
+  intended to be used for this priority information.
+
+  Jens has an implementation of a simple deadline i/o scheduler that
+  makes a best effort attempt to start requests within a given expiry
+  time limit, along with trying to optimize disk seeks as in the current
+  elevator. It does this by sorting a request on two lists, one by
+  the deadline and one by the sector order. It employs a policy that
+  follows sector ordering as long as a deadline is not violated, and
+  tries to keep up with deadlines in so far as it can batch up to at
+  least a certain minimum number of sector ordered requests to reduce
+  arbitrary disk seeks. This implementation is constructed in a way
+  that makes it possible to support advanced compound i/o schedulers
+  as a combination of several low level schedulers with an overall
+  class-independent scheduler layered above.
+
+The current elevator scheme provides a latency bound over how many future
+requests can "pass" (get placed before) a given request, and this bound
+is determined by the request type (read, write). However, it doesn't
+prioritize a new request over existing requests in the queue based on its
+latency requirement. A new request could of course get serviced before
+earlier requests based on the position on disk which it accesses. This is
+due to the sort/merge in the  basic elevator scan logic, but irrespective
+of the request's own priority/latency value. Interestingly the elevator
+sequence or the latency bound setting of the new request is unaffected by the
+number of existing requests it has passed, i.e. doesn't depend on where
+it is positioned in the queue, but only on the number of requests that pass
+it in the future.
+
+
+1.3 Direct Access to Low level Device/Driver Capabilities (Bypass mode)
+    (e.g Diagnostics, Systems Management)
+
+There are situations where high-level code needs to have direct access to
+the low level device capabilities or requires the ability to issue commands
+to the device bypassing some of the intermediate i/o layers.
+These could, for example, be special control commands issued through ioctl
+interfaces, or could be raw read/write commands that stress the drive's
+capabilities for certain kinds of fitness tests. Having direct interfaces at
+multiple levels without having to pass through upper layers makes
+it possible to perform bottom up validation of the i/o path, layer by
+layer, starting from the media.
+
+The normal i/o submission interfaces, e.g submit_bio, could be bypassed
+for specially crafted requests which such ioctl or diagnostics
+interfaces would typically use, and the elevator add_request routine
+can instead be used to directly insert such requests in the queue or preferably
+the blk_do_rq routine can be used to place the request on the queue and
+wait for completion. Alternatively, sometimes the caller might just
+invoke a lower level driver specific interface with the request as a
+parameter.
+
+If the request is a means for passing on special information associated with
+the command, then such information is associated with the request->special
+field (rather than misuse the request->buffer field which is meant for the
+request data buffer's virtual mapping).
+
+For passing request data, the caller must build up a bio descriptor
+representing the concerned memory buffer if the underlying driver interprets
+bio segments or uses the block layer end*request* functions for i/o
+completion. Alternatively one could directly use the request->buffer field to
+specify the virtual address of the buffer, if the driver expects buffer
+addresses passed in this way and ignores bio entries for the request type
+involved. In the latter case, the driver would modify and manage the
+request->buffer, request->sector and request->nr_sectors or
+request->current_nr_sectors fields itself rather than using the block layer
+end_request or end_that_request_first completion interfaces.
+(See 2.3 or Documentation/bio/request.txt for a brief explanation of
+the request structure fields)
+
+[TBD: end_that_request_last should be usable even in this case;
+Perhaps an end_that_direct_request_first routine could be implemented to make
+handling direct requests easier for such drivers; Also for drivers that
+expect bios, a helper function could be provided for setting up a bio
+corresponding to a data buffer]
+
+<JENS: I dont understand the above, why is end_that_request_first() not
+usable? Or _last for that matter. I must be missing something>
+<SUP: What I meant here was that if the request doesn't have a bio, then
+ end_that_request_first doesn't modify nr_sectors or current_nr_sectors,
+ and hence can't be used for advancing request state settings on the
+ completion of partial transfers. The driver has to modify these fields 
+ directly by hand.
+ This is because end_that_request_first only iterates over the bio list,
+ and always returns 0 if there are none associated with the request.
+ _last works OK in this case, and is not a problem, as I mentioned earlier
+>
+
+1.3.1 Pre-built Commands
+
+A request can be created with a pre-built custom command  to be sent directly
+to the device. The cmd block in the request structure has room for filling
+in the command bytes. (i.e rq->cmd is now 16 bytes in size, and meant for
+command pre-building, and the type of the request is now indicated
+through rq->flags instead of via rq->cmd)
+
+The request structure flags can be set up to indicate the type of request
+in such cases (REQ_PC: direct packet command passed to driver, REQ_BLOCK_PC:
+packet command issued via blk_do_rq, REQ_SPECIAL: special request).
+
+It can help to pre-build device commands for requests in advance.
+Drivers can now specify a request prepare function (q->prep_rq_fn) that the
+block layer would invoke to pre-build device commands for a given request,
+or perform other preparatory processing for the request. This is routine is
+called by elv_next_request(), i.e. typically just before servicing a request.
+(The prepare function would not be called for requests that have REQ_DONTPREP
+enabled)
+
+Aside:
+  Pre-building could possibly even be done early, i.e before placing the
+  request on the queue, rather than construct the command on the fly in the
+  driver while servicing the request queue when it may affect latencies in
+  interrupt context or responsiveness in general. One way to add early
+  pre-building would be to do it whenever we fail to merge on a request.
+  Now REQ_NOMERGE is set in the request flags to skip this one in the future,
+  which means that it will not change before we feed it to the device. So
+  the pre-builder hook can be invoked there.
+
+
+2. Flexible and generic but minimalist i/o structure/descriptor.
+
+2.1 Reason for a new structure and requirements addressed
+
+Prior to 2.5, buffer heads were used as the unit of i/o at the generic block
+layer, and the low level request structure was associated with a chain of
+buffer heads for a contiguous i/o request. This led to certain inefficiencies
+when it came to large i/o requests and readv/writev style operations, as it
+forced such requests to be broken up into small chunks before being passed
+on to the generic block layer, only to be merged by the i/o scheduler
+when the underlying device was capable of handling the i/o in one shot.
+Also, using the buffer head as an i/o structure for i/os that didn't originate
+from the buffer cache unecessarily added to the weight of the descriptors
+which were generated for each such chunk.
+
+The following were some of the goals and expectations considered in the
+redesign of the block i/o data structure in 2.5.
+
+i.  Should be appropriate as a descriptor for both raw and buffered i/o  -
+    avoid cache related fields which are irrelevant in the direct/page i/o path,
+    or filesystem block size alignment restrictions which may not be relevant
+    for raw i/o.
+ii. Ability to represent high-memory buffers (which do not have a virtual
+    address mapping in kernel address space).
+iii.Ability to represent large i/os w/o unecessarily breaking them up (i.e
+    greater than PAGE_SIZE chunks in one shot)
+iv. At the same time, ability to retain independent identity of i/os from
+    different sources or i/o units requiring individual completion (e.g. for
+    latency reasons)
+v.  Ability to represent an i/o involving multiple physical memory segments
+    (including non-page aligned page fragments, as specified via readv/writev)
+    without unecessarily breaking it up, if the underlying device is capable of
+    handling it.
+vi. Preferably should be based on a memory descriptor structure that can be
+    passed around different types of subsystems or layers, maybe even
+    networking, without duplication or extra copies of data/descriptor fields
+    themselves in the process
+vii.Ability to handle the possibility of splits/merges as the structure passes
+    through layered drivers (lvm, md, evms), with minimal overhead.
+
+The solution was to define a new structure (bio)  for the block layer,
+instead of using the buffer head structure (bh) directly, the idea being
+avoidance of some associated baggage and limitations. The bio structure
+is uniformly used for all i/o at the block layer ; it forms a part of the
+bh structure for buffered i/o, and in the case of raw/direct i/o kiobufs are
+mapped to bio structures.
+
+2.2 The bio struct
+
+The bio structure uses a vector representation pointing to an array of tuples
+of <page, offset, len> to describe the i/o buffer, and has various other
+fields describing i/o parameters and state that needs to be maintained for
+performing the i/o.
+
+Notice that this representation means that a bio has no virtual address
+mapping at all (unlike buffer heads).
+
+struct bio_vec {
+       struct page     *bv_page;
+       unsigned short  bv_len;
+       unsigned short  bv_offset;
+};
+
+/*
+ * main unit of I/O for the block layer and lower layers (ie drivers)
+ */
+struct bio {
+       sector_t            bi_sector;
+       struct bio          *bi_next;    /* request queue link */
+       struct block_device *bi_bdev;	/* target device */
+       unsigned long       bi_flags;    /* status, command, etc */
+       unsigned long       bi_rw;       /* low bits: r/w, high: priority */
+
+       unsigned int	bi_vcnt;     /* how may bio_vec's */
+       unsigned int	bi_idx;		/* current index into bio_vec array */
+
+       unsigned int	bi_size;     /* total size in bytes */
+       unsigned short 	bi_phys_segments; /* segments after physaddr coalesce*/
+       unsigned short	bi_hw_segments; /* segments after DMA remapping */
+       unsigned int	bi_max;	     /* max bio_vecs we can hold
+                                        used as index into pool */
+       struct bio_vec   *bi_io_vec;  /* the actual vec list */
+       bio_end_io_t	*bi_end_io;  /* bi_end_io (bio) */
+       atomic_t		bi_cnt;	     /* pin count: free when it hits zero */
+       void             *bi_private;
+       bio_destructor_t *bi_destructor; /* bi_destructor (bio) */
+};
+
+With this multipage bio design:
+
+- Large i/os can be sent down in one go using a bio_vec list consisting
+  of an array of <page, offset, len> fragments (similar to the way fragments
+  are represented in the zero-copy network code)
+- Splitting of an i/o request across multiple devices (as in the case of
+  lvm or raid) is achieved by cloning the bio (where the clone points to
+  the same bi_io_vec array, but with the index and size accordingly modified)
+- A linked list of bios is used as before for unrelated merges (*) - this
+  avoids reallocs and makes independent completions easier to handle.
+- Code that traverses the req list needs to make a distinction between
+  segments of a request (bio_for_each_segment) and the distinct completion
+  units/bios (rq_for_each_bio).
+- Drivers which can't process a large bio in one shot can use the bi_idx
+  field to keep track of the next bio_vec entry to process.
+  (e.g a 1MB bio_vec needs to be handled in max 128kB chunks for IDE)
+  [TBD: Should preferably also have a bi_voffset and bi_vlen to avoid modifying
+   bi_offset an len fields]
+
+(*) unrelated merges -- a request ends up containing two or more bios that
+    didn't originate from the same place.
+
+bi_end_io() i/o callback gets called on i/o completion of the entire bio.
+
+At a lower level, drivers build a scatter gather list from the merged bios.
+The scatter gather list is in the form of an array of <page, offset, len>
+entries with their corresponding dma address mappings filled in at the
+appropriate time. As an optimization, contiguous physical pages can be
+covered by a single entry where <page> refers to the first page and <len>
+covers the range of pages (upto 16 contiguous pages could be covered this
+way). There is a helper routine (blk_rq_map_sg) which drivers can use to build
+the sg list.
+
+Note: Right now the only user of bios with more than one page is ll_rw_kio,
+which in turn means that only raw I/O uses it (direct i/o may not work
+right now). The intent however is to enable clustering of pages etc to
+become possible. The pagebuf abstraction layer from SGI also uses multi-page
+bios, but that is currently not included in the stock development kernels.
+The same is true of Andrew Morton's work-in-progress multipage bio writeout 
+and readahead patches.
+
+2.3 Changes in the Request Structure
+
+The request structure is the structure that gets passed down to low level
+drivers. The block layer make_request function builds up a request structure,
+places it on the queue and invokes the drivers request_fn. The driver makes
+use of block layer helper routine elv_next_request to pull the next request
+off the queue. Control or diagnostic functions might bypass block and directly
+invoke underlying driver entry points passing in a specially constructed
+request structure.
+
+Only some relevant fields (mainly those which changed or may be referred
+to in some of the discussion here) are listed below, not necessarily in
+the order in which they occur in the structure (see include/linux/blkdev.h)
+Refer to Documentation/bio/request.txt for details about all the request
+structure fields and a quick reference about the layers which are
+supposed to use or modify those fields.
+
+struct request {
+	struct list_head queuelist;  /* Not meant to be directly accessed by
+					the driver.
+					Used by q->elv_next_request_fn
+					rq->queue is gone
+					*/
+	.
+	.
+	unsigned char cmd[16]; /* prebuilt command data block */
+	unsigned long flags;   /* also includes earlier rq->cmd settings */
+	.
+	.
+	sector_t sector; /* this field is now of type sector_t instead of int
+			    preparation for 64 bit sectors */
+	.
+	.
+
+	/* Number of scatter-gather DMA addr+len pairs after
+	 * physical address coalescing is performed.
+	 */
+	unsigned short nr_phys_segments;
+
+	/* Number of scatter-gather addr+len pairs after
+	 * physical and DMA remapping hardware coalescing is performed.
+	 * This is the number of scatter-gather entries the driver
+	 * will actually have to deal with after DMA mapping is done.
+	 */
+	unsigned short nr_hw_segments;
+
+	/* Various sector counts */
+	unsigned long nr_sectors;  /* no. of sectors left: driver modifiable */
+	unsigned long hard_nr_sectors;  /* block internal copy of above */
+	unsigned int current_nr_sectors; /* no. of sectors left in the
+					   current segment:driver modifiable */
+	unsigned long hard_cur_sectors; /* block internal copy of the above */
+	.
+	.
+	int tag;	/* command tag associated with request */
+	void *special;  /* same as before */
+	char *buffer;   /* valid only for low memory buffers upto
+			 current_nr_sectors */
+	.
+	.
+	struct bio *bio, *biotail;  /* bio list instead of bh */
+	struct request_list *rl;
+}
+	
+See the rq_flag_bits definitions for an explanation of the various flags
+available. Some bits are used by the block layer or i/o scheduler.
+	
+The behaviour of the various sector counts are almost the same as before,
+except that since we have multi-segment bios, current_nr_sectors refers
+to the numbers of sectors in the current segment being processed which could
+be one of the many segments in the current bio (i.e i/o completion unit).
+The nr_sectors value refers to the total number of sectors in the whole
+request that remain to be transferred (no change). The purpose of the
+hard_xxx values is for block to remember these counts everytime it hands
+over the request to the driver. These values are updated by block on
+end_that_request_first, i.e. everytime the driver completes a part of the
+transfer and invokes block end*request helpers to mark this. The
+driver should not modify these values. The block layer sets up the
+nr_sectors and current_nr_sectors fields (based on the corresponding
+hard_xxx values and the number of bytes transferred) and updates it on
+every transfer that invokes end_that_request_first. It does the same for the
+buffer, bio, bio->bi_idx fields too.
+
+The buffer field is just a virtual address mapping of the current segment
+of the i/o buffer in cases where the buffer resides in low-memory. For high
+memory i/o, this field is not valid and must not be used by drivers.
+
+Code that sets up its own request structures and passes them down to
+a driver needs to be careful about interoperation with the block layer helper
+functions which the driver uses. (Section 1.3)
+
+3. Using bios
+
+3.1 Setup/Teardown
+
+There are routines for managing the allocation, and reference counting, and
+freeing of bios (bio_alloc, bio_get, bio_put).
+
+This makes use of Ingo Molnar's mempool implementation, which enables
+subsystems like bio to maintain their own reserve memory pools for guaranteed
+deadlock-free allocations during extreme VM load. For example, the VM
+subsystem makes use of the block layer to writeout dirty pages in order to be
+able to free up memory space, a case which needs careful handling. The
+allocation logic draws from the preallocated emergency reserve in situations
+where it cannot allocate through normal means. If the pool is empty and it
+can wait, then it would trigger action that would help free up memory or
+replenish the pool (without deadlocking) and wait for availability in the pool.
+If it is in IRQ context, and hence not in a position to do this, allocation
+could fail if the pool is empty. In general mempool always first tries to
+perform allocation without having to wait, even if it means digging into the
+pool as long it is not less that 50% full.
+
+On a free, memory is released to the pool or directly freed depending on
+the current availability in the pool. The mempool interface lets the
+subsystem specify the routines to be used for normal alloc and free. In the
+case of bio, these routines make use of the standard slab allocator.
+
+The caller of bio_alloc is expected to taken certain steps to avoid
+deadlocks, e.g. avoid trying to allocate more memory from the pool while
+already holding memory obtained from the pool.
+[TBD: This is a potential issue, though a rare possibility
+ in the bounce bio allocation that happens in the current code, since
+ it ends up allocating a second bio from the same pool while
+ holding the original bio ]
+
+Memory allocated from the pool should be released back within a limited
+amount of time (in the case of bio, that would be after the i/o is completed).
+This ensures that if part of the pool has been used up, some work (in this
+case i/o) must already be in progress and memory would be available when it
+is over. If allocating from multiple pools in the same code path, the order
+or hierarchy of allocation needs to be consistent, just the way one deals
+with multiple locks.
+
+The bio_alloc routine also needs to allocate the bio_vec_list (bvec_alloc())
+for a non-clone bio. There are the 6 pools setup for different size biovecs,
+so bio_alloc(gfp_mask, nr_iovecs) will allocate a vec_list of the
+given size from these slabs.
+
+The bi_destructor() routine takes into account the possibility of the bio
+having originated from a different source (see later discussions on
+n/w to block transfers and kvec_cb)
+
+The bio_get() routine may be used to hold an extra reference on a bio prior
+to i/o submission, if the bio fields are likely to be accessed after the
+i/o is issued (since the bio may otherwise get freed in case i/o completion
+happens in the meantime).
+
+The bio_clone() routine may be used to duplicate a bio, where the clone
+shares the bio_vec_list with the original bio (i.e. both point to the
+same bio_vec_list). This would typically be used for splitting i/o requests
+in lvm or md.
+
+3.2 Generic bio helper Routines
+
+3.2.1 Traversing segments and completion units in a request
+
+The macros bio_for_each_segment() and rq_for_each_bio() should be used for
+traversing the bios in the request list (drivers should avoid directly
+trying to do it themselves). Using these helpers should also make it easier
+to cope with block changes in the future.
+
+	rq_for_each_bio(bio, rq)
+		bio_for_each_segment(bio_vec, bio, i)
+			/* bio_vec is now current segment */
+
+I/O completion callbacks are per-bio rather than per-segment, so drivers
+that traverse bio chains on completion need to keep that in mind. Drivers
+which don't make a distinction between segments and completion units would
+need to be reorganized to support multi-segment bios.
+
+3.2.2 Setting up DMA scatterlists
+
+The blk_rq_map_sg() helper routine would be used for setting up scatter
+gather lists from a request, so a driver need not do it on its own.
+
+	nr_segments = blk_rq_map_sg(q, rq, scatterlist);
+
+The helper routine provides a level of abstraction which makes it easier
+to modify the internals of request to scatterlist conversion down the line
+without breaking drivers. The blk_rq_map_sg routine takes care of several
+things like collapsing physically contiguous segments (if QUEUE_FLAG_CLUSTER
+is set) and correct segment accounting to avoid exceeding the limits which
+the i/o hardware can handle, based on various queue properties.
+
+- Prevents a clustered segment from crossing a 4GB mem boundary
+- Avoids building segments that would exceed the number of physical
+  memory segments that the driver can handle (phys_segments) and the
+  number that the underlying hardware can handle at once, accounting for
+  DMA remapping (hw_segments)  (i.e. IOMMU aware limits).
+
+Routines which the low level driver can use to set up the segment limits:
+
+blk_queue_max_hw_segments() : Sets an upper limit of the maximum number of
+hw data segments in a request (i.e. the maximum number of address/length
+pairs the host adapter can actually hand to the device at once)
+
+blk_queue_max_phys_segments() : Sets an upper limit on the maximum number
+of physical data segments in a request (i.e. the largest sized scatter list
+a driver could handle)
+
+3.2.3 I/O completion
+
+The existing generic block layer helper routines end_request,
+end_that_request_first and end_that_request_last can be used for i/o
+completion (and setting things up so the rest of the i/o or the next
+request can be kicked of) as before. With the introduction of multi-page
+bio support, end_that_request_first requires an additional argument indicating
+the number of sectors completed.
+
+3.2.4 Implications for drivers that do not interpret bios (don't handle
+ multiple segments)
+
+Drivers that do not interpret bios e.g those which do not handle multiple
+segments and do not support i/o into high memory addresses (require bounce
+buffers) and expect only virtually mapped buffers, can access the rq->buffer
+field. As before the driver should use current_nr_sectors to determine the
+size of remaining data in the current segment (that is the maximum it can
+transfer in one go unless it interprets segments), and rely on the block layer
+end_request, or end_that_request_first/last to take care of all accounting
+and transparent mapping of the next bio segment when a segment boundary
+is crossed on completion of a transfer. (The end*request* functions should
+be used if only if the request has come down from block/bio path, not for
+direct access requests which only specify rq->buffer without a valid rq->bio)
+
+3.2.5 Generic request command tagging
+
+3.2.5.1 Tag helpers
+
+Block now offers some simple generic functionality to help support command
+queueing (typically known as tagged command queueing), ie manage more than
+one outstanding command on a queue at any given time.
+
+	blk_queue_init_tags(request_queue_t *q, int depth)
+
+	Initialize internal command tagging structures for a maximum
+	depth of 'depth'.
+
+	blk_queue_free_tags((request_queue_t *q)
+
+	Teardown tag info associated with the queue. This will be done
+	automatically by block if blk_queue_cleanup() is called on a queue
+	that is using tagging.
+
+The above are initialization and exit management, the main helpers during
+normal operations are:
+
+	blk_queue_start_tag(request_queue_t *q, struct request *rq)
+
+	Start tagged operation for this request. A free tag number between
+	0 and 'depth' is assigned to the request (rq->tag holds this number),
+	and 'rq' is added to the internal tag management. If the maximum depth
+	for this queue is already achieved (or if the tag wasn't started for
+	some other reason), 1 is returned. Otherwise 0 is returned.
+
+	blk_queue_end_tag(request_queue_t *q, struct request *rq)
+
+	End tagged operation on this request. 'rq' is removed from the internal
+	book keeping structures.
+
+To minimize struct request and queue overhead, the tag helpers utilize some
+of the same request members that are used for normal request queue management.
+This means that a request cannot both be an active tag and be on the queue
+list at the same time. blk_queue_start_tag() will remove the request, but
+the driver must remember to call blk_queue_end_tag() before signalling
+completion of the request to the block layer. This means ending tag
+operations before calling end_that_request_last()! For an example of a user
+of these helpers, see the IDE tagged command queueing support.
+
+Certain hardware conditions may dictate a need to invalidate the block tag
+queue. For instance, on IDE any tagged request error needs to clear both
+the hardware and software block queue and enable the driver to sanely restart
+all the outstanding requests. There's a third helper to do that:
+
+	blk_queue_invalidate_tags(request_queue_t *q)
+
+	Clear the internal block tag queue and readd all the pending requests
+	to the request queue. The driver will receive them again on the
+	next request_fn run, just like it did the first time it encountered
+	them.
+
+3.2.5.2 Tag info
+
+Some block functions exist to query current tag status or to go from a
+tag number to the associated request. These are, in no particular order:
+
+	blk_queue_tagged(q)
+
+	Returns 1 if the queue 'q' is using tagging, 0 if not.
+
+	blk_queue_tag_request(q, tag)
+
+	Returns a pointer to the request associated with tag 'tag'.
+
+	blk_queue_tag_depth(q)
+	
+	Return current queue depth.
+
+	blk_queue_tag_queue(q)
+
+	Returns 1 if the queue can accept a new queued command, 0 if we are
+	at the maximum depth already.
+
+	blk_queue_rq_tagged(rq)
+
+	Returns 1 if the request 'rq' is tagged.
+
+3.2.5.2 Internal structure
+
+Internally, block manages tags in the blk_queue_tag structure:
+
+	struct blk_queue_tag {
+		struct request **tag_index;	/* array or pointers to rq */
+		unsigned long *tag_map;		/* bitmap of free tags */
+		struct list_head busy_list;	/* fifo list of busy tags */
+		int busy;			/* queue depth */
+		int max_depth;			/* max queue depth */
+	};
+
+Most of the above is simple and straight forward, however busy_list may need
+a bit of explaining. Normally we don't care too much about request ordering,
+but in the event of any barrier requests in the tag queue we need to ensure
+that requests are restarted in the order they were queue. This may happen
+if the driver needs to use blk_queue_invalidate_tags().
+
+Tagging also defines a new request flag, REQ_QUEUED. This is set whenever
+a request is currently tagged. You should not use this flag directly,
+blk_rq_tagged(rq) is the portable way to do so.
+
+3.3 I/O Submission
+
+The routine submit_bio() is used to submit a single io. Higher level i/o
+routines make use of this:
+
+(a) Buffered i/o:
+The routine submit_bh() invokes submit_bio() on a bio corresponding to the
+bh, allocating the bio if required. ll_rw_block() uses submit_bh() as before.
+
+(b) Kiobuf i/o (for raw/direct i/o):
+The ll_rw_kio() routine breaks up the kiobuf into page sized chunks and
+maps the array to one or more multi-page bios, issuing submit_bio() to
+perform the i/o on each of these.
+
+The embedded bh array in the kiobuf structure has been removed and no
+preallocation of bios is done for kiobufs. [The intent is to remove the
+blocks array as well, but it's currently in there to kludge around direct i/o.]
+Thus kiobuf allocation has switched back to using kmalloc rather than vmalloc.
+
+Todo/Observation:
+
+ A single kiobuf structure is assumed to correspond to a contiguous range
+ of data, so brw_kiovec() invokes ll_rw_kio for each kiobuf in a kiovec.
+ So right now it wouldn't work for direct i/o on non-contiguous blocks.
+ This is to be resolved.  The eventual direction is to replace kiobuf
+ by kvec's.
+
+ Badari Pulavarty has a patch to implement direct i/o correctly using
+ bio and kvec.
+
+
+(c) Page i/o:
+Todo/Under discussion:
+
+ Andrew Morton's multi-page bio patches attempt to issue multi-page
+ writeouts (and reads) from the page cache, by directly building up
+ large bios for submission completely bypassing the usage of buffer
+ heads. This work is still in progress.
+
+ Christoph Hellwig had some code that uses bios for page-io (rather than
+ bh). This isn't included in bio as yet. Christoph was also working on a
+ design for representing virtual/real extents as an entity and modifying
+ some of the address space ops interfaces to utilize this abstraction rather
+ than buffer_heads. (This is somewhat along the lines of the SGI XFS pagebuf
+ abstraction, but intended to be as lightweight as possible).
+
+(d) Direct access i/o:
+Direct access requests that do not contain bios would be submitted differently
+as discussed earlier in section 1.3.
+
+Aside:
+
+  Kvec i/o:
+
+  Ben LaHaise's aio code uses a slighly different structure instead
+  of kiobufs, called a kvec_cb. This contains an array of <page, offset, len>
+  tuples (very much like the networking code), together with a callback function
+  and data pointer. This is embedded into a brw_cb structure when passed
+  to brw_kvec_async().
+
+  Now it should be possible to directly map these kvecs to a bio. Just as while
+  cloning, in this case rather than PRE_BUILT bio_vecs, we set the bi_io_vec
+  array pointer to point to the veclet array in kvecs.
+
+  TBD: In order for this to work, some changes are needed in the way multi-page
+  bios are handled today. The values of the tuples in such a vector passed in
+  from higher level code should not be modified by the block layer in the course
+  of its request processing, since that would make it hard for the higher layer
+  to continue to use the vector descriptor (kvec) after i/o completes. Instead,
+  all such transient state should either be maintained in the request structure,
+  and passed on in some way to the endio completion routine.
+
+
+4. The I/O scheduler
+
+The generic i/o scheduler algorithm attempts to sort/merge/batch requests for
+optimal disk scan and request servicing performance (based on generic
+principles and device capabilities), optimized for:
+i.   improved throughput
+ii.  improved latency
+iii. better utilization of h/w & CPU time
+
+Characteristics:
+
+i. Linked list for O(n) insert/merge (linear scan) right now
+
+This is just the same as it was in 2.4.
+
+There is however an added level of abstraction in the operations for adding
+and extracting a request to/from the queue, which makes it possible to
+try out alternative queue structures without changes to the users of the queue.
+Some things like head-active are thus now handled within elv_next_request
+making it possible to mark more than one request to be left alone.
+
+Aside:
+1. The use of a merge hash was explored to reduce merge times and to make
+   elevator_noop close to noop by avoiding the scan for merge. However the
+   complexity and locking issues introduced wasn't desirable especially as
+   with multi-page bios the incidence of merges is expected to be lower.
+2. The use of binomial/fibonacci heaps was explored to reduce the scan time;
+   however the idea was given up due to the complexity and added weight of
+   data structures, complications for handling barriers, as well as the
+   advantage of O(1) extraction and deletion (performance critical path) with
+   the existing list implementation vs heap based implementations.
+
+ii. Utilizes max_phys/hw_segments, and max_request_size  parameters, to merge
+    within the limits that the device can handle (See 3.2.2)
+
+iii. Last merge hint
+
+In 2.5, information about the last merge is saved as a hint for the subsequent
+request. This way, if sequential data is coming down the pipe, the hint can
+be used to speed up merges without going through a scan.
+
+iv. Handling barrier cases
+
+As mentioned earlier, barrier support is new to 2.5, and the i/o scheduler
+has been modified accordingly.
+
+When a barrier comes in, then since insert happens in the form of a
+linear scan, starting from the end, it just needs to be ensured that this
+and future scans stops barrier point. This is achieved by  skipping the
+entire merge/scan logic for a barrier request, so it gets placed at the
+end of the queue, and specifying a zero latency for the request containing
+the bio so that no future requests can pass it.
+
+v. Plugging the queue to batch requests in anticipation of opportunities for
+  merge/sort optimizations
+
+This is just the same as in 2.4 so far, though per-device unplugging
+support is anticipated for 2.5. Also with a priority-based i/o scheduler,
+such decisions could be based on request priorities.
+
+Plugging is an approach that the current i/o scheduling algorithm resorts to so
+that it collects up enough requests in the queue to be able to take
+advantage of the sorting/merging logic in the elevator. If the
+queue is empty when a request comes in, then it plugs the request queue
+(sort of like plugging the bottom of a vessel to get fluid to build up)
+till it fills up with a few more requests, before starting to service
+the requests. This provides an opportunity to merge/sort the requests before
+passing them down to the device. There are various conditions when the queue is
+unplugged (to open up the flow again), either through a scheduled task or
+could be on demand. For example wait_on_buffer sets the unplugging going
+(by running tq_disk) so the read gets satisfied soon. So in the read case,
+the queue gets explicitly unplugged as part of waiting for completion,
+in fact all queues get unplugged as a side-effect.
+
+Aside:
+  This is kind of controversial territory, as its not clear if plugging is
+  always the right thing to do. Devices typically have their own queues,
+  and allowing a big queue to build up in software, while letting the device be
+  idle for a while may not always make sense. The trick is to handle the fine
+  balance between when to plug and when to open up. Also now that we have
+  multi-page bios being queued in one shot, we may not need to wait to merge
+  a big request from the broken up pieces coming by.
+
+  Per-queue granularity unplugging (still a Todo) may help reduce some of the
+  concerns with just a single tq_disk flush approach. Something like
+  blk_kick_queue() to unplug a specific queue (right away ?)
+  or optionally, all queues, is in the plan.
+
+
+5. Scalability related changes
+
+5.1 Granular Locking: io_request_lock replaced by a per-queue lock
+
+The global io_request_lock has been removed as of 2.5, to avoid
+the scalability bottleneck it was causing, and has been replaced by more
+granular locking. The request queue structure has a pointer to the
+lock to be used for that queue. As a result, locking can now be
+per-queue, with a provision for sharing a lock across queues if
+necessary (e.g the scsi layer sets the queue lock pointers to the
+corresponding adapter lock, which results in a per host locking
+granularity). The locking semantics are the same, i.e. locking is
+still imposed by the block layer, grabbing the lock before
+request_fn execution which it means that lots of older drivers
+should still be SMP safe. Drivers are free to drop the queue
+lock themselves, if required. Drivers that explicitly used the
+io_request_lock for serialization need to be modified accordingly.
+Usually it's as easy as adding a global lock:
+
+	static spinlock_t my_driver_lock = SPIN_LOCK_UNLOCKED;
+
+and passing the address to that lock to blk_init_queue().
+
+5.2 64 bit sector numbers (sector_t prepares for 64 bit support)
+
+The sector number used in the bio structure has been changed to sector_t,
+which could be defined as 64 bit in preparation for 64 bit sector support.
+
+6. Other Changes/Implications
+
+6.1 Partition re-mapping handled by the generic block layer
+
+In 2.5 some of the gendisk/partition related code has been reorganized.
+Now the generic block layer performs partition-remapping early and thus
+provides drivers with a sector number relative to whole device, rather than
+having to take partition number into account in order to arrive at the true
+sector number. The routine blk_partition_remap() is invoked by
+generic_make_request even before invoking the queue specific make_request_fn,
+so the i/o scheduler also gets to operate on whole disk sector numbers. This
+should typically not require changes to block drivers, it just never gets
+to invoke its own partition sector offset calculations since all bios
+sent are offset from the beginning of the device.
+
+
+7. A Few Tips on Migration of older drivers
+
+Old-style drivers that just use CURRENT and ignores clustered requests,
+may not need much change.  The generic layer will automatically handle
+clustered requests, multi-page bios, etc for the driver.
+
+For a low performance driver or hardware that is PIO driven or just doesn't
+support scatter-gather changes should be minimal too.
+
+The following are some points to keep in mind when converting old drivers
+to bio.
+
+Drivers should use elv_next_request to pick up requests and are no longer
+supposed to handle looping directly over the request list.
+(struct request->queue has been removed)
+
+Now end_that_request_first takes an additional number_of_sectors argument.
+It used to handle always just the first buffer_head in a request, now
+it will loop and handle as many sectors (on a bio-segment granularity)
+as specified.
+
+Now bh->b_end_io is replaced by bio->bi_end_io, but most of the time the
+right thing to use is bio_endio(bio, uptodate) instead.
+
+If the driver is dropping the io_request_lock from its request_fn strategy,
+then it just needs to replace that with q->queue_lock instead.
+
+As described in Sec 1.1, drivers can set max sector size, max segment size
+etc per queue now. Drivers that used to define their own merge functions i
+to handle things like this can now just use the blk_queue_* functions at
+blk_init_queue time.
+
+Drivers no longer have to map a {partition, sector offset} into the
+correct absolute location anymore, this is done by the block layer, so
+where a driver received a request ala this before:
+
+	rq->rq_dev = mk_kdev(3, 5);	/* /dev/hda5 */
+	rq->sector = 0;			/* first sector on hda5 */
+
+  it will now see
+
+	rq->rq_dev = mk_kdev(3, 0);	/* /dev/hda */
+	rq->sector = 123128;		/* offset from start of disk */
+
+As mentioned, there is no virtual mapping of a bio. For DMA, this is
+not a problem as the driver probably never will need a virtual mapping.
+Instead it needs a bus mapping (pci_map_page for a single segment or
+use blk_rq_map_sg for scatter gather) to be able to ship it to the driver. For
+PIO drivers (or drivers that need to revert to PIO transfer once in a
+while (IDE for example)), where the CPU is doing the actual data
+transfer a virtual mapping is needed. If the driver supports highmem I/O,
+(Sec 1.1, (ii) ) it needs to use bio_kmap and bio_kmap_irq to temporarily
+map a bio into the virtual address space. See how IDE handles this with
+ide_map_buffer.
+
+
+8. Prior/Related/Impacted patches
+
+8.1. Earlier kiobuf patches (sct/axboe/chait/hch/mkp)
+- orig kiobuf & raw i/o patches (now in 2.4 tree)
+- direct kiobuf based i/o to devices (no intermediate bh's)
+- page i/o using kiobuf
+- kiobuf splitting for lvm (mkp)
+- elevator support for kiobuf request merging (axboe)
+8.2. Zero-copy networking (Dave Miller)
+8.3. SGI XFS - pagebuf patches - use of kiobufs
+8.4. Multi-page pioent patch for bio (Christoph Hellwig)
+8.5. Direct i/o implementation (Andrea Arcangeli) since 2.4.10-pre11
+8.6. Async i/o implementation patch (Ben LaHaise)
+8.7. EVMS layering design (IBM EVMS team)
+8.8. Larger page cache size patch (Ben LaHaise) and
+     Large page size (Daniel Phillips)
+    => larger contiguous physical memory buffers
+8.9. VM reservations patch (Ben LaHaise)
+8.10. Write clustering patches ? (Marcelo/Quintela/Riel ?)
+8.11. Block device in page cache patch (Andrea Archangeli) - now in 2.4.10+
+8.12. Multiple block-size transfers for faster raw i/o (Shailabh Nagar,
+      Badari)
+8.13  Priority based i/o scheduler - prepatches (Arjan van de Ven)
+8.14  IDE Taskfile i/o patch (Andre Hedrik)
+8.15  Multi-page writeout and readahead patches (Andrew Morton)
+8.16  Direct i/o patches for 2.5 using kvec and bio (Badari Pulavarthy)
+
+9. Other References:
+
+9.1 The Splice I/O Model - Larry McVoy (and subsequent discussions on lkml,
+and Linus' comments - Jan 2001)
+9.2 Discussions about kiobuf and bh design on lkml between sct, linus, alan
+et al - Feb-March 2001 (many of the initial thoughts that led to bio were
+brought up in this discusion thread)
+9.3 Discussions on mempool on lkml - Dec 2001.
+
diff -Nru a/Documentation/block/request.txt b/Documentation/block/request.txt
--- a/Documentation/block/request.txt	Wed May 29 11:43:02 2002
+++ b/Documentation/block/request.txt	Wed May 29 11:43:02 2002
@@ -1,7 +1,7 @@
 
 struct request documentation
 
-Jens Axboe <axboe@suse.de> 070102
+Jens Axboe <axboe@suse.de> 27/05/02
 
 1.0
 Index
@@ -68,6 +68,8 @@
 					of request
 
 unsigned int hard_cur_sectors	B	Used to keep current_nr_sectors sane
+
+int tag				DB	TCQ tag, if assigned
 
 void *special			D	Free to be used by driver
 
diff -Nru a/Documentation/fb/tridentfb.txt b/Documentation/fb/tridentfb.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/fb/tridentfb.txt	Wed May 29 11:43:03 2002
@@ -0,0 +1,49 @@
+Tridentfb is a framebuffer driver for some Trident chip based cards.
+
+The following list of chips is thought to be supported although not all are
+tested:
+
+those from the Image series with Cyber in their names - accelerated
+those with Blade in their names (Blade3D,CyberBlade...) - accelerated
+the newer CyberBladeXP family  - nonaccelerated
+
+Only PCI/AGP based cards are supported, none of the older Tridents.
+
+How to use it?
+==============
+Just do your usual console work :)
+
+When booting you can pass the following parameters
+==================================================
+
+noaccel - turns off acceleration (when it doesn't work for your card)
+accel - force text acceleration (for boards which by default are noacceled)
+
+fp	- use flat panel related stuff
+crt 	- assume monitor is present instead of fp
+
+center 	- for flat panels and resolutions smaller than native size center the
+	  image, otherwise use
+stretch
+
+memsize - integer value in Kb, use if your card's memory size is misdetected.
+	  look at the driver output to see what it says when initializing.
+memdiff - integer value in Kb,should be nonzero if your card reports
+	  more memory than it actually has.For instance mine is 192K less than
+	  detection says in all three BIOS selectable situations 2M, 4M, 8M.
+	  Only use if your video memory is taken from main memory hence of
+	  configurable size.Otherwise use memsize.
+	  If in some modes which barely fit the memory you see garbage at the bottom
+	  this might help by not letting change to that mode anymore.
+
+nativex - the width in pixels of the flat panel.If you know it (usually 1024
+	  800 or 1280) and it is not what the driver seems to detect use it.
+
+bpp  - bits per pixel (8,16 or 32)
+mode - a mode name like 800x600 (as described in Documentation/fb/modedb.txt)
+
+Using insane values for the above parameters will probably result in driver
+misbehaviour so take care(for instance memsize=12345678 or memdiff=23784 or
+nativex=93)
+
+Contact: jani@astechnix.ro
diff -Nru a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
--- a/Documentation/filesystems/Locking	Wed May 29 11:43:02 2002
+++ b/Documentation/filesystems/Locking	Wed May 29 11:43:02 2002
@@ -132,7 +132,7 @@
 	int (*writepage)(struct page *);
 	int (*readpage)(struct file *, struct page *);
 	int (*sync_page)(struct page *);
-	int (*writeback_mapping)(struct address_space *, int *nr_to_write);
+	int (*writepages)(struct address_space *, int *nr_to_write);
 	int (*vm_writeback)(struct page *, int *nr_to_write);
 	int (*set_page_dirty)(struct page *page);
 	int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
@@ -148,8 +148,9 @@
 			BKL	PageLocked(page)
 writepage:		no	yes, unlocks
 readpage:		no	yes, unlocks
+readpages:		no
 sync_page:		no	maybe
-writeback_mapping:	no
+writepages:		no
 vm_writeback:		no	yes
 set_page_dirty		no	no
 prepare_write:		no	yes
@@ -164,6 +165,8 @@
 	->readpage() unlocks the page, either synchronously or via I/O
 completion.
 
+	->readpages() populates the pagecache with the passed pages and starts I/O against them.  They come unlocked upon I/O completion.
+
 	->writepage() unlocks the page synchronously, before returning to
 the caller.  If the page has write I/O underway against it, writepage()
 should run SetPageWriteback() against the page prior to unlocking it.
@@ -178,12 +181,12 @@
 existing instances of this method ->sync_page() itself doesn't look
 well-defined...
 
-	->writeback_mapping() is used for periodic writeback and for
-systemcall-initiated sync operations. The address_space should start
-I/O against at least *nr_to_write pages.  *nr_to_write must be decremented
-for each page which is written.  *nr_to_write must not go negative (this
-will be relaxed later).  If nr_to_write is NULL, all dirty pages must
-be written.
+	->writepages() is used for periodic writeback and for syscall-initiated
+sync operations.  The address_space should start I/O against at least
+*nr_to_write pages.  *nr_to_write must be decremented for each page which is
+written.  The address_space implementation may write more (or less) pages
+than *nr_to_write asks for, but it should try to be reasonably close.  If
+nr_to_write is NULL, all dirty pages must be written.
 
 	->vm_writeback() is called from the VM.  The address_space should
 start I/O against at least *nr_to_write pages, including the passed page. As
diff -Nru a/Documentation/ide.txt b/Documentation/ide.txt
--- a/Documentation/ide.txt	Wed May 29 11:43:01 2002
+++ b/Documentation/ide.txt	Wed May 29 11:43:01 2002
@@ -212,7 +212,7 @@
 driver using the "options=" keyword to insmod, while replacing any ',' with
 ';'.  For example:
 
-	insmod ide.o options="ide0=serialize ide2=0x1e8;0x3ee;11"
+	insmod ide.o options="ide0=serialize ide1=serialize ide2=0x1e8;0x3ee;11"
 
 
 ================================================================================
@@ -220,50 +220,69 @@
 Summary of ide driver parameters for kernel "command line":
 ----------------------------------------------------------
  "hdx="  is recognized for all "x" from "a" to "h", such as "hdc".
+ 
  "idex=" is recognized for all "x" from "0" to "3", such as "ide1".
 
  "hdx=noprobe"		: drive may be present, but do not probe for it
+ 
  "hdx=none"		: drive is NOT present, ignore cmos and do not probe
+ 
  "hdx=nowerr"		: ignore the WRERR_STAT bit on this drive
+ 
  "hdx=cdrom"		: drive is present, and is a cdrom drive
+ 
  "hdx=cyl,head,sect"	: disk drive is present, with specified geometry
+ 
  "hdx=autotune"		: driver will attempt to tune interface speed
-				to the fastest PIO mode supported,
-				if possible for this drive only.
-				Not fully supported by all chipset types,
-				and quite likely to cause trouble with
-				older/odd IDE drives.
+			  to the fastest PIO mode supported,
+			  if possible for this drive only.
+			  Not fully supported by all chipset types,
+			  and quite likely to cause trouble with
+			  older/odd IDE drives.
+
  "hdx=slow"		: insert a huge pause after each access to the data
-				port. Should be used only as a last resort.
+			  port. Should be used only as a last resort.
+				
  "hdxlun=xx"		: set the drive last logical unit
 
  "idebus=xx"		: inform IDE driver of VESA/PCI bus speed in MHz,
-				where "xx" is between 20 and 66 inclusive,
-				used when tuning chipset PIO modes.
-				For PCI bus, 25 is correct for a P75 system,
-				30 is correct for P90,P120,P180 systems,
-				and 33 is used for P100,P133,P166 systems.
-				If in doubt, use idebus=33 for PCI.
-				As for VLB, it is safest to not specify it.
-				Bigger values are safer than smaller ones.
+			  where "xx" is between 20 and 66 inclusive,
+			  used when tuning chipset PIO modes.
+			  For PCI bus, 25 is correct for a P75 system,
+			  30 is correct for P90,P120,P180 systems,
+			  and 33 is used for P100,P133,P166 systems.
+			  If in doubt, use idebus=33 for PCI.
+			  As for VLB, it is safest to not specify it.
+			  Bigger values are safer than smaller ones.
 
  "idex=noprobe"		: do not attempt to access/use this interface
+ 
  "idex=base"		: probe for an interface at the addr specified,
-				where "base" is usually 0x1f0 or 0x170
-				and "ctl" is assumed to be "base"+0x206
+			  where "base" is usually 0x1f0 or 0x170
+			  and "ctl" is assumed to be "base"+0x206
+			  
  "idex=base,ctl"	: specify both base and ctl
+
  "idex=base,ctl,irq"	: specify base, ctl, and irq number
+ 
  "idex=autotune"	: driver will attempt to tune interface speed
-				to the fastest PIO mode supported,
-				for all drives on this interface.
-				Not fully supported by all chipset types,
-				and quite likely to cause trouble with
-				older/odd IDE drives.
- "idex=noautotune"	: driver will NOT attempt to tune interface speed
-				This is the default for most chipsets,
-				except the cmd640.
- "idex=serialize"	: do not overlap operations on idex and ide(x^1)
+			  to the fastest PIO mode supported,
+			  for all drives on this interface.
+			  Not fully supported by all chipset types,
+			  and quite likely to cause trouble with
+			  older/odd IDE drives.
+
+ "idex=noautotune"	: driver will NOT attempt to tune interface speed 
+			  This is the default for most chipsets,
+			  except the cmd640.
+				
+ "idex=serialize"	: do not overlap operations on idex. Please note
+			  that you will have to specify this option for
+			  both the respecitve primary and secondary channel
+			  to take effect.
+			
  "idex=reset"		: reset interface after probe
+ 
  "idex=dma"		: automatically configure/use DMA if possible.
 
 The following are valid ONLY on ide0, which usually corresponds to the first
@@ -304,6 +323,6 @@
 
 mlord@pobox.com
 --
-Wed Apr 17 22:52:44 CEST 2002 edited by Marcin Dalecki
 
-For current maintainers of this stuff, please see the linux/MAINTAINERS file.
+Wed Apr 17 22:52:44 CEST 2002 edited by Marcin Dalecki, the current
+maintainer.
diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt	Wed May 29 11:43:03 2002
+++ b/Documentation/kernel-parameters.txt	Wed May 29 11:43:03 2002
@@ -45,6 +45,7 @@
 	SERIAL	Serial support is enabled.
 	SMP 	The kernel is an SMP kernel.
 	SOUND	Appropriate sound system support is enabled.
+	SWSUSP  Software suspension is enabled.
 	V4L	Video For Linux support is enabled.
 	VGA 	The VGA console has been enabled.
 	VT	Virtual terminal support is enabled.
@@ -392,6 +393,8 @@
 			initial RAM disk.
 
 	nointroute	[IA-64]
+
+	noresume	[SWSUSP] Disables resume and restore original swap space.
  
 	no-scroll	[VGA]
 
@@ -518,6 +521,8 @@
 	reboot=		[BUGS=ix86]
 
 	reserve=	[KNL,BUGS] force the kernel to ignore some iomem area.
+
+	resume=		[SWSUSP] specify the partition device for software suspension.
 
 	riscom8=	[HW,SERIAL]
 
diff -Nru a/Documentation/sched-coding.txt b/Documentation/sched-coding.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/sched-coding.txt	Wed May 29 11:43:03 2002
@@ -0,0 +1,126 @@
+     Reference for various scheduler-related methods in the O(1) scheduler
+		Robert Love <rml@tech9.net>, MontaVista Software
+
+
+Note most of these methods are local to kernel/sched.c - this is by design.
+The scheduler is meant to be self-contained and abstracted away.  This document
+is primarily for understanding the scheduler, not interfacing to it.  Some of
+the discussed interfaces, however, are general process/scheduling methods.
+They are typically defined in include/linux/sched.h.
+
+
+Main Scheduling Methods
+-----------------------
+
+void load_balance(runqueue_t *this_rq, int idle)
+	Attempts to pull tasks from one cpu to another to balance cpu usage,
+	if needed.  This method is called explicitly if the runqueues are
+	inbalanced or periodically by the timer tick.  Prior to calling,
+	the current runqueue must be locked and interrupts disabled.
+
+void schedule()
+	The main scheduling function.  Upon return, the highest priority
+	process will be active.
+
+
+Locking
+-------
+
+Each runqueue has its own lock, rq->lock.  When multiple runqueues need
+to be locked, lock acquires must be ordered by ascending &runqueue value.
+
+A specific runqueue is locked via
+
+	task_rq_lock(task_t pid, unsigned long *flags)
+
+which disables preemption, disables interrupts, and locks the runqueue pid is
+running on.  Likewise,
+
+	task_rq_unlock(task_t pid, unsigned long *flags)
+
+unlocks the runqueue pid is running on, restores interrupts to their previous
+state, and reenables preemption.
+
+The routines
+
+	double_rq_lock(runqueue_t *rq1, runqueue_t *rq2)
+
+and
+
+	double_rq_unlock(runqueue_t *rq1, runqueue_t rq2)
+
+safely lock and unlock, respectively, the two specified runqueues.  They do
+not, however, disable and restore interrupts.  Users are required to do so
+manually before and after calls.
+
+
+Values
+------
+
+MAX_PRIO
+	The maximum priority of the system, stored in the task as task->prio.
+	Lower priorities are higher.  Normal (non-RT) priorities range from
+	MAX_RT_PRIO to (MAX_PRIO - 1).
+MAX_RT_PRIO
+	The maximum real-time priority of the system.  Valid RT priorities
+	range from 0 to (MAX_RT_PRIO - 1).
+MAX_USER_RT_PRIO
+	The maximum real-time priority that is exported to user-space.  Should
+	always be equal to or less than MAX_RT_PRIO.  Setting it less allows
+	kernel threads to have higher priorities than any user-space task.
+MIN_TIMESLICE
+MAX_TIMESLICE
+	Respectively, the minimum and maximum timeslices (quanta) of a process.
+
+Data
+----
+
+struct runqueue
+	The main per-CPU runqueue data structure.
+struct task_struct
+	The main per-process data structure.
+
+
+General Methods
+---------------
+
+cpu_rq(cpu)
+	Returns the runqueue of the specified cpu.
+this_rq()
+	Returns the runqueue of the current cpu.
+task_rq(pid)
+	Returns the runqueue which holds the specified pid.
+cpu_curr(cpu)
+	Returns the task currently running on the given cpu.
+rt_task(pid)
+	Returns true if pid is real-time, false if not.
+
+
+Process Control Methods
+-----------------------
+
+void set_user_nice(task_t *p, long nice)
+	Sets the "nice" value of task p to the given value.
+int setscheduler(pid_t pid, int policy, struct sched_param *param)
+	Sets the scheduling policy and parameters for the given pid.
+void set_cpus_allowed(task_t *p, unsigned long new_mask)
+	Sets a given task's CPU affinity and migrates it to a proper cpu.
+	Callers must have a valid reference to the task and assure the
+	task not exit prematurely.  No locks can be held during the call.
+set_task_state(tsk, state_value)
+	Sets the given task's state to the given value.
+set_current_state(state_value)
+	Sets the current task's state to the given value.
+void set_tsk_need_resched(struct task_struct *tsk)
+	Sets need_resched in the given task.
+void clear_tsk_need_resched(struct task_struct *tsk)
+	Clears need_resched in the given task.
+void set_need_resched()
+	Sets need_resched in the current task.
+void clear_need_resched()
+	Clears need_resched in the current task.
+int need_resched()
+	Returns true if need_resched is set in the current task, false
+	otherwise.
+yield()
+	Place the current process at the end of the runqueue and call schedule.
diff -Nru a/Documentation/sched-design.txt b/Documentation/sched-design.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/sched-design.txt	Wed May 29 11:43:03 2002
@@ -0,0 +1,165 @@
+		   Goals, Design and Implementation of the
+		      new ultra-scalable O(1) scheduler
+
+
+  This is an edited version of an email Ingo Molnar sent to
+  lkml on 4 Jan 2002.  It describes the goals, design, and
+  implementation of Ingo's new ultra-scalable O(1) scheduler.
+  Last Updated: 18 April 2002.
+
+
+Goal
+====
+
+The main goal of the new scheduler is to keep all the good things we know
+and love about the current Linux scheduler:
+
+ - good interactive performance even during high load: if the user
+   types or clicks then the system must react instantly and must execute
+   the user tasks smoothly, even during considerable background load.
+
+ - good scheduling/wakeup performance with 1-2 runnable processes.
+
+ - fairness: no process should stay without any timeslice for any
+   unreasonable amount of time. No process should get an unjustly high
+   amount of CPU time.
+
+ - priorities: less important tasks can be started with lower priority,
+   more important tasks with higher priority.
+
+ - SMP efficiency: no CPU should stay idle if there is work to do.
+
+ - SMP affinity: processes which run on one CPU should stay affine to
+   that CPU. Processes should not bounce between CPUs too frequently.
+
+ - plus additional scheduler features: RT scheduling, CPU binding.
+
+and the goal is also to add a few new things:
+
+ - fully O(1) scheduling. Are you tired of the recalculation loop
+   blowing the L1 cache away every now and then? Do you think the goodness
+   loop is taking a bit too long to finish if there are lots of runnable
+   processes? This new scheduler takes no prisoners: wakeup(), schedule(),
+   the timer interrupt are all O(1) algorithms. There is no recalculation
+   loop. There is no goodness loop either.
+
+ - 'perfect' SMP scalability. With the new scheduler there is no 'big'
+   runqueue_lock anymore - it's all per-CPU runqueues and locks - two
+   tasks on two separate CPUs can wake up, schedule and context-switch
+   completely in parallel, without any interlocking. All
+   scheduling-relevant data is structured for maximum scalability.
+
+ - better SMP affinity. The old scheduler has a particular weakness that
+   causes the random bouncing of tasks between CPUs if/when higher
+   priority/interactive tasks, this was observed and reported by many
+   people. The reason is that the timeslice recalculation loop first needs
+   every currently running task to consume its timeslice. But when this
+   happens on eg. an 8-way system, then this property starves an
+   increasing number of CPUs from executing any process. Once the last
+   task that has a timeslice left has finished using up that timeslice,
+   the recalculation loop is triggered and other CPUs can start executing
+   tasks again - after having idled around for a number of timer ticks.
+   The more CPUs, the worse this effect.
+
+   Furthermore, this same effect causes the bouncing effect as well:
+   whenever there is such a 'timeslice squeeze' of the global runqueue,
+   idle processors start executing tasks which are not affine to that CPU.
+   (because the affine tasks have finished off their timeslices already.)
+
+   The new scheduler solves this problem by distributing timeslices on a
+   per-CPU basis, without having any global synchronization or
+   recalculation.
+
+ - batch scheduling. A significant proportion of computing-intensive tasks
+   benefit from batch-scheduling, where timeslices are long and processes
+   are roundrobin scheduled. The new scheduler does such batch-scheduling
+   of the lowest priority tasks - so nice +19 jobs will get
+   'batch-scheduled' automatically. With this scheduler, nice +19 jobs are
+   in essence SCHED_IDLE, from an interactiveness point of view.
+
+ - handle extreme loads more smoothly, without breakdown and scheduling
+   storms.
+
+ - O(1) RT scheduling. For those RT folks who are paranoid about the
+   O(nr_running) property of the goodness loop and the recalculation loop.
+
+ - run fork()ed children before the parent. Andrea has pointed out the
+   advantages of this a few months ago, but patches for this feature
+   do not work with the old scheduler as well as they should,
+   because idle processes often steal the new child before the fork()ing
+   CPU gets to execute it.
+
+
+Design
+======
+
+the core of the new scheduler are the following mechanizms:
+
+ - *two*, priority-ordered 'priority arrays' per CPU. There is an 'active'
+   array and an 'expired' array. The active array contains all tasks that
+   are affine to this CPU and have timeslices left. The expired array
+   contains all tasks which have used up their timeslices - but this array
+   is kept sorted as well. The active and expired array is not accessed
+   directly, it's accessed through two pointers in the per-CPU runqueue
+   structure. If all active tasks are used up then we 'switch' the two
+   pointers and from now on the ready-to-go (former-) expired array is the
+   active array - and the empty active array serves as the new collector
+   for expired tasks.
+
+ - there is a 64-bit bitmap cache for array indices. Finding the highest
+   priority task is thus a matter of two x86 BSFL bit-search instructions.
+
+the split-array solution enables us to have an arbitrary number of active
+and expired tasks, and the recalculation of timeslices can be done
+immediately when the timeslice expires. Because the arrays are always
+access through the pointers in the runqueue, switching the two arrays can
+be done very quickly.
+
+this is a hybride priority-list approach coupled with roundrobin
+scheduling and the array-switch method of distributing timeslices.
+
+ - there is a per-task 'load estimator'.
+
+one of the toughest things to get right is good interactive feel during
+heavy system load. While playing with various scheduler variants i found
+that the best interactive feel is achieved not by 'boosting' interactive
+tasks, but by 'punishing' tasks that want to use more CPU time than there
+is available. This method is also much easier to do in an O(1) fashion.
+
+to establish the actual 'load' the task contributes to the system, a
+complex-looking but pretty accurate method is used: there is a 4-entry
+'history' ringbuffer of the task's activities during the last 4 seconds.
+This ringbuffer is operated without much overhead. The entries tell the
+scheduler a pretty accurate load-history of the task: has it used up more
+CPU time or less during the past N seconds. [the size '4' and the interval
+of 4x 1 seconds was found by lots of experimentation - this part is
+flexible and can be changed in both directions.]
+
+the penalty a task gets for generating more load than the CPU can handle
+is a priority decrease - there is a maximum amount to this penalty
+relative to their static priority, so even fully CPU-bound tasks will
+observe each other's priorities, and will share the CPU accordingly.
+
+the SMP load-balancer can be extended/switched with additional parallel
+computing and cache hierarchy concepts: NUMA scheduling, multi-core CPUs
+can be supported easily by changing the load-balancer. Right now it's
+tuned for my SMP systems.
+
+i skipped the prev->mm == next->mm advantage - no workload i know of shows
+any sensitivity to this. It can be added back by sacrificing O(1)
+schedule() [the current and one-lower priority list can be searched for a
+that->mm == current->mm condition], but costs a fair number of cycles
+during a number of important workloads, so i wanted to avoid this as much
+as possible.
+
+- the SMP idle-task startup code was still racy and the new scheduler
+triggered this. So i streamlined the idle-setup code a bit. We do not call
+into schedule() before all processors have started up fully and all idle
+threads are in place.
+
+- the patch also cleans up a number of aspects of sched.c - moves code
+into other areas of the kernel where it's appropriate, and simplifies
+certain code paths and data constructs. As a result, the new scheduler's
+code is smaller than the old one.
+
+	Ingo
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Wed May 29 11:43:01 2002
+++ b/MAINTAINERS	Wed May 29 11:43:01 2002
@@ -574,6 +574,11 @@
 L:	linux-fsdevel@vger.kernel.org
 S:	Maintained
 
+FILESYSTEMS (VFS and infrastructure)
+P:	Alexander Viro
+M:	viro@math.psu.edu
+S:	Maintained
+
 FPU EMULATOR
 P:	Bill Metzenthen
 M:	billm@suburbia.net
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Wed May 29 11:43:01 2002
+++ b/Makefile	Wed May 29 11:43:01 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 18
+SUBLEVEL = 19
 EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -110,56 +110,8 @@
 LIBS		=$(TOPDIR)/lib/lib.a
 SUBDIRS		=init kernel lib drivers mm fs net ipc sound
 
-DRIVERS-n :=
-DRIVERS-y :=
-DRIVERS-m :=
-DRIVERS-  :=
-
-DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
-DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o
-DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o
-DRIVERS-y += drivers/base/base.o \
-	drivers/char/char.o \
-	drivers/block/block.o \
-	drivers/misc/misc.o \
-	drivers/net/net.o \
-	drivers/media/media.o
-DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/built-in.o
-DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o
-DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o
-DRIVERS-$(CONFIG_FC4) += drivers/fc4/built-in.o
-DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o
-DRIVERS-$(CONFIG_FUSION) += drivers/message/message.o
-DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o
-
-ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),)
-DRIVERS-y += drivers/cdrom/driver.o
-endif
-
+DRIVERS-y 	= drivers/built-in.o
 DRIVERS-$(CONFIG_SOUND) += sound/sound.o
-DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o
-DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmcia/pcmcia.o
-DRIVERS-$(CONFIG_DIO) += drivers/dio/built-in.o
-DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o
-DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o
-DRIVERS-$(CONFIG_ALL_PPC) += drivers/macintosh/macintosh.o
-DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o
-DRIVERS-$(CONFIG_PNP) += drivers/pnp/pnp.o
-DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/built-in.o
-DRIVERS-$(CONFIG_VT) += drivers/video/video.o
-DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/built-in.o
-DRIVERS-$(CONFIG_TC) += drivers/tc/built-in.o
-DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
-DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
-DRIVERS-$(CONFIG_GAMEPORT) += drivers/input/gameport/gamedrv.o
-DRIVERS-$(CONFIG_SERIO) += drivers/input/serio/seriodrv.o
-DRIVERS-$(CONFIG_I2O) += drivers/message/message.o
-DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
-DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
-DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
-DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o
-DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o
-DRIVERS-$(CONFIG_ISDN) += drivers/isdn/vmlinux-obj.o
 
 DRIVERS := $(DRIVERS-y)
 
@@ -172,7 +124,7 @@
 # ---------------------------------------------------------------------------
 
 boot: vmlinux
-	@$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" AFLAGS="$(AFLAGS) $(AFLAGS_KERNEL)" -C arch/$(ARCH)/boot
+	@$(MAKE) -C arch/$(ARCH)/boot
 
 # Build vmlinux
 # ---------------------------------------------------------------------------
@@ -202,29 +154,40 @@
 	echo Generating build number
 	. scripts/mkversion > .tmpversion
 	mv -f .tmpversion .version
-	$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" AFLAGS="$(AFLAGS) $(AFLAGS_KERNEL)" -C init
+	$(MAKE) -C init
 	echo $(cmd_link_vmlinux)
 	$(cmd_link_vmlinux)
 	echo 'cmd_$@ := $(cmd_link_vmlinux)' > $(@D)/.$(@F).cmd
 	$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
 endef
 
-vmlinux: $(CONFIGURATION) $(vmlinux-objs) dummy
+vmlinux: $(CONFIGURATION) $(vmlinux-objs) FORCE
 	$(call if_changed_rule,link_vmlinux)
 
-#	The actual objects are generated when descending, make sure
-#	no implicit rule kicks in
+#	The actual objects are generated when descending, 
+#	make sure no implicit rule kicks in
 
-$(sort $(vmlinux-objs)): linuxsubdirs
-	@
+$(sort $(vmlinux-objs)): $(SUBDIRS) ;
 
 # 	Handle descending into subdirectories listed in $(SUBDIRS)
 
-.PHONY: linuxsubdirs
-linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS))
+.PHONY: $(SUBDIRS)
+$(SUBDIRS): FORCE include/linux/version.h include/config/MARKER
+	@$(MAKE) -C $@
+
+# Single targets
+# ---------------------------------------------------------------------------
 
-$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/linux/version.h include/config/MARKER
-	@$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" AFLAGS="$(AFLAGS) $(AFLAGS_KERNEL)" -C $(patsubst _dir_%, %, $@)
+%.s: %.c FORCE
+	@$(MAKE) -C $(@D) $(@F)
+%.i: %.c FORCE
+	@$(MAKE) -C $(@D) $(@F)
+%.o: %.c FORCE
+	@$(MAKE) -C $(@D) $(@F)
+%.s: %.S FORCE
+	@$(MAKE) -C $(@D) $(@F)
+%.o: %.S FORCE
+	@$(MAKE) -C $(@D) $(@F)
 
 # Configuration
 # ---------------------------------------------------------------------------
@@ -266,7 +229,10 @@
 	@echo Generating $@
 	@. scripts/mkversion_h $@ $(KERNELRELEASE) $(VERSION) $(PATCHLEVEL) $(SUBLEVEL)
 
-comma	:= ,
+# helpers built in scripts/
+
+scripts/mkdep scripts/split-include : FORCE
+	@$(MAKE) -C scripts
 
 # ---------------------------------------------------------------------------
 # Generate dependencies
@@ -275,11 +241,34 @@
 
 dep-files: scripts/mkdep archdep include/linux/version.h
 	scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
-	$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
+	@$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS))
 ifdef CONFIG_MODVERSIONS
 	$(MAKE) update-modverfile
 endif
 
+.PHONY: $(patsubst %,_sfdep_%,$(SUBDIRS))
+$(patsubst %,_sfdep_%,$(SUBDIRS)): FORCE
+	@$(MAKE) -C $(patsubst _sfdep_%, %, $@) fastdep
+
+# update modversions.h, but only if it would change
+update-modverfile:
+	@(echo "#ifndef _LINUX_MODVERSIONS_H";\
+	  echo "#define _LINUX_MODVERSIONS_H"; \
+	  echo "#include <linux/modsetver.h>"; \
+	  cd $(TOPDIR)/include/linux/modules; \
+	  for f in *.ver; do \
+	    if [ -f $$f ]; then echo "#include <linux/modules/$${f}>"; fi; \
+	  done; \
+	  echo "#endif"; \
+	) > $(TOPDIR)/include/linux/modversions.h.tmp
+	@if [ -r $(TOPDIR)/include/linux/modversions.h ] && cmp -s $(TOPDIR)/include/linux/modversions.h $(TOPDIR)/include/linux/modversions.h.tmp; then \
+		echo $(TOPDIR)/include/linux/modversions.h was not updated; \
+		rm -f $(TOPDIR)/include/linux/modversions.h.tmp; \
+	else \
+		echo $(TOPDIR)/include/linux/modversions.h was updated; \
+		mv -f $(TOPDIR)/include/linux/modversions.h.tmp $(TOPDIR)/include/linux/modversions.h; \
+	fi
+
 # ---------------------------------------------------------------------------
 # Modules
 
@@ -296,7 +285,7 @@
 
 .PHONY: $(patsubst %, _mod_%, $(SUBDIRS))
 $(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h include/config/MARKER
-	@$(MAKE) -C $(patsubst _mod_%, %, $@) CFLAGS="$(CFLAGS) $(CFLAGS_MODULE)" AFLAGS="$(AFLAGS) $(AFLAGS_MODULE)" modules
+	@$(MAKE) -C $(patsubst _mod_%, %, $@) modules
 
 #	Install modules
 
@@ -333,7 +322,7 @@
 # ---------------------------------------------------------------------------
 # Modules not configured
 
-modules modules_install: dummy
+modules modules_install: FORCE
 	@echo
 	@echo "The present kernel configuration has modules disabled."
 	@echo "Type 'make config' and enable loadable module support."
@@ -343,19 +332,6 @@
 
 endif # CONFIG_MODULES
 
-# ---------------------------------------------------------------------------
-
-include Rules.make
-
-# Build helpers in scripts/
-# FIXME: do that in scripts/Makefile?
-
-scripts/mkdep: scripts/mkdep.c
-	$(HOSTCC) $(HOSTCFLAGS) -o scripts/mkdep scripts/mkdep.c
-
-scripts/split-include: scripts/split-include.c
-	$(HOSTCC) $(HOSTCFLAGS) -o scripts/split-include scripts/split-include.c
-
 # Cleaning up
 # ---------------------------------------------------------------------------
 
@@ -480,25 +456,18 @@
 
 # Generate tags for editors
 
-TAGS: dummy
+TAGS: FORCE
 	{ find include/asm-${ARCH} -name '*.h' -print ; \
 	find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print ; \
 	find $(SUBDIRS) init -name '*.[ch]' ; } | grep -v SCCS | etags -
 
 # 	Exuberant ctags works better with -I
-tags: dummy
+tags: FORCE
 	CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__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 '*.[ch]' | xargs ctags $$CTAGSF -a
 
-# Targets which will only descend into one subdir, not trying
-# to link vmlinux afterwards
-# FIXME: anybody still using this?
-
-fs lib mm ipc kernel drivers net sound: dummy
-	$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" AFLAGS="$(AFLAGS) $(AFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)
-
 # Make a backup
 # FIXME anybody still using this?
 
@@ -520,3 +489,4 @@
 			       $(filter-out $(cmd_$(@F)),$(cmd_$(1)))),\
 	               @$(rule_$(1)))
 
+FORCE:
diff -Nru a/Rules.make b/Rules.make
--- a/Rules.make	Wed May 29 11:43:02 2002
+++ b/Rules.make	Wed May 29 11:43:02 2002
@@ -2,36 +2,25 @@
 # This file contains rules which are shared between multiple Makefiles.
 #
 
-#
-# False targets.
-#
-.PHONY: dummy
+# Some standard vars
 
-#
-# Special variables which should not be exported
-#
-unexport EXTRA_AFLAGS
-unexport EXTRA_CFLAGS
-unexport EXTRA_LDFLAGS
-unexport EXTRA_ARFLAGS
-unexport SUBDIRS
-unexport SUB_DIRS
-unexport ALL_SUB_DIRS
-unexport MOD_SUB_DIRS
-unexport O_TARGET
-
-unexport obj-y
-unexport obj-m
-unexport obj-n
-unexport obj-
-unexport export-objs
-unexport subdir-y
-unexport subdir-m
-unexport subdir-n
-unexport subdir-
-unexport mod-subdirs
+comma   := ,
+empty   :=
+space   := $(empty) $(empty)
 
-comma	:= ,
+# Figure out paths
+# ---------------------------------------------------------------------------
+# Find the path relative to the toplevel dir, $(RELDIR), and express
+# the toplevel dir as a relative path from this dir, $(TOPDIR_REL)
+
+ifeq ($(findstring $(TOPDIR),$(CURDIR)),)
+  # Can only happen when something is built out of tree
+  RELDIR := $(CURDIR)
+  TOPDIR_REL := $(TOPDIR)
+else
+  RELDIR := $(subst $(TOPDIR)/,,$(CURDIR))
+  TOPDIR_REL := $(subst $(space),,$(foreach d,$(subst /, ,$(RELDIR)),../))
+endif
 
 # Figure out what we need to build from the various variables
 # ===========================================================================
@@ -63,7 +52,7 @@
 # add it to $(subdir-m)
 
 both-m          := $(filter $(mod-subdirs), $(subdir-y))
-SUB_DIRS	:= $(subdir-y)
+SUB_DIRS	:= $(subdir-y) $(if $(BUILD_MODULES),$(subdir-m))
 MOD_SUB_DIRS	:= $(sort $(subdir-m) $(both-m))
 ALL_SUB_DIRS	:= $(sort $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-))
 
@@ -94,14 +83,14 @@
 subdir-obj-y := $(foreach o,$(obj-y),$(if $(filter-out $(o),$(notdir $(o))),$(o)))
 
 # Replace multi-part objects by their individual parts, look at local dir only
-real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(m)))
+real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(m))) $(EXTRA_TARGETS)
 real-objs-m := $(foreach m, $(obj-m), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(m)))
 
 # ==========================================================================
 #
 # Get things started.
 #
-first_rule: all_targets
+first_rule: vmlinux $(if $(BUILD_MODULES),$(obj-m))
 
 #
 # Common rules
@@ -110,38 +99,61 @@
 # Compile C sources (.c)
 # ---------------------------------------------------------------------------
 
-$(export-objs): export_flags := $(EXPORT_FLAGS)
+# FIXME: if we don't know if built-in or modular, assume built-in.
+# Only happens in Makefiles which override the default first_rule:
+modkern_cflags := $(CFLAGS_KERNEL)
+
+$(real-objs-y)      : modkern_cflags := $(CFLAGS_KERNEL)
+$(real-objs-y:.o=.i): modkern_cflags := $(CFLAGS_KERNEL)
+$(real-objs-y:.o=.s): modkern_cflags := $(CFLAGS_KERNEL)
+
+$(real-objs-m)      : modkern_cflags := $(CFLAGS_MODULE)
+$(real-objs-m:.o=.i): modkern_cflags := $(CFLAGS_MODULE)
+$(real-objs-m:.o=.s): modkern_cflags := $(CFLAGS_MODULE)
 
-c_flags = $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$(*F).o) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(export_flags)
+$(export-objs)      : export_flags   := $(EXPORT_FLAGS)
+$(export-objs:.o=.i): export_flags   := $(EXPORT_FLAGS)
+$(export-objs:.o=.s): export_flags   := $(EXPORT_FLAGS)
 
-cmd_cc_s_c = $(CC) $(c_flags) -S $< -o $@
+c_flags = $(CFLAGS) $(modkern_cflags) $(EXTRA_CFLAGS) $(CFLAGS_$(*F).o) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(export_flags)
 
-%.s: %.c dummy
+cmd_cc_s_c = $(CC) $(c_flags) -S -o $@ $< 
+
+%.s: %.c FORCE
 	$(call if_changed,cmd_cc_s_c)
 
-cmd_cc_i_c = $(CPP) $(c_flags) $< > $@
+cmd_cc_i_c = $(CPP) $(c_flags)   -o $@ $<
 
-%.i: %.c dummy
+%.i: %.c FORCE
 	$(call if_changed,cmd_cc_i_c)
 
 cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
 
-%.o: %.c dummy
+%.o: %.c FORCE
 	$(call if_changed,cmd_cc_o_c)
 
 # Compile assembler sources (.S)
 # ---------------------------------------------------------------------------
 
-a_flags = $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
+# FIXME (s.a.)
+modkern_aflags := $(AFLAGS_KERNEL)
+
+$(real-objs-y)      : modkern_aflags := $(AFLAGS_KERNEL)
+$(real-objs-y:.o=.s): modkern_aflags := $(AFLAGS_KERNEL)
+
+$(real-objs-m)      : modkern_aflags := $(AFLAGS_MODULE)
+$(real-objs-m:.o=.s): modkern_aflags := $(AFLAGS_MODULE)
 
-cmd_as_s_S = $(CPP) $(a_flags) $< > $@
+a_flags = $(AFLAGS) $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
 
-%.s: %.S dummy
+cmd_as_s_S = $(CPP) $(a_flags)   -o $@ $< 
+
+%.s: %.S FORCE
 	$(call if_changed,cmd_as_s_S)
 
 cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $<
 
-%.o: %.S dummy
+%.o: %.S FORCE
 	$(call if_changed,cmd_as_o_S)
 
 # FIXME
@@ -163,10 +175,10 @@
 # Build the compiled-in targets
 # ---------------------------------------------------------------------------
 
-all_targets: $(O_TARGET) $(L_TARGET) sub_dirs
+vmlinux: $(O_TARGET) $(L_TARGET) $(EXTRA_TARGETS) sub_dirs
 
 # To build objects in subdirs, we need to descend into the directories
-$(subdir-obj-y): sub_dirs
+$(sort $(subdir-obj-y)): sub_dirs ;
 
 #
 # Rule to compile a set of .o files into one .o file
@@ -177,7 +189,7 @@
 		      $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(obj-y), $^),\
 		      rm -f $@; $(AR) rcs $@)
 
-$(O_TARGET): $(obj-y) dummy
+$(O_TARGET): $(obj-y) FORCE
 	$(call if_changed,cmd_link_o_target)
 endif # O_TARGET
 
@@ -187,7 +199,7 @@
 ifdef L_TARGET
 cmd_link_l_target = rm -f $@; $(AR) $(EXTRA_ARFLAGS) rcs $@ $(obj-y)
 
-$(L_TARGET): $(obj-y) dummy
+$(L_TARGET): $(obj-y) FORCE
 	$(call if_changed,cmd_link_l_target)
 endif
 
@@ -202,16 +214,16 @@
 # 	foo.o: $(foo-objs)
 # but that's not so easy, so we rather make all composite objects depend
 # on the set of all their parts
-$(multi-used-y) : %.o: $(multi-objs-y) dummy
+$(multi-used-y) : %.o: $(multi-objs-y) FORCE
 	$(call if_changed,cmd_link_multi)
 
-$(multi-used-m) : %.o: $(multi-objs-m) dummy
+$(multi-used-m) : %.o: $(multi-objs-m) FORCE
 	$(call if_changed,cmd_link_multi)
 
 #
 # This make dependencies quickly
 #
-fastdep: dummy
+fastdep: FORCE
 	$(TOPDIR)/scripts/mkdep $(CFLAGS) $(EXTRA_CFLAGS) -- $(wildcard *.[chS]) > .depend
 ifdef ALL_SUB_DIRS
 	$(MAKE) $(patsubst %,_sfdep_%,$(ALL_SUB_DIRS)) _FASTDEP_ALL_SUB_DIRS="$(ALL_SUB_DIRS)"
@@ -227,53 +239,48 @@
 # A rule to make subdirectories
 #
 subdir-list = $(sort $(patsubst %,_subdir_%,$(SUB_DIRS)))
-sub_dirs: dummy $(subdir-list)
+sub_dirs: FORCE $(subdir-list)
 
 ifdef SUB_DIRS
-$(subdir-list) : dummy
+$(subdir-list) : FORCE
 	@$(MAKE) -C $(patsubst _subdir_%,%,$@)
 endif
 
 #
 # A rule to make modules
 #
-ifneq "$(strip $(obj-m))" ""
-MOD_DESTDIR := $(shell $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh)
-endif
-
 ifneq "$(strip $(MOD_SUB_DIRS))" ""
 .PHONY: $(patsubst %,_modsubdir_%,$(MOD_SUB_DIRS))
-$(patsubst %,_modsubdir_%,$(MOD_SUB_DIRS)) : dummy
+$(patsubst %,_modsubdir_%,$(MOD_SUB_DIRS)) : FORCE
 	@$(MAKE) -C $(patsubst _modsubdir_%,%,$@) modules
 
 .PHONY: $(patsubst %,_modinst_%,$(MOD_SUB_DIRS))
-$(patsubst %,_modinst_%,$(MOD_SUB_DIRS)) : dummy
+$(patsubst %,_modinst_%,$(MOD_SUB_DIRS)) : FORCE
 	@$(MAKE) -C $(patsubst _modinst_%,%,$@) modules_install
 endif
 
 .PHONY: modules
-modules: $(obj-m) dummy \
-	 $(patsubst %,_modsubdir_%,$(MOD_SUB_DIRS))
+modules: $(obj-m) FORCE $(patsubst %,_modsubdir_%,$(MOD_SUB_DIRS))
 
 .PHONY: _modinst__
-_modinst__: dummy
+_modinst__: FORCE
 ifneq "$(strip $(obj-m))" ""
-	mkdir -p $(MODLIB)/kernel/$(MOD_DESTDIR)
-	cp $(obj-m) $(MODLIB)/kernel/$(MOD_DESTDIR)
+	mkdir -p $(MODLIB)/kernel/$(RELDIR)
+	cp $(obj-m) $(MODLIB)/kernel/$(RELDIR)
 endif
 
 .PHONY: modules_install
-modules_install: _modinst__ \
-	 $(patsubst %,_modinst_%,$(MOD_SUB_DIRS))
+modules_install: _modinst__ $(patsubst %,_modinst_%,$(MOD_SUB_DIRS))
 
-#
-# A rule to do nothing
-#
-dummy:
+
+# Add FORCE to the prequisites of a target to force it to be always rebuilt.
+# ---------------------------------------------------------------------------
+.PHONY: FORCE
+FORCE:
 
 #
 # This is useful for testing
-#
+# FIXME: really?
 script:
 	$(SCRIPT)
 
@@ -290,12 +297,9 @@
 ifdef CONFIG_MODVERSIONS
 ifneq "$(strip $(export-objs))" ""
 
-MODINCL = $(TOPDIR)/include/linux/modules
-MODCURDIR = $(subst $(TOPDIR)/,,$(shell /bin/pwd))
-MODPREFIX = $(subst /,-,$(MODCURDIR))__
+MODINCL := $(TOPDIR)/include/linux/modules
+MODPREFIX := $(subst /,-,$(RELDIR))__
 
-# The -w option (enable warnings) for genksyms will return here in 2.1
-# So where has it gone?
 #
 # Added the SMP separator to stop module accidents between uniprocessor
 # and SMP Intel boxes - AC - from bits by Michael Chastain
@@ -322,30 +326,8 @@
 # updates .ver files but not modversions.h
 fastdep: $(addprefix $(MODINCL)/$(MODPREFIX),$(export-objs:.o=.ver))
 
-# updates .ver files and modversions.h like before (is this needed?)
-dep: fastdep update-modverfile
-
 endif # export-objs 
 
-# update modversions.h, but only if it would change
-update-modverfile:
-	@(echo "#ifndef _LINUX_MODVERSIONS_H";\
-	  echo "#define _LINUX_MODVERSIONS_H"; \
-	  echo "#include <linux/modsetver.h>"; \
-	  cd $(TOPDIR)/include/linux/modules; \
-	  for f in *.ver; do \
-	    if [ -f $$f ]; then echo "#include <linux/modules/$${f}>"; fi; \
-	  done; \
-	  echo "#endif"; \
-	) > $(TOPDIR)/include/linux/modversions.h.tmp
-	@if [ -r $(TOPDIR)/include/linux/modversions.h ] && cmp -s $(TOPDIR)/include/linux/modversions.h $(TOPDIR)/include/linux/modversions.h.tmp; then \
-		echo $(TOPDIR)/include/linux/modversions.h was not updated; \
-		rm -f $(TOPDIR)/include/linux/modversions.h.tmp; \
-	else \
-		echo $(TOPDIR)/include/linux/modversions.h was updated; \
-		mv -f $(TOPDIR)/include/linux/modversions.h.tmp $(TOPDIR)/include/linux/modversions.h; \
-	fi
-
 $(active-objs): $(TOPDIR)/include/linux/modversions.h
 
 else
@@ -362,7 +344,6 @@
 endif
 
 endif # CONFIG_MODULES
-
 
 #
 # include dependency files if they exist
diff -Nru a/arch/alpha/boot/Makefile b/arch/alpha/boot/Makefile
--- a/arch/alpha/boot/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/alpha/boot/Makefile	Wed May 29 11:43:02 2002
@@ -55,7 +55,7 @@
 
 bootp.o: ksize.h
 
-ksize.h: vmlinux.nh dummy
+ksize.h: vmlinux.nh FORCE
 	echo "#define KERNEL_SIZE `ls -l vmlinux.nh | awk '{print $$5}'`" > $@T
 ifdef INITRD
 	[ -f $(INITRD) ] || exit 1
@@ -98,4 +98,4 @@
 
 dep:
 
-dummy:
+FORCE:
diff -Nru a/arch/alpha/config.in b/arch/alpha/config.in
--- a/arch/alpha/config.in	Wed May 29 11:43:02 2002
+++ b/arch/alpha/config.in	Wed May 29 11:43:02 2002
@@ -259,7 +259,7 @@
 	"ELF		CONFIG_KCORE_ELF	\
 	 A.OUT		CONFIG_KCORE_AOUT" ELF
 fi
-if [ "$CONFIG_PROC_FS" != "n" -a "$CONFIG_ALPHA_SRM" = "y" ]; then
+if [ "$CONFIG_PROC_FS" != "n" ]; then
    tristate 'SRM environment through procfs' CONFIG_SRM_ENV
 fi
  
diff -Nru a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
--- a/arch/alpha/kernel/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/alpha/kernel/Makefile	Wed May 29 11:43:02 2002
@@ -1,15 +1,11 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-O_TARGET := kernel.o
+O_TARGET	:= kernel.o
+EXTRA_TARGETS	:= head.o
 
-EXTRA_AFLAGS := $(CFLAGS)
+EXTRA_AFLAGS	:= $(CFLAGS)
 
 export-objs := alpha_ksyms.o
 
@@ -97,7 +93,7 @@
 
 endif # GENERIC
 
-all: kernel.o head.o
+include $(TOPDIR)/Rules.make
 
 ASM_OFFSETS_H = $(TOPDIR)/include/asm-alpha/asm_offsets.h
 asm_offsets:
@@ -112,4 +108,3 @@
 clean::
 	rm -f check_asm
 
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
--- a/arch/alpha/kernel/alpha_ksyms.c	Wed May 29 11:43:01 2002
+++ b/arch/alpha/kernel/alpha_ksyms.c	Wed May 29 11:43:01 2002
@@ -58,11 +58,12 @@
 EXPORT_SYMBOL(probe_irq_mask);
 EXPORT_SYMBOL(screen_info);
 EXPORT_SYMBOL(perf_irq);
-#ifdef CONFIG_ALPHA_SRM
 EXPORT_SYMBOL(callback_getenv);
 EXPORT_SYMBOL(callback_setenv);
 EXPORT_SYMBOL(callback_save_env);
-#endif /* CONFIG_ALPHA_SRM */
+#ifdef CONFIG_ALPHA_GENERIC
+EXPORT_SYMBOL(alpha_using_srm);
+#endif /* CONFIG_ALPHA_GENERIC */
 
 /* platform dependent support */
 EXPORT_SYMBOL(_inb);
diff -Nru a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
--- a/arch/alpha/kernel/pci.c	Wed May 29 11:43:01 2002
+++ b/arch/alpha/kernel/pci.c	Wed May 29 11:43:01 2002
@@ -19,6 +19,7 @@
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/bootmem.h>
+#include <linux/cache.h>
 #include <asm/machvec.h>
 
 #include "proto.h"
@@ -121,8 +122,6 @@
 	{ 0 }
 };
 
-#define MAX(val1, val2)		((val1) > (val2) ? (val1) : (val2))
-#define ALIGN(val,align)	(((val) + ((align) - 1)) & ~((align) - 1))
 #define KB			1024
 #define MB			(1024*KB)
 #define GB			(1024*MB)
@@ -169,7 +168,7 @@
 		 */
 
 		/* Align to multiple of size of minimum base.  */
-		alignto = MAX(0x1000, align);
+		alignto = max(0x1000UL, align);
 		start = ALIGN(start, alignto);
 		if (hose->sparse_mem_base && size <= 7 * 16*MB) {
 			if (((start / (16*MB)) & 0x7) == 0) {
@@ -187,8 +186,6 @@
 
 	res->start = start;
 }
-#undef MAX
-#undef ALIGN
 #undef KB
 #undef MB
 #undef GB
diff -Nru a/arch/arm/Makefile b/arch/arm/Makefile
--- a/arch/arm/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/arm/Makefile	Wed May 29 11:43:02 2002
@@ -189,7 +189,7 @@
 
 ifeq ($(findstring y,$(CONFIG_ARCH_CLPS7500) $(CONFIG_ARCH_L7200)),y)
 SUBDIRS		+=drivers/acorn/char
-DRIVERS		+=drivers/acorn/char/acorn-char.o
+DRIVERS		+=drivers/acorn/char/built-in.o
 endif
 
 MAKEBOOT	 =$(MAKE) -C arch/$(ARCH)/boot
@@ -209,11 +209,8 @@
 
 vmlinux: arch/arm/vmlinux.lds
 
-arch/arm/vmlinux.lds: $(LDSCRIPT) dummy
+arch/arm/vmlinux.lds: $(LDSCRIPT) FORCE
 	@sed 's/TEXTADDR/$(TEXTADDR)/;s/DATAADDR/$(DATAADDR)/' $(LDSCRIPT) >$@
-
-arch/arm/kernel arch/arm/mm arch/arm/lib: dummy
-	$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)
 
 bzImage zImage zinstall Image bootpImage install: vmlinux
 	@$(MAKEBOOT) $@
diff -Nru a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
--- a/arch/arm/kernel/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/arm/kernel/Makefile	Wed May 29 11:43:03 2002
@@ -1,16 +1,13 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
+
+O_TARGET := kernel.o
 
 ENTRY_OBJ = entry-$(PROCESSOR).o
 
 AFLAGS_head.o := -DTEXTADDR=$(TEXTADDR)
 
-O_TARGET	:= kernel.o
-
 # Object file lists.
 
 obj-y		:= arch.o compat.o dma.o $(ENTRY_OBJ) entry-common.o irq.o   \
@@ -43,7 +40,7 @@
 obj-$(CONFIG_DEBUG_LL)	+= debug.o
 endif
 
-all: kernel.o $(head-y) init_task.o
+EXTRA_TARGETS := $(head-y) init_task.o
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
--- a/arch/arm/kernel/signal.c	Wed May 29 11:43:01 2002
+++ b/arch/arm/kernel/signal.c	Wed May 29 11:43:01 2002
@@ -51,42 +51,6 @@
 
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
-	int err = -EFAULT;;
-
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		goto out;
-
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-
-	/* If you change siginfo_t structure, please be sure
-	   this code is fixed accordingly.
-	   It should never copy any pad contained in the structure
-	   to avoid security leaks, but must copy the generic
-	   3 ints plus the relevant union member.  */
-	err = __put_user(from->si_signo, &to->si_signo);
-	err |= __put_user(from->si_errno, &to->si_errno);
-	err |= __put_user((short)from->si_code, &to->si_code);
-	/* First 32bits of unions are always present.  */
-	err |= __put_user(from->si_pid, &to->si_pid);
-	switch (from->si_code >> 16) {
-	case __SI_FAULT >> 16:
-		break;
-	case __SI_CHLD >> 16:
-		err |= __put_user(from->si_utime, &to->si_utime);
-		err |= __put_user(from->si_stime, &to->si_stime);
-		err |= __put_user(from->si_status, &to->si_status);
-	default:
-		err |= __put_user(from->si_uid, &to->si_uid);
-		break;
-	/* case __SI_RT: This is not generated by the kernel as of now.  */
-	}
-out:
-	return err;
-}
-
 /*
  * atomically swap in the new signal mask, and wait for a signal.
  */
diff -Nru a/arch/arm/mach-arc/Makefile b/arch/arm/mach-arc/Makefile
--- a/arch/arm/mach-arc/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/arm/mach-arc/Makefile	Wed May 29 11:43:02 2002
@@ -1,9 +1,6 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
 
 O_TARGET		:= arc.o
 
@@ -19,8 +16,8 @@
 
 obj-$(CONFIG_DEBUG_LL)	+= debug.o
 
-all: arc.o head.o
+EXTRA_TARGETS 		:= head.o
 
-include $(TOPDIR)/Rules.make
+AFLAGS_head.o		:= -DTEXTADDR=$(TEXTADDR)
 
-AFLAGS_head.o := -DTEXTADDR=$(TEXTADDR)
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/cris/Makefile b/arch/cris/Makefile
--- a/arch/cris/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/cris/Makefile	Wed May 29 11:43:03 2002
@@ -61,12 +61,6 @@
 LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a)
 LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC)
 
-arch/cris/kernel: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/cris/kernel
-
-arch/cris/mm: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/cris/mm
-
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
 vmlinux.bin: vmlinux
@@ -88,10 +82,10 @@
 
 clinux: vmlinux.bin decompress.bin rescue.bin
 
-decompress.bin: dummy
+decompress.bin: FORCE
 	@make -C arch/cris/boot/compressed decompress.bin
 
-rescue.bin: dummy
+rescue.bin: FORCE
 	@make -C arch/cris/boot/rescue rescue.bin
 
 zImage: vmlinux.bin
diff -Nru a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile
--- a/arch/cris/kernel/Makefile	Wed May 29 11:43:01 2002
+++ b/arch/cris/kernel/Makefile	Wed May 29 11:43:01 2002
@@ -2,15 +2,9 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-all: kernel.o head.o
-
-O_TARGET := kernel.o
+O_TARGET	:= kernel.o
+EXTRA_TARGETS	:= head.o
 
 export-objs := ksyms.o
 
diff -Nru a/arch/cris/kernel/signal.c b/arch/cris/kernel/signal.c
--- a/arch/cris/kernel/signal.c	Wed May 29 11:43:01 2002
+++ b/arch/cris/kernel/signal.c	Wed May 29 11:43:01 2002
@@ -518,9 +518,11 @@
  */	
 
 static inline void
-handle_signal(int canrestart, unsigned long sig, struct k_sigaction *ka,
+handle_signal(int canrestart, unsigned long sig,
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
+	struct k_sigaction *ka = &current->sig->action[sig-1];
+
 	/* Are we from a system call? */
 	if (canrestart) {
 		/* If so, check system call restarting.. */
@@ -580,7 +582,7 @@
 int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
 {
 	siginfo_t info;
-	struct k_sigaction *ka;
+	int signr;
 
 	/*
 	 * We want the common case to go fast, which
@@ -594,98 +596,10 @@
 	if (!oldset)
 		oldset = &current->blocked;
 
-	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sig->action[signr-1];
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP:
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				lock_kernel();
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(canrestart, signr, ka, &info, oldset, regs);
+		handle_signal(canrestart, signr, &info, oldset, regs);
 		return 1;
 	}
 
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
--- a/arch/i386/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/i386/Makefile	Wed May 29 11:43:02 2002
@@ -103,17 +103,9 @@
 DRIVERS	+= arch/i386/pci/pci.o
 endif
 
-arch/i386/kernel: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/i386/kernel
-
-arch/i386/mm: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/i386/mm
-
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
 vmlinux: arch/i386/vmlinux.lds
-
-FORCE: ;
 
 .PHONY: zImage bzImage compressed zlilo bzlilo zdisk bzdisk install \
 		clean archclean archmrproper archdep
diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/i386/kernel/Makefile	Wed May 29 11:43:02 2002
@@ -1,15 +1,8 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-EXTRA_AFLAGS	:= -traditional
-
-all: kernel.o head.o init_task.o
+EXTRA_TARGETS := head.o init_task.o
 
 O_TARGET := kernel.o
 
@@ -35,5 +28,7 @@
 obj-y += setup-visws.o
 obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
 endif
+
+EXTRA_AFLAGS	:= -traditional
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/kernel/acpi_wakeup.S b/arch/i386/kernel/acpi_wakeup.S
--- a/arch/i386/kernel/acpi_wakeup.S	Wed May 29 11:43:02 2002
+++ b/arch/i386/kernel/acpi_wakeup.S	Wed May 29 11:43:02 2002
@@ -262,7 +262,6 @@
 
 ENTRY(saved_magic)	.long	0
 ENTRY(saved_magic2)	.long	0	
-ENTRY(saved_videomode)	.long	0
 
 ALIGN
 # saved registers
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Wed May 29 11:43:02 2002
+++ b/arch/i386/kernel/entry.S	Wed May 29 11:43:02 2002
@@ -395,6 +395,11 @@
 BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
 BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
 BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
+
+#ifdef CONFIG_X86_MCE_P4THERMAL
+BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR)
+#endif
+
 #endif
 
 ENTRY(divide_error)
diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
--- a/arch/i386/kernel/head.S	Wed May 29 11:43:01 2002
+++ b/arch/i386/kernel/head.S	Wed May 29 11:43:01 2002
@@ -182,26 +182,19 @@
 	pushfl			# push EFLAGS
 	popl %eax		# get EFLAGS
 	movl %eax,%ecx		# save original EFLAGS
-	xorl $0x40000,%eax	# flip AC bit in EFLAGS
+	xorl $0x240000,%eax	# flip AC and ID bits in EFLAGS
 	pushl %eax		# copy to EFLAGS
 	popfl			# set EFLAGS
 	pushfl			# get new EFLAGS
 	popl %eax		# put it in eax
 	xorl %ecx,%eax		# change in flags
-	andl $0x40000,%eax	# check if AC bit changed
+	pushl %ecx		# restore original EFLAGS
+	popfl
+	testl $0x40000,%eax	# check if AC bit changed
 	je is386
 
 	movb $4,X86		# at least 486
-	movl %ecx,%eax
-	xorl $0x200000,%eax	# check ID flag
-	pushl %eax
-	popfl			# if we are on a straight 486DX, SX, or
-	pushfl			# 487SX we can't change it
-	popl %eax
-	xorl %ecx,%eax
-	pushl %ecx		# restore original EFLAGS
-	popfl
-	andl $0x200000,%eax
+	testl $0x200000,%eax	# check if ID bit changed
 	je is486
 
 	/* get vendor info */
@@ -227,18 +220,15 @@
 	movb %cl,X86_MASK
 	movl %edx,X86_CAPABILITY
 
-is486:
-	movl %cr0,%eax		# 486 or better
-	andl $0x80000011,%eax	# Save PG,PE,ET
-	orl $0x50022,%eax	# set AM, WP, NE and MP
+is486:	movl $0x50022,%ecx	# set AM, WP, NE and MP
 	jmp 2f
 
-is386:	pushl %ecx		# restore original EFLAGS
-	popfl
-	movl %cr0,%eax		# 386
+is386:	movl $2,%ecx		# set MP
+2:	movl %cr0,%eax
 	andl $0x80000011,%eax	# Save PG,PE,ET
-	orl $2,%eax		# set MP
-2:	movl %eax,%cr0
+	orl %ecx,%eax
+	movl %eax,%cr0
+
 	call check_x87
 	incb ready
 	lgdt gdt_descr
diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
--- a/arch/i386/kernel/i386_ksyms.c	Wed May 29 11:43:03 2002
+++ b/arch/i386/kernel/i386_ksyms.c	Wed May 29 11:43:03 2002
@@ -174,3 +174,5 @@
 
 extern int is_sony_vaio_laptop;
 EXPORT_SYMBOL(is_sony_vaio_laptop);
+
+EXPORT_SYMBOL(__PAGE_KERNEL);
diff -Nru a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
--- a/arch/i386/kernel/i8259.c	Wed May 29 11:43:03 2002
+++ b/arch/i386/kernel/i8259.c	Wed May 29 11:43:03 2002
@@ -407,7 +407,7 @@
 
 	/* thermal monitor LVT interrupt */
 #ifdef CONFIG_X86_MCE_P4THERMAL
-	set_intr_gate(THERMAL_APIC_VECTOR, smp_thermal_interrupt);
+	set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
 #endif
 #endif
 
diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
--- a/arch/i386/kernel/setup.c	Wed May 29 11:43:03 2002
+++ b/arch/i386/kernel/setup.c	Wed May 29 11:43:03 2002
@@ -168,6 +168,8 @@
 static int disable_x86_serial_nr __initdata = 1;
 static int disable_x86_fxsr __initdata = 0;
 
+unsigned long saved_videomode;
+
 extern unsigned long saved_videomode;
 
 /*
@@ -684,10 +686,8 @@
  	drive_info = DRIVE_INFO;
  	screen_info = SCREEN_INFO;
 	apm_info.bios = APM_BIOS_INFO;
-#ifdef CONFIG_ACPI_SLEEP
 	saved_videomode = VIDEO_MODE;
 	printk("Video mode to be used for restore is %lx\n", saved_videomode);
-#endif
 	if( SYS_DESC_TABLE.length != 0 ) {
 		MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
 		machine_id = SYS_DESC_TABLE.table[0];
diff -Nru a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
--- a/arch/i386/kernel/signal.c	Wed May 29 11:43:03 2002
+++ b/arch/i386/kernel/signal.c	Wed May 29 11:43:03 2002
@@ -18,9 +18,7 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
-#include <linux/tty.h>
 #include <linux/personality.h>
-#include <linux/binfmts.h>
 #include <linux/suspend.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
@@ -30,41 +28,6 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
-		int err;
-
-		/* If you change siginfo_t structure, please be sure
-		   this code is fixed accordingly.
-		   It should never copy any pad contained in the structure
-		   to avoid security leaks, but must copy the generic
-		   3 ints plus the relevant union member.  */
-		err = __put_user(from->si_signo, &to->si_signo);
-		err |= __put_user(from->si_errno, &to->si_errno);
-		err |= __put_user((short)from->si_code, &to->si_code);
-		/* First 32bits of unions are always present.  */
-		err |= __put_user(from->si_pid, &to->si_pid);
-		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
-		case __SI_CHLD >> 16:
-			err |= __put_user(from->si_utime, &to->si_utime);
-			err |= __put_user(from->si_stime, &to->si_stime);
-			err |= __put_user(from->si_status, &to->si_status);
-		default:
-			err |= __put_user(from->si_uid, &to->si_uid);
-			break;
-		/* case __SI_RT: This is not generated by the kernel as of now.  */
-		}
-		return err;
-	}
-}
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -535,9 +498,11 @@
  */	
 
 static void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
+	struct pt_regs * regs)
 {
+	struct k_sigaction *ka = &current->sig->action[sig-1];
+
 	/* Are we from a system call? */
 	if (regs->orig_eax >= 0) {
 		/* If so, check system call restarting.. */
@@ -584,7 +549,7 @@
 int do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
 	siginfo_t info;
-	struct k_sigaction *ka;
+	int signr;
 
 	/*
 	 * We want the common case to go fast, which
@@ -603,98 +568,8 @@
 	if (!oldset)
 		oldset = &current->blocked;
 
-	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->parent->pid;
-				info.si_uid = current->parent->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sig->action[signr-1];
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP: {
-				struct signal_struct *sig;
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				sig = current->parent->sig;
-				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-			}
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		/* Reenable any watchpoints before delivering the
 		 * signal to user space. The processor register will
 		 * have been cleared if the watchpoint triggered
@@ -703,7 +578,7 @@
 		__asm__("movl %0,%%db7"	: : "r" (current->thread.debugreg[7]));
 
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, ka, &info, oldset, regs);
+		handle_signal(signr, &info, oldset, regs);
 		return 1;
 	}
 
diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c
--- a/arch/i386/mm/init.c	Wed May 29 11:43:02 2002
+++ b/arch/i386/mm/init.c	Wed May 29 11:43:02 2002
@@ -177,71 +177,52 @@
 	}
 }
 
+unsigned long __PAGE_KERNEL = _PAGE_KERNEL;
+
 static void __init pagetable_init (void)
 {
-	unsigned long vaddr, end;
+	unsigned long vaddr, pfn;
 	pgd_t *pgd, *pgd_base;
 	int i, j, k;
 	pmd_t *pmd;
 	pte_t *pte, *pte_base;
 
-	/*
-	 * This can be zero as well - no problem, in that case we exit
-	 * the loops anyway due to the PTRS_PER_* conditions.
-	 */
-	end = (unsigned long)__va(max_low_pfn*PAGE_SIZE);
-
 	pgd_base = swapper_pg_dir;
 #if CONFIG_X86_PAE
 	for (i = 0; i < PTRS_PER_PGD; i++)
-		set_pgd(pgd_base + i, __pgd(1 + __pa(empty_zero_page)));
+		set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT));
 #endif
+	if (cpu_has_pse) {
+		set_in_cr4(X86_CR4_PSE);
+	}
+	if (cpu_has_pge) {
+		set_in_cr4(X86_CR4_PGE);
+		__PAGE_KERNEL |= _PAGE_GLOBAL;
+	}
+
 	i = __pgd_offset(PAGE_OFFSET);
+	pfn = 0;
 	pgd = pgd_base + i;
 
-	for (; i < PTRS_PER_PGD; pgd++, i++) {
-		vaddr = i*PGDIR_SIZE;
-		if (end && (vaddr >= end))
-			break;
+	for (; i < PTRS_PER_PGD && pfn < max_low_pfn; pgd++, i++) {
 #if CONFIG_X86_PAE
 		pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-		set_pgd(pgd, __pgd(__pa(pmd) + 0x1));
+		set_pgd(pgd, __pgd(__pa(pmd) | _PAGE_PRESENT));
 #else
-		pmd = (pmd_t *)pgd;
+		pmd = (pmd_t *) pgd;
 #endif
-		if (pmd != pmd_offset(pgd, 0))
-			BUG();
-		for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
-			vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
-			if (end && (vaddr >= end))
-				break;
+		for (j = 0; j < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, j++) {
 			if (cpu_has_pse) {
-				unsigned long __pe;
+				set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE));
+				pfn += PTRS_PER_PTE;
+			} else {
+				pte_base = pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
 
-				set_in_cr4(X86_CR4_PSE);
-				boot_cpu_data.wp_works_ok = 1;
-				__pe = _KERNPG_TABLE + _PAGE_PSE + __pa(vaddr);
-				/* Make it "global" too if supported */
-				if (cpu_has_pge) {
-					set_in_cr4(X86_CR4_PGE);
-					__pe += _PAGE_GLOBAL;
-				}
-				set_pmd(pmd, __pmd(__pe));
-				continue;
-			}
-
-			pte_base = pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+				for (k = 0; k < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, k++)
+					set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
 
-			for (k = 0; k < PTRS_PER_PTE; pte++, k++) {
-				vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE;
-				if (end && (vaddr >= end))
-					break;
-				*pte = pfn_pte(__pa(vaddr) >> PAGE_SHIFT, PAGE_KERNEL);
+				set_pmd(pmd, __pmd(__pa(pte_base) | _KERNPG_TABLE));
 			}
-			set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base)));
-			if (pte_base != pte_offset_kernel(pmd, 0))
-				BUG();
-
 		}
 	}
 
@@ -358,13 +339,16 @@
 
 void __init test_wp_bit(void)
 {
-/*
- * Ok, all PSE-capable CPUs are definitely handling the WP bit right.
- */
 	const unsigned long vaddr = PAGE_OFFSET;
 	pgd_t *pgd;
 	pmd_t *pmd;
 	pte_t *pte, old_pte;
+
+	if (cpu_has_pse) {
+		/* Ok, all PSE-capable CPUs are definitely handling the WP bit right. */
+		boot_cpu_data.wp_works_ok = 1;
+		return;
+	}
 
 	printk("Checking if this processor honours the WP bit even in supervisor mode... ");
 
diff -Nru a/arch/ia64/Config.help b/arch/ia64/Config.help
--- a/arch/ia64/Config.help	Wed May 29 11:43:02 2002
+++ b/arch/ia64/Config.help	Wed May 29 11:43:02 2002
@@ -400,7 +400,7 @@
   Select your IA64 processor type.  The default is Intel Itanium.
 
 CONFIG_MCKINLEY
-  Select this to configure for a McKinley processor.
+  Select this to configure for an Itanium 2 (McKinley) processor.
 
 CONFIG_IA64_GENERIC
   This selects the system type of your hardware.  A "generic" kernel
diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile
--- a/arch/ia64/Makefile	Wed May 29 11:43:01 2002
+++ b/arch/ia64/Makefile	Wed May 29 11:43:01 2002
@@ -69,13 +69,6 @@
 				$(CORE_FILES)
 endif
 
-ifdef CONFIG_IA64_SOFTSDV
-        SUBDIRS         :=      arch/$(ARCH)/dig	\
-				$(SUBDIRS)
-        CORE_FILES      :=      arch/$(ARCH)/dig/dig.a	\
-				$(CORE_FILES)
-endif
-
 ifdef CONFIG_IA64_DIG
         SUBDIRS         :=      arch/$(ARCH)/dig	\
 				$(SUBDIRS)
@@ -105,8 +98,6 @@
 arch/$(ARCH)/vmlinux.lds: arch/$(ARCH)/vmlinux.lds.S FORCE
 	$(CPP) -D__ASSEMBLY__ -C -P -I$(HPATH) -I$(HPATH)/asm-$(ARCH) \
 		-traditional arch/$(ARCH)/vmlinux.lds.S > $@
-
-FORCE: ;
 
 compressed: vmlinux
 	$(OBJCOPY) --strip-all vmlinux vmlinux-tmp
diff -Nru a/arch/ia64/config.in b/arch/ia64/config.in
--- a/arch/ia64/config.in	Wed May 29 11:43:03 2002
+++ b/arch/ia64/config.in	Wed May 29 11:43:03 2002
@@ -16,7 +16,7 @@
 
 choice 'IA-64 processor type' \
 	"Itanium			CONFIG_ITANIUM \
-	 McKinley			CONFIG_MCKINLEY" Itanium
+	 Itanium-2			CONFIG_MCKINLEY" Itanium
 
 choice 'IA-64 system type'					\
 	"generic		CONFIG_IA64_GENERIC		\
@@ -26,11 +26,18 @@
 	 SGI-SN1		CONFIG_IA64_SGI_SN1		\
 	 SGI-SN2		CONFIG_IA64_SGI_SN2" generic
 
-choice 'Kernel page size'						\
+if [ "$CONFIG_ITANIUM" = "y" ]; then
+  choice 'Kernel page size'						\
+	"4KB			CONFIG_IA64_PAGE_SIZE_4KB		\
+	 8KB			CONFIG_IA64_PAGE_SIZE_8KB		\
+	 16KB			CONFIG_IA64_PAGE_SIZE_16KB" 16KB
+else
+  choice 'Kernel page size'						\
 	"4KB			CONFIG_IA64_PAGE_SIZE_4KB		\
 	 8KB			CONFIG_IA64_PAGE_SIZE_8KB		\
 	 16KB			CONFIG_IA64_PAGE_SIZE_16KB		\
 	 64KB			CONFIG_IA64_PAGE_SIZE_64KB" 16KB
+fi
 
 if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
   define_bool CONFIG_ACPI y
diff -Nru a/arch/ia64/dig/Makefile b/arch/ia64/dig/Makefile
--- a/arch/ia64/dig/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/ia64/dig/Makefile	Wed May 29 11:43:02 2002
@@ -5,13 +5,9 @@
 # Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
 #
 
-all: dig.a
-
 O_TARGET := dig.a
 
 obj-y := setup.o
 obj-$(CONFIG_IA64_GENERIC) += machvec.o
-
-clean::
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/ia64/hp/common/Makefile b/arch/ia64/hp/common/Makefile
--- a/arch/ia64/hp/common/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/ia64/hp/common/Makefile	Wed May 29 11:43:02 2002
@@ -12,17 +12,3 @@
 obj-y := sba_iommu.o
 
 include $(TOPDIR)/Rules.make
-#
-# ia64/platform/hp/common/Makefile
-#
-# Copyright (C) 2002 Hewlett Packard
-# Copyright (C) Alex Williamson (alex_williamson@hp.com)
-#
-
-O_TARGET := common.o
-
-export-objs := sba_iommu.o
-
-obj-y := sba_iommu.o
-
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
--- a/arch/ia64/hp/common/sba_iommu.c	Wed May 29 11:43:02 2002
+++ b/arch/ia64/hp/common/sba_iommu.c	Wed May 29 11:43:02 2002
@@ -1389,6 +1389,12 @@
 	return ((unsigned long)sba_sg_iova(sg));
 }
 
+int
+sba_dma_supported (struct pci_dev *dev, u64 mask)
+{
+	return 1;
+}
+
 /**************************************************************
 *
 *   Initialization and claim
@@ -1858,5 +1864,6 @@
 EXPORT_SYMBOL(sba_map_sg);
 EXPORT_SYMBOL(sba_unmap_sg);
 EXPORT_SYMBOL(sba_dma_address);
+EXPORT_SYMBOL(sba_dma_supported);
 EXPORT_SYMBOL(sba_alloc_consistent);
 EXPORT_SYMBOL(sba_free_consistent);
diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
--- a/arch/ia64/hp/sim/simserial.c	Wed May 29 11:43:03 2002
+++ b/arch/ia64/hp/sim/simserial.c	Wed May 29 11:43:03 2002
@@ -7,9 +7,9 @@
  * case means sys_sim.c console (goes via the simulator). The code hereafter
  * is completely leveraged from the serial.c driver.
  *
- * Copyright (C) 1999-2000 Hewlett-Packard Co
- * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2000, 2002 Hewlett-Packard Co
+ *	Stephane Eranian <eranian@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * 02/04/00 D. Mosberger	Merged in serial.c bug fixes in rs_close().
  * 02/25/00 D. Mosberger	Synced up with 2.3.99pre-5 version of serial.c.
@@ -24,7 +24,7 @@
 #include <linux/major.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/console.h>
 #include <linux/module.h>
 #include <linux/serial.h>
diff -Nru a/arch/ia64/hp/zx1/Makefile b/arch/ia64/hp/zx1/Makefile
--- a/arch/ia64/hp/zx1/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/ia64/hp/zx1/Makefile	Wed May 29 11:43:02 2002
@@ -11,16 +11,3 @@
 obj-$(CONFIG_IA64_GENERIC) += hpzx1_machvec.o
 
 include $(TOPDIR)/Rules.make
-#
-# ia64/platform/hp/zx1/Makefile
-#
-# Copyright (C) 2002 Hewlett Packard
-# Copyright (C) Alex Williamson (alex_williamson@hp.com)
-#
-
-O_TARGET := zx1.o
-
-obj-y := hpzx1_misc.o
-obj-$(CONFIG_IA64_GENERIC) += hpzx1_machvec.o
-
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/ia64/hp/zx1/hpzx1_misc.c b/arch/ia64/hp/zx1/hpzx1_misc.c
--- a/arch/ia64/hp/zx1/hpzx1_misc.c	Wed May 29 11:43:02 2002
+++ b/arch/ia64/hp/zx1/hpzx1_misc.c	Wed May 29 11:43:02 2002
@@ -198,7 +198,6 @@
 extern acpi_resource *acpi_get_crs_next(acpi_buffer *, int *);
 extern acpi_resource_data *acpi_get_crs_type(acpi_buffer *, int *, int);
 extern void acpi_dispose_crs(acpi_buffer *);
-extern acpi_status acpi_cf_evaluate_method(acpi_handle, UINT8 *, NATIVE_UINT *);
 
 static acpi_status
 hp_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length)
@@ -388,407 +387,7 @@
 }
 
 extern void sba_init(void);
-	
-void
-hpzx1_pci_fixup (int phase)
-{
-	if (phase == 0)
-		hpzx1_acpi_dev_init();
-	iosapic_pci_fixup(phase);
-        if (phase == 1)
-		sba_init();
-}
-/*
- * Misc. support for HP zx1 chipset support
- *
- * Copyright (C) 2002 Hewlett-Packard Co
- * Copyright (C) 2002 Alex Williamson <alex_williamson@hp.com>
- * Copyright (C) 2002 Bjorn Helgaas <bjorn_helgaas@hp.com>
- */
-
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/acpi.h>
-#include <asm/iosapic.h>
-#include <asm/efi.h>
-
-#include "../drivers/acpi/include/platform/acgcc.h"
-#include "../drivers/acpi/include/actypes.h"
-#include "../drivers/acpi/include/acexcep.h"
-#include "../drivers/acpi/include/acpixf.h"
-#include "../drivers/acpi/include/actbl.h"
-#include "../drivers/acpi/include/acconfig.h"
-#include "../drivers/acpi/include/acmacros.h"
-#include "../drivers/acpi/include/aclocal.h"
-#include "../drivers/acpi/include/acobject.h"
-#include "../drivers/acpi/include/acstruct.h"
-#include "../drivers/acpi/include/acnamesp.h"
-#include "../drivers/acpi/include/acutils.h"
-
-#define PFX "hpzx1: "
-
-struct fake_pci_dev {
-	struct fake_pci_dev *next;
-	unsigned char bus;
-	unsigned int devfn;
-	int sizing;		// in middle of BAR sizing operation?
-	unsigned long csr_base;
-	unsigned int csr_size;
-	unsigned long mapped_csrs;	// ioremapped
-};
-
-static struct fake_pci_dev *fake_pci_head, **fake_pci_tail = &fake_pci_head;
-
-static struct pci_ops orig_pci_ops;
-
-static inline struct fake_pci_dev *
-fake_pci_find_slot(unsigned char bus, unsigned int devfn)
-{
-	struct fake_pci_dev *dev;
-
-	for (dev = fake_pci_head; dev; dev = dev->next)
-		if (dev->bus == bus && dev->devfn == devfn)
-			return dev;
-	return NULL;
-}
-
-static struct fake_pci_dev *
-alloc_fake_pci_dev(void)
-{
-        struct fake_pci_dev *dev;
-
-        dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev)
-		return NULL;
-
-	memset(dev, 0, sizeof(*dev));
-
-        *fake_pci_tail = dev;
-        fake_pci_tail = &dev->next;
-
-        return dev;
-}
-
-#define HP_CFG_RD(sz, bits, name) \
-static int hp_cfg_read##sz (struct pci_dev *dev, int where, u##bits *value) \
-{ \
-	struct fake_pci_dev *fake_dev; \
-	if (!(fake_dev = fake_pci_find_slot(dev->bus->number, dev->devfn))) \
-		return orig_pci_ops.name(dev, where, value); \
-	\
-	switch (where) { \
-	case PCI_COMMAND: \
-		*value = read##sz(fake_dev->mapped_csrs + where); \
-		*value |= PCI_COMMAND_MEMORY; /* SBA omits this */ \
-		break; \
-	case PCI_BASE_ADDRESS_0: \
-		if (fake_dev->sizing) \
-			*value = ~(fake_dev->csr_size - 1); \
-		else \
-			*value = (fake_dev->csr_base & \
-				    PCI_BASE_ADDRESS_MEM_MASK) | \
-				PCI_BASE_ADDRESS_SPACE_MEMORY; \
-		fake_dev->sizing = 0; \
-		break; \
-	default: \
-		*value = read##sz(fake_dev->mapped_csrs + where); \
-		break; \
-	} \
-	return PCIBIOS_SUCCESSFUL; \
-}
-
-#define HP_CFG_WR(sz, bits, name) \
-static int hp_cfg_write##sz (struct pci_dev *dev, int where, u##bits value) \
-{ \
-	struct fake_pci_dev *fake_dev; \
-	if (!(fake_dev = fake_pci_find_slot(dev->bus->number, dev->devfn))) \
-		return orig_pci_ops.name(dev, where, value); \
-	\
-	switch (where) { \
-	case PCI_BASE_ADDRESS_0: \
-		if (value == ~0) \
-			fake_dev->sizing = 1; \
-		break; \
-	default: \
-		write##sz(value, fake_dev->mapped_csrs + where); \
-		break; \
-	} \
-	return PCIBIOS_SUCCESSFUL; \
-}
-
-HP_CFG_RD(b,  8, read_byte)
-HP_CFG_RD(w, 16, read_word)
-HP_CFG_RD(l, 32, read_dword)
-HP_CFG_WR(b,  8, write_byte)
-HP_CFG_WR(w, 16, write_word)
-HP_CFG_WR(l, 32, write_dword)
-
-static struct pci_ops hp_pci_conf = {
-	hp_cfg_readb,
-	hp_cfg_readw,
-	hp_cfg_readl,
-	hp_cfg_writeb,
-	hp_cfg_writew,
-	hp_cfg_writel,
-};
-
-/*
- * Assume we'll never have a physical slot higher than 0x10, so we can
- * use slots above that for "fake" PCI devices to represent things
- * that only show up in the ACPI namespace.
- */
-#define HP_MAX_SLOT	0x10
-
-static struct fake_pci_dev *
-hpzx1_fake_pci_dev(unsigned long addr, unsigned int bus, unsigned int size)
-{
-	struct fake_pci_dev *dev;
-	int slot;
-
-	// Note: lspci thinks 0x1f is invalid
-	for (slot = 0x1e; slot > HP_MAX_SLOT; slot--) {
-		if (!fake_pci_find_slot(bus, PCI_DEVFN(slot, 0)))
-			break;
-	}
-	if (slot == HP_MAX_SLOT) {
-		printk(KERN_ERR PFX
-			"no slot space for device (0x%p) on bus 0x%02x\n",
-			(void *) addr, bus);
-		return NULL;
-	}
-
-	dev = alloc_fake_pci_dev();
-	if (!dev) {
-		printk(KERN_ERR PFX
-			"no memory for device (0x%p) on bus 0x%02x\n",
-			(void *) addr, bus);
-		return NULL;
-	}
-
-	dev->bus = bus;
-	dev->devfn = PCI_DEVFN(slot, 0);
-	dev->csr_base = addr;
-	dev->csr_size = size;
-
-	/*
-	 * Drivers should ioremap what they need, but we have to do
-	 * it here, too, so PCI config accesses work.
-	 */
-	dev->mapped_csrs = (unsigned long) ioremap(dev->csr_base, dev->csr_size);
-
-	return dev;
-}
-
-typedef struct {
-	u8	guid_id;
-	u8	guid[16];
-	u8	csr_base[8];
-	u8	csr_length[8];
-} acpi_hp_vendor_long;
-
-#define HP_CCSR_LENGTH 0x21
-#define HP_CCSR_TYPE 0x2
-#define HP_CCSR_GUID \
-    ((efi_guid_t) { 0x69e9adf9, 0x924f, 0xab5f, { 0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad }})
-
-extern acpi_status acpi_get_crs(acpi_handle, acpi_buffer *);
-extern acpi_resource *acpi_get_crs_next(acpi_buffer *, int *);
-extern acpi_resource_data *acpi_get_crs_type(acpi_buffer *, int *, int);
-extern void acpi_dispose_crs(acpi_buffer *);
-extern acpi_status acpi_cf_evaluate_method(acpi_handle, UINT8 *, NATIVE_UINT *);
-
-static acpi_status
-hp_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length)
-{
-	int i, offset = 0;
-	acpi_status status;
-	acpi_buffer buf;
-	acpi_resource_vendor *res;
-	acpi_hp_vendor_long *hp_res;
-	efi_guid_t vendor_guid;
-
-	*csr_base = 0;
-	*csr_length = 0;
-
-	status = acpi_get_crs(obj, &buf);
-	if (status != AE_OK) {
-		printk(KERN_ERR PFX "Unable to get _CRS data on object\n");
-		return status;
-	}
-
-	res = (acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR);
-	if (!res) {
-		printk(KERN_ERR PFX "Failed to find config space for device\n");
-		acpi_dispose_crs(&buf);
-		return AE_NOT_FOUND;
-	}
-
-	hp_res = (acpi_hp_vendor_long *)(res->reserved);
-
-	if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) {
-		printk(KERN_ERR PFX "Unknown Vendor data\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
-	}
-
-	memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t));
-	if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) {
-		printk(KERN_ERR PFX "Vendor GUID does not match\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
-	}
-
-	for (i = 0 ; i < 8 ; i++) {
-		*csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8));
-		*csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8));
-	}
-
-	acpi_dispose_crs(&buf);
-
-	return AE_OK;
-}
-
-static acpi_status
-hpzx1_sba_probe(acpi_handle obj, u32 depth, void *context, void **ret)
-{
-	u64 csr_base = 0, csr_length = 0;
-	char *name = context;
-	struct fake_pci_dev *dev;
-	acpi_status status;
-
-	status = hp_csr_space(obj, &csr_base, &csr_length);
-
-	if (status != AE_OK)
-		return status;
-
-	/*
-	 * Only SBA shows up in ACPI namespace, so its CSR space
-	 * includes both SBA and IOC.  Make SBA and IOC show up
-	 * separately in PCI space.
-	 */
-	if ((dev = hpzx1_fake_pci_dev(csr_base, 0, 0x1000)))
-		printk(KERN_INFO PFX "%s SBA at 0x%lx; pci dev %02x:%02x.%d\n",
-			name, csr_base, dev->bus,
-			PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-	if ((dev = hpzx1_fake_pci_dev(csr_base + 0x1000, 0, 0x1000)))
-		printk(KERN_INFO PFX "%s IOC at 0x%lx; pci dev %02x:%02x.%d\n",
-			name, csr_base + 0x1000, dev->bus,
-			PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-
-	return AE_OK;
-}
-
-static acpi_status
-hpzx1_lba_probe(acpi_handle obj, u32 depth, void *context, void **ret)
-{
-	acpi_status status;
-	u64 csr_base = 0, csr_length = 0;
-	char *name = context;
-	NATIVE_UINT busnum = 0;
-	struct fake_pci_dev *dev;
-
-	status = hp_csr_space(obj, &csr_base, &csr_length);
-
-	if (status != AE_OK)
-		return status;
-
-	status = acpi_cf_evaluate_method(obj, METHOD_NAME__BBN, &busnum);
-	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR PFX "evaluate _BBN fail=0x%x\n", status);
-		busnum = 0;	// no _BBN; stick it on bus 0
-	}
-
-	if ((dev = hpzx1_fake_pci_dev(csr_base, busnum, csr_length)))
-		printk(KERN_INFO PFX "%s LBA at 0x%lx, _BBN 0x%02x; "
-			"pci dev %02x:%02x.%d\n",
-			name, csr_base, busnum, dev->bus,
-			PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-
-	return AE_OK;
-}
-
-static void
-hpzx1_acpi_dev_init(void)
-{
-	extern struct pci_ops pci_conf;
-
-	/*
-	 * Make fake PCI devices for the following hardware in the
-	 * ACPI namespace.  This makes it more convenient for drivers
-	 * because they can claim these devices based on PCI
-	 * information, rather than needing to know about ACPI.  The
-	 * 64-bit "HPA" space for this hardware is available as BAR
-	 * 0/1.
-	 *
-	 * HWP0001: Single IOC SBA w/o IOC in namespace
-	 * HWP0002: LBA device
-	 * HWP0003: AGP LBA device
-	 */
-	acpi_get_devices("HWP0001", hpzx1_sba_probe, "HWP0001", NULL);
-#ifdef CONFIG_IA64_HP_PROTO
-	if (fake_pci_tail != &fake_pci_head) {
-#endif
-	acpi_get_devices("HWP0002", hpzx1_lba_probe, "HWP0002", NULL);
-	acpi_get_devices("HWP0003", hpzx1_lba_probe, "HWP0003", NULL);
-
-#ifdef CONFIG_IA64_HP_PROTO
-	}
-
-#define ZX1_FUNC_ID_VALUE    (PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP
-	/*
-	 * Early protos don't have bridges in the ACPI namespace, so
-	 * if we didn't find anything, add the things we know are
-	 * there.
-	 */
-	if (fake_pci_tail == &fake_pci_head) {
-		u64 hpa, csr_base;
-		struct fake_pci_dev *dev;
 
-		csr_base = 0xfed00000UL;
-		hpa = (u64) ioremap(csr_base, 0x1000);
-		if (__raw_readl(hpa) == ZX1_FUNC_ID_VALUE) {
-			if ((dev = hpzx1_fake_pci_dev(csr_base, 0, 0x1000)))
-				printk(KERN_INFO PFX "HWP0001 SBA at 0x%lx; "
-					"pci dev %02x:%02x.%d\n", csr_base,
-					dev->bus, PCI_SLOT(dev->devfn),
-					PCI_FUNC(dev->devfn));
-			if ((dev = hpzx1_fake_pci_dev(csr_base + 0x1000, 0,
-					0x1000)))
-				printk(KERN_INFO PFX "HWP0001 IOC at 0x%lx; "
-					"pci dev %02x:%02x.%d\n",
-					csr_base + 0x1000,
-					dev->bus, PCI_SLOT(dev->devfn),
-					PCI_FUNC(dev->devfn));
-
-			csr_base = 0xfed24000UL;
-			iounmap(hpa);
-			hpa = (u64) ioremap(csr_base, 0x1000);
-			if ((dev = hpzx1_fake_pci_dev(csr_base, 0x40, 0x1000)))
-				printk(KERN_INFO PFX "HWP0003 AGP LBA at "
-					"0x%lx; pci dev %02x:%02x.%d\n",
-					csr_base,
-					dev->bus, PCI_SLOT(dev->devfn),
-					PCI_FUNC(dev->devfn));
-		}
-		iounmap(hpa);
-	}
-#endif
-
-	if (fake_pci_tail == &fake_pci_head)
-		return;
-
-	/*
-	 * Replace PCI ops, but only if we made fake devices.
-	 */
-	orig_pci_ops = pci_conf;
-	pci_conf = hp_pci_conf;
-}
-
-extern void sba_init(void);
-	
 void
 hpzx1_pci_fixup (int phase)
 {
diff -Nru a/arch/ia64/ia32/Makefile b/arch/ia64/ia32/Makefile
--- a/arch/ia64/ia32/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/ia64/ia32/Makefile	Wed May 29 11:43:03 2002
@@ -2,13 +2,9 @@
 # Makefile for the ia32 kernel emulation subsystem.
 #
 
-all: ia32.o
-
 O_TARGET := ia32.o
 
 obj-y := ia32_entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o ia32_support.o ia32_traps.o \
 	 binfmt_elf32.o ia32_ldt.o
-
-clean::
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
--- a/arch/ia64/ia32/ia32_entry.S	Wed May 29 11:43:03 2002
+++ b/arch/ia64/ia32/ia32_entry.S	Wed May 29 11:43:03 2002
@@ -40,12 +40,18 @@
 	zxt4 out1=in1				// newsp
 	mov out3=16				// stacksize (compensates for 16-byte scratch area)
 	adds out2=IA64_SWITCH_STACK_SIZE+16,sp	// out2 = &regs
-	zxt4 out0=in0				// out0 = clone_flags
-	br.call.sptk.many rp=do_fork_WITHOUT_CLONE_IDLETASK		// FIXME: mask out CLONE_IDLETASK from flags, and return value now task_struct *.
+	dep out0=0,in0,CLONE_IDLETASK_BIT,1	// out0 = clone_flags & ~CLONE_IDLETASK
+	br.call.sptk.many rp=do_fork
 .ret0:	.restore sp
 	adds sp=IA64_SWITCH_STACK_SIZE,sp	// pop the switch stack
+	mov r2=-1000
+	adds r3=IA64_TASK_PID_OFFSET,r8
+	;;
+	cmp.leu p6,p0=r8,r2
 	mov ar.pfs=loc1
 	mov rp=loc0
+	;;
+(p6)	ld4 r8=[r3]
 	br.ret.sptk.many rp
 END(ia32_clone)
 
@@ -167,11 +173,17 @@
 	mov out1=0
 	mov out3=0
 	adds out2=IA64_SWITCH_STACK_SIZE+16,sp	// out2 = &regs
-	br.call.sptk.few rp=do_fork_FIXME_RETURNS_TASK_STRUCT
-.ret5:	mov ar.pfs=loc1
-	.restore sp
+	br.call.sptk.few rp=do_fork
+.ret5:	.restore sp
 	adds sp=IA64_SWITCH_STACK_SIZE,sp	// pop the switch stack
+	mov r2=-1000
+	adds r3=IA64_TASK_PID_OFFSET,r8
+	;;
+	cmp.leu p6,p0=r8,r2
+	mov ar.pfs=loc1
 	mov rp=loc0
+	;;
+(p6)	ld4 r8=[r3]
 	br.ret.sptk.many rp
 END(sys32_fork)
 
@@ -310,7 +322,7 @@
 	data8 sys32_ni_syscall	/* init_module */
 	data8 sys32_ni_syscall	/* delete_module */
 	data8 sys32_ni_syscall	/* get_kernel_syms */  /* 130 */
-	data8 sys32_quotactl
+	data8 sys_quotactl
 	data8 sys_getpgid
 	data8 sys_fchdir
 	data8 sys32_ni_syscall	/* sys_bdflush */
diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c	Wed May 29 11:43:03 2002
+++ b/arch/ia64/ia32/sys_ia32.c	Wed May 29 11:43:03 2002
@@ -3669,97 +3669,6 @@
 	return result;
 }
 
-extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
-
-#ifdef CONFIG_QIFACE_COMPAT
-#ifdef CONFIG_QIFACE_V1
-struct user_dqblk32 {
-	__u32 dqb_bhardlimit;
-	__u32 dqb_bsoftlimit;
-	__u32 dqb_curblocks;
-	__u32 dqb_ihardlimit;
-	__u32 dqb_isoftlimit;
-	__u32 dqb_curinodes;
-	__kernel_time_t32 dqb_btime;
-	__kernel_time_t32 dqb_itime;
-};
-typedef struct v1c_mem_dqblk comp_dqblk_t;
-
-#define Q_COMP_GETQUOTA Q_V1_GETQUOTA
-#define Q_COMP_SETQUOTA Q_V1_SETQUOTA
-#define Q_COMP_SETQLIM Q_V1_SETQLIM
-#define Q_COMP_SETUSE Q_V1_SETUSE
-#else
-struct user_dqblk32 {
-	__u32 dqb_ihardlimit;
-	__u32 dqb_isoftlimit;
-	__u32 dqb_curinodes;
-	__u32 dqb_bhardlimit;
-	__u32 dqb_bsoftlimit;
-	__u64 dqb_curspace;
-	__kernel_time_t32 dqb_btime;
-	__kernel_time_t32 dqb_itime;
-};
-typedef struct v2c_mem_dqblk comp_dqblk_t;
-
-#define Q_COMP_GETQUOTA Q_V2_GETQUOTA
-#define Q_COMP_SETQUOTA Q_V2_SETQUOTA
-#define Q_COMP_SETQLIM Q_V2_SETQLIM
-#define Q_COMP_SETUSE Q_V2_SETUSE
-#endif
-
-asmlinkage long sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
-{
-	int cmds = cmd >> SUBCMDSHIFT;
-	long err;
-	comp_dqblk_t d;
-	mm_segment_t old_fs;
-	char *spec;
-	
-	switch (cmds) {
-		case Q_COMP_GETQUOTA:
-			break;
-		case Q_COMP_SETQUOTA:
-		case Q_COMP_SETUSE:
-		case Q_COMP_SETQLIM:
-			if (copy_from_user(&d, (struct user_dqblk32 *)addr,
-					    sizeof (struct user_dqblk32)))
-				return -EFAULT;
-			d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime;
-			d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime;
-			break;
-	default:
-		return sys_quotactl(cmd, special, id, (__kernel_caddr_t)addr);
-	}
-	spec = getname (special);
-	err = PTR_ERR(spec);
-	if (IS_ERR(spec)) return err;
-	old_fs = get_fs();
-	set_fs (KERNEL_DS);
-	err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d);
-	set_fs (old_fs);
-	putname (spec);
-	if (err)
-		return err;
-	if (cmds == Q_COMP_GETQUOTA) {
-		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-		((struct user_dqblk32 *)&d)->dqb_itime = i;
-		((struct user_dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user ((struct user_dqblk32 *)addr, &d,
-				  sizeof (struct user_dqblk32)))
-			return -EFAULT;
-	}
-	return 0;
-}
-
-#else
-/* No conversion needed for new interface */
-asmlinkage long sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
-{
-	return sys_quotactl(cmd, special, id, addr);
-}
-#endif
-
 asmlinkage long
 sys32_sched_rr_get_interval (pid_t pid, struct timespec32 *interval)
 {
diff -Nru a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
--- a/arch/ia64/kernel/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/ia64/kernel/Makefile	Wed May 29 11:43:03 2002
@@ -2,9 +2,8 @@
 # Makefile for the linux kernel.
 #
 
-all: kernel.o head.o init_task.o
-
-O_TARGET := kernel.o
+O_TARGET	:= kernel.o
+EXTRA_TARGETS	:= head.o init_task.o
 
 export-objs := ia64_ksyms.o
 
diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
--- a/arch/ia64/kernel/acpi.c	Wed May 29 11:43:03 2002
+++ b/arch/ia64/kernel/acpi.c	Wed May 29 11:43:03 2002
@@ -3,8 +3,8 @@
  *
  *  Copyright (C) 1999 VA Linux Systems
  *  Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
- *  Copyright (C) 2000 Hewlett-Packard Co.
- *  Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ *  Copyright (C) 2000, 2002 Hewlett-Packard Co.
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *  Copyright (C) 2000 Intel Corp.
  *  Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com>
  *  Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -173,7 +173,7 @@
 #define ACPI_MAX_PLATFORM_IRQS	256
 
 /* Array to record platform interrupt vectors for generic interrupt routing. */
-int platform_irq_list[ACPI_MAX_PLATFORM_IRQS];
+int platform_irq_list[ACPI_MAX_PLATFORM_IRQS] = { [0 ... ACPI_MAX_PLATFORM_IRQS - 1] = -1 };
 
 /*
  * Interrupt routing API for device drivers.  Provides interrupt vector for
@@ -421,8 +421,6 @@
 static int __init
 acpi_parse_madt (unsigned long phys_addr, unsigned long size)
 {
-	int i = 0;
-
 	if (!phys_addr || !size)
 		return -EINVAL;
 
@@ -432,11 +430,6 @@
 		return -ENODEV;
 	}
 
-	/* Initialize platform interrupt vector array */
-
-	for (i = 0; i < ACPI_MAX_PLATFORM_IRQS; i++)
-		platform_irq_list[i] = -1;
-
 	/* Get base address of IPI Message Block */
 
 	if (acpi_madt->lapic_address)
@@ -643,7 +636,7 @@
 	*vectors = NULL;
 	*count = 0;
 
-	if (acpi_prts.count < 0) {
+	if (acpi_prts.count <= 0) {
 		printk(KERN_ERR PREFIX "No PCI IRQ routing entries\n");
 		return -ENODEV;
 	}
@@ -660,10 +653,10 @@
 
 	list_for_each(node, &acpi_prts.entries) {
 		entry = (struct acpi_prt_entry *)node;
-		vector[i].bus    = (u16) entry->id.bus;
-		vector[i].pci_id = (u32) entry->id.dev << 16 | 0xffff;
-		vector[i].pin    = (u8)  entry->id.pin;
-		vector[i].irq    = (u8)  entry->source.index;
+		vector[i].bus    = entry->id.bus;
+		vector[i].pci_id = ((u32) entry->id.dev << 16) | 0xffff;
+		vector[i].pin    = entry->id.pin;
+		vector[i].irq    = entry->source.index;
 		i++;
 	}
 	*count = acpi_prts.count;
diff -Nru a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
--- a/arch/ia64/kernel/efi.c	Wed May 29 11:43:01 2002
+++ b/arch/ia64/kernel/efi.c	Wed May 29 11:43:01 2002
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999-2001 Hewlett-Packard Co.
+ * Copyright (C) 1999-2002 Hewlett-Packard Co.
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  *	Stephane Eranian <eranian@hpl.hp.com>
  *
@@ -212,8 +212,8 @@
 	void *efi_map_start, *efi_map_end, *p;
 	efi_memory_desc_t *md;
 	u64 efi_desc_size;
-	int pal_code_count=0;
-	u64 mask, flags;
+	int pal_code_count = 0;
+	u64 mask, psr;
 	u64 vaddr;
 
 	efi_map_start = __va(ia64_boot_param->efi_memmap);
@@ -266,10 +266,10 @@
 		/*
 		 * Cannot write to CRx with PSR.ic=1
 		 */
-		ia64_clear_ic(flags);
+		psr = ia64_clear_ic();
 		ia64_itr(0x1, IA64_TR_PALCODE, vaddr & mask,
 			 pte_val(pfn_pte(md->phys_addr >> PAGE_SHIFT, PAGE_KERNEL)), IA64_GRANULE_SHIFT);
-		local_irq_restore(flags);
+		ia64_set_psr(psr);
 		ia64_srlz_i();
 	}
 }
@@ -485,7 +485,7 @@
 }
 
 u32
-efi_mem_type (u64 phys_addr)
+efi_mem_type (unsigned long phys_addr)
 {
 	void *efi_map_start, *efi_map_end, *p;
 	efi_memory_desc_t *md;
@@ -506,7 +506,7 @@
 }
 
 u64
-efi_mem_attributes (u64 phys_addr)
+efi_mem_attributes (unsigned long phys_addr)
 {
 	void *efi_map_start, *efi_map_end, *p;
 	efi_memory_desc_t *md;
diff -Nru a/arch/ia64/kernel/efi_stub.S b/arch/ia64/kernel/efi_stub.S
--- a/arch/ia64/kernel/efi_stub.S	Wed May 29 11:43:01 2002
+++ b/arch/ia64/kernel/efi_stub.S	Wed May 29 11:43:01 2002
@@ -53,23 +53,21 @@
 	mov loc4=ar.rsc			// save RSE configuration
 	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
 	;;
-
 	ld8 gp=[in0]			// load EFI function's global pointer
-	mov out0=in1
-	mov out1=in2
 	movl r16=PSR_BITS_TO_CLEAR
-
 	mov loc3=psr			// save processor status word
 	movl r17=PSR_BITS_TO_SET
 	;;
-	mov out2=in3
 	or loc3=loc3,r17
 	mov b6=r2
 	;;
 	andcm r16=loc3,r16		// get psr with IT, DT, and RT bits cleared
-	mov out3=in4
 	br.call.sptk.many rp=ia64_switch_mode
 .ret0:	mov out4=in5
+	mov out0=in1
+	mov out1=in2
+	mov out2=in3
+	mov out3=in4
 	mov out5=in6
 	mov out6=in7
 	br.call.sptk.many rp=b6		// call the EFI function
diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
--- a/arch/ia64/kernel/entry.S	Wed May 29 11:43:02 2002
+++ b/arch/ia64/kernel/entry.S	Wed May 29 11:43:02 2002
@@ -100,12 +100,18 @@
 	mov out1=in1
 	mov out3=in2
 	adds out2=IA64_SWITCH_STACK_SIZE+16,sp	// out2 = &regs
-	mov out0=in0				// out0 = clone_flags
-	br.call.sptk.many rp=do_fork_WITHOUT_CLONE_IDLETASK // FIXME: mask out CLONE_IDLETASK from flags, and now returns task_struct *.
+	dep out0=0,in0,CLONE_IDLETASK_BIT,1	// out0 = clone_flags & ~CLONE_IDLETASK
+	br.call.sptk.many rp=do_fork
 .ret1:	.restore sp
 	adds sp=IA64_SWITCH_STACK_SIZE,sp	// pop the switch stack
+	mov r2=-1000
+	adds r3=IA64_TASK_PID_OFFSET,r8
+	;;
+	cmp.leu p6,p0=r8,r2
 	mov ar.pfs=loc1
 	mov rp=loc0
+	;;
+(p6)	ld4 r8=[r3]
 	br.ret.sptk.many rp
 END(sys_clone2)
 
@@ -119,12 +125,18 @@
 	mov out1=in1
 	mov out3=16				// stacksize (compensates for 16-byte scratch area)
 	adds out2=IA64_SWITCH_STACK_SIZE+16,sp	// out2 = &regs
-	mov out0=in0				// out0 = clone_flags
-	br.call.sptk.many rp=do_fork_WITHOUT_CLONE_IDLETASK // FIXME: mask out CLONE_IDLETASK from flags, and now return task_struct *.
+	dep out0=0,in0,CLONE_IDLETASK_BIT,1	// out0 = clone_flags & ~CLONE_IDLETASK
+	br.call.sptk.many rp=do_fork
 .ret2:	.restore sp
 	adds sp=IA64_SWITCH_STACK_SIZE,sp	// pop the switch stack
+	mov r2=-1000
+	adds r3=IA64_TASK_PID_OFFSET,r8
+	;;
+	cmp.leu p6,p0=r8,r2
 	mov ar.pfs=loc1
 	mov rp=loc0
+	;;
+(p6)	ld4 r8=[r3]
 	br.ret.sptk.many rp
 END(sys_clone)
 
diff -Nru a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S
--- a/arch/ia64/kernel/gate.S	Wed May 29 11:43:02 2002
+++ b/arch/ia64/kernel/gate.S	Wed May 29 11:43:02 2002
@@ -13,7 +13,7 @@
 #include <asm/unistd.h>
 #include <asm/page.h>
 
-	.section .text.gate,"ax"
+	.section .text.gate, "ax"
 
 #	define ARG0_OFF		(16 + IA64_SIGFRAME_ARG0_OFFSET)
 #	define ARG1_OFF		(16 + IA64_SIGFRAME_ARG1_OFFSET)
@@ -108,7 +108,7 @@
 	dep r8=0,r8,38,26			// clear EC0, CPL0 and reserved bits
 	adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
 	;;
-	.spillsp ar.pfs, CFM_OFF
+	.spillsp ar.pfs, CFM_OFF+SIGCONTEXT_OFF
 	st8 [base0]=r8				// save CFM0
 	adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
 	;;
diff -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
--- a/arch/ia64/kernel/iosapic.c	Wed May 29 11:43:03 2002
+++ b/arch/ia64/kernel/iosapic.c	Wed May 29 11:43:03 2002
@@ -24,6 +24,8 @@
  *                              /proc/irq/#/smp_affinity
  * 02/04/02	P. Diefenbaugh	Cleaned up ACPI PCI IRQ routing.
  * 02/04/18	J.I. Lee	bug fix in iosapic_init_pci_irq
+ * 02/04/30	J.I. Lee	bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping
+ *				error
  */
 /*
  * Here is what the interrupt logic between a PCI device and the CPU looks like:
@@ -112,7 +114,7 @@
 	int i;
 
 	for (i = 0; i < num_iosapic; i++) {
-		if ((irq - iosapic_lists[i].base_irq) < iosapic_lists[i].max_pin)
+		if ((unsigned) (irq - iosapic_lists[i].base_irq) <= iosapic_lists[i].max_pin)
 			return i;
 	}
 
@@ -138,7 +140,7 @@
  * Map PCI pin to the corresponding IA-64 interrupt vector.  If no such mapping exists,
  * return -1.
  */
-static int
+int
 pci_pin_to_vector (int bus, int slot, int pci_pin)
 {
 	struct pci_vector_struct *r;
@@ -630,7 +632,7 @@
 	}
 }
 
-void __init
+static void __init
 iosapic_init_pci_irq (void)
 {
 	int i, index, vector, pin;
diff -Nru a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
--- a/arch/ia64/kernel/irq.c	Wed May 29 11:43:02 2002
+++ b/arch/ia64/kernel/irq.c	Wed May 29 11:43:02 2002
@@ -1197,7 +1197,7 @@
 {
 	char name [MAX_NAMELEN];
 
-	if (!root_irq_dir || (irq_desc(irq)->handler == &no_irq_type))
+	if (!root_irq_dir || (irq_desc(irq)->handler == &no_irq_type) || irq_dir[irq])
 		return;
 
 	memset(name, 0, MAX_NAMELEN);
diff -Nru a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S
--- a/arch/ia64/kernel/pal.S	Wed May 29 11:43:03 2002
+++ b/arch/ia64/kernel/pal.S	Wed May 29 11:43:03 2002
@@ -216,7 +216,7 @@
 	mov out3 = in3		// copy arg3
 	;;
 	mov loc3 = psr		// save psr
-	;; 
+	;;
 	mov loc4=ar.rsc			// save RSE configuration
 	dep.z loc2=loc2,0,61		// convert pal entry point to physical
 	;;
diff -Nru a/arch/ia64/kernel/pci.c b/arch/ia64/kernel/pci.c
--- a/arch/ia64/kernel/pci.c	Wed May 29 11:43:02 2002
+++ b/arch/ia64/kernel/pci.c	Wed May 29 11:43:02 2002
@@ -199,7 +199,7 @@
 	return;
 }
 
-void __init
+static int __init
 pcibios_init (void)
 {
 #	define PCI_BUSES_TO_SCAN 255
@@ -218,9 +218,10 @@
 		pci_scan_bus(i, pci_root_ops, NULL);
 
 	platform_pci_fixup(1);	/* phase 1 fixups (after buses scanned) */
-
-	return;
+	return 0;
 }
+
+subsys_initcall(pcibios_init);
 
 /*
  *  Called after each bus is probed, but before its children
diff -Nru a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
--- a/arch/ia64/kernel/perfmon.c	Wed May 29 11:43:03 2002
+++ b/arch/ia64/kernel/perfmon.c	Wed May 29 11:43:03 2002
@@ -23,6 +23,7 @@
 #include <linux/vmalloc.h>
 #include <linux/wrapper.h>
 #include <linux/mm.h>
+#include <linux/sysctl.h>
 
 #include <asm/bitops.h>
 #include <asm/errno.h>
@@ -38,11 +39,11 @@
 #ifdef CONFIG_PERFMON
 
 /*
- * For PMUs which rely on the debug registers for some features, you
- * must enable the following flag to activate the support for
+ * For PMUs which rely on the debug registers for some features, you must
+ * you must enable the following flag to activate the support for
  * accessing the registers via the perfmonctl() interface.
  */
-#ifdef CONFIG_ITANIUM
+#if defined(CONFIG_ITANIUM) || defined(CONFIG_MCKINLEY)
 #define PFM_PMU_USES_DBR	1
 #endif
 
@@ -68,26 +69,27 @@
 #define PMC_OVFL_NOTIFY(ctx, i)	((ctx)->ctx_soft_pmds[i].flags &  PFM_REGFL_OVFL_NOTIFY)
 #define PFM_FL_INHERIT_MASK	(PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)
 
+/* i assume unsigned */
 #define PMC_IS_IMPL(i)	  (i<pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1UL<< (i) %64))
 #define PMD_IS_IMPL(i)	  (i<pmu_conf.num_pmds &&  pmu_conf.impl_regs[4+(i>>6)] & (1UL<<(i) % 64))
 
-#define PMD_IS_COUNTING(i) (i >=0  && i < 256 && pmu_conf.counter_pmds[i>>6] & (1UL <<(i) % 64))
-#define PMC_IS_COUNTING(i) PMD_IS_COUNTING(i)
+/* XXX: these three assume that register i is implemented */
+#define PMD_IS_COUNTING(i) (pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING)
+#define PMC_IS_COUNTING(i) (pmu_conf.pmc_desc[i].type == PFM_REG_COUNTING)
+#define PMC_IS_MONITOR(c)  (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR)
 
+/* k assume unsigned */
 #define IBR_IS_IMPL(k)	  (k<pmu_conf.num_ibrs)
 #define DBR_IS_IMPL(k)	  (k<pmu_conf.num_dbrs)
 
-#define PMC_IS_BTB(a)	  (((pfm_monitor_t *)(a))->pmc_es == PMU_BTB_EVENT)
-
-#define LSHIFT(x)		(1UL<<(x))
-#define PMM(x)			LSHIFT(x)
-#define PMC_IS_MONITOR(c)	((pmu_conf.monitor_pmcs[0] & PMM((c))) != 0)
-
 #define CTX_IS_ENABLED(c) 	((c)->ctx_flags.state == PFM_CTX_ENABLED)
 #define CTX_OVFL_NOBLOCK(c)	((c)->ctx_fl_block == 0)
 #define CTX_INHERIT_MODE(c)	((c)->ctx_fl_inherit)
 #define CTX_HAS_SMPL(c)		((c)->ctx_psb != NULL)
-#define CTX_USED_PMD(ctx,n) 	(ctx)->ctx_used_pmds[(n)>>6] |= 1UL<< ((n) % 64)
+/* XXX: does not support more than 64 PMDs */
+#define CTX_USED_PMD(ctx, mask) (ctx)->ctx_used_pmds[0] |= (mask)
+#define CTX_IS_USED_PMD(ctx, c) (((ctx)->ctx_used_pmds[0] & (1UL << (c))) != 0UL)
+
 
 #define CTX_USED_IBR(ctx,n) 	(ctx)->ctx_used_ibrs[(n)>>6] |= 1UL<< ((n) % 64)
 #define CTX_USED_DBR(ctx,n) 	(ctx)->ctx_used_dbrs[(n)>>6] |= 1UL<< ((n) % 64)
@@ -109,12 +111,18 @@
  */
 #define DBprintk(a) \
 	do { \
-		if (pfm_debug_mode >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
+		if (pfm_sysctl.debug >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
 	} while (0)
 
+#define DBprintk_ovfl(a) \
+	do { \
+		if (pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \
+	} while (0)
+
+
 
 /* 
- * These are some helpful architected PMC and IBR/DBR register layouts
+ * Architected PMC structure
  */
 typedef struct {
 	unsigned long pmc_plm:4;	/* privilege level mask */
@@ -139,41 +147,40 @@
 typedef struct _pfm_smpl_buffer_desc {
 	spinlock_t		psb_lock;	/* protection lock */
 	unsigned long		psb_refcnt;	/* how many users for the buffer */
-	int			psb_flags;	/* bitvector of flags */
+	int			psb_flags;	/* bitvector of flags (not yet used) */
 
 	void			*psb_addr;	/* points to location of first entry */
 	unsigned long		psb_entries;	/* maximum number of entries */
 	unsigned long		psb_size;	/* aligned size of buffer */
 	unsigned long		psb_index;	/* next free entry slot XXX: must use the one in buffer */
 	unsigned long		psb_entry_size;	/* size of each entry including entry header */
+
 	perfmon_smpl_hdr_t	*psb_hdr;	/* points to sampling buffer header */
 
 	struct _pfm_smpl_buffer_desc *psb_next;	/* next psb, used for rvfreeing of psb_hdr */
 
 } pfm_smpl_buffer_desc_t;
 
+/*
+ * psb_flags
+ */
+#define PSB_HAS_VMA	0x1		/* a virtual mapping for the buffer exists */
+
 #define LOCK_PSB(p)	spin_lock(&(p)->psb_lock)
 #define UNLOCK_PSB(p)	spin_unlock(&(p)->psb_lock)
 
-#define PFM_PSB_VMA	0x1			/* a VMA is describing the buffer */
-
 /*
- * This structure is initialized at boot time and contains
- * a description of the PMU main characteristic as indicated
- * by PAL
+ * The possible type of a PMU register
  */
-typedef struct {
-	unsigned long pfm_is_disabled;	/* indicates if perfmon is working properly */
-	unsigned long perf_ovfl_val;	/* overflow value for generic counters   */
-	unsigned long max_counters;	/* upper limit on counter pair (PMC/PMD) */
-	unsigned long num_pmcs ;	/* highest PMC implemented (may have holes) */
-	unsigned long num_pmds;		/* highest PMD implemented (may have holes) */
-	unsigned long impl_regs[16];	/* buffer used to hold implememted PMC/PMD mask */
-	unsigned long num_ibrs;		/* number of instruction debug registers */
-	unsigned long num_dbrs;		/* number of data debug registers */
-	unsigned long monitor_pmcs[4];	/* which pmc are controlling monitors */
-	unsigned long counter_pmds[4];	/* which pmd are used as counters */
-} pmu_config_t;
+typedef enum { 
+	PFM_REG_NOTIMPL, /* not implemented */
+	PFM_REG_NONE, 	 /* end marker */
+	PFM_REG_MONITOR, /* a PMC with a pmc.pm field only */
+	PFM_REG_COUNTING,/* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */
+	PFM_REG_CONTROL, /* PMU control register */
+	PFM_REG_CONFIG,  /* refine configuration */
+	PFM_REG_BUFFER	 /* PMD used as buffer */
+} pfm_pmu_reg_type_t;
 
 /*
  * 64-bit software counter structure
@@ -221,9 +228,11 @@
 
 	struct semaphore	ctx_restart_sem;   	/* use for blocking notification mode */
 
-	unsigned long		ctx_used_pmds[4];	/* bitmask of used PMD (speedup ctxsw) */
-	unsigned long		ctx_saved_pmcs[4];	/* bitmask of PMC to save on ctxsw */
-	unsigned long		ctx_reload_pmcs[4];	/* bitmask of PMC to reload on ctxsw (SMP) */
+	unsigned long		ctx_used_pmds[4];	/* bitmask of PMD used                 */
+	unsigned long		ctx_reload_pmds[4];	/* bitmask of PMD to reload on ctxsw   */
+
+	unsigned long		ctx_used_pmcs[4];	/* bitmask PMC used by context         */
+	unsigned long		ctx_reload_pmcs[4];	/* bitmask of PMC to reload on ctxsw   */
 
 	unsigned long		ctx_used_ibrs[4];	/* bitmask of used IBR (speedup ctxsw) */
 	unsigned long		ctx_used_dbrs[4];	/* bitmask of used DBR (speedup ctxsw) */
@@ -235,6 +244,7 @@
 	unsigned long		ctx_cpu;		/* cpu to which perfmon is applied (system wide) */
 
 	atomic_t		ctx_saving_in_progress;	/* flag indicating actual save in progress */
+	atomic_t		ctx_is_busy;		/* context accessed by overflow handler */
 	atomic_t		ctx_last_cpu;		/* CPU id of current or last CPU used */
 } pfm_context_t;
 
@@ -250,16 +260,54 @@
  * mostly used to synchronize between system wide and per-process
  */
 typedef struct {
-	spinlock_t		pfs_lock;		/* lock the structure */
+	spinlock_t		pfs_lock;		   /* lock the structure */
 
-	unsigned long		pfs_task_sessions;	/* number of per task sessions */
-	unsigned long		pfs_sys_sessions;	/* number of per system wide sessions */
-	unsigned long   	pfs_sys_use_dbregs;	  	/* incremented when a system wide session uses debug regs */
-	unsigned long   	pfs_ptrace_use_dbregs;	  /* incremented when a process uses debug regs */
-	struct task_struct	*pfs_sys_session[NR_CPUS];  /* point to task owning a system-wide session */
+	unsigned long		pfs_task_sessions;	   /* number of per task sessions */
+	unsigned long		pfs_sys_sessions;	   /* number of per system wide sessions */
+	unsigned long   	pfs_sys_use_dbregs;	   /* incremented when a system wide session uses debug regs */
+	unsigned long   	pfs_ptrace_use_dbregs;	   /* incremented when a process uses debug regs */
+	struct task_struct	*pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */
 } pfm_session_t;
 
 /*
+ * information about a PMC or PMD.
+ * dep_pmd[]: a bitmask of dependent PMD registers 
+ * dep_pmc[]: a bitmask of dependent PMC registers
+ */
+typedef struct {
+	pfm_pmu_reg_type_t	type;
+	int			pm_pos;
+	int			(*read_check)(struct task_struct *task, unsigned int cnum, unsigned long *val);
+	int			(*write_check)(struct task_struct *task, unsigned int cnum, unsigned long *val);
+	unsigned long		dep_pmd[4];
+	unsigned long		dep_pmc[4];
+} pfm_reg_desc_t;
+/* assume cnum is a valid monitor */
+#define PMC_PM(cnum, val)	(((val) >> (pmu_conf.pmc_desc[cnum].pm_pos)) & 0x1)
+#define PMC_WR_FUNC(cnum)	(pmu_conf.pmc_desc[cnum].write_check)
+#define PMD_WR_FUNC(cnum)	(pmu_conf.pmd_desc[cnum].write_check)
+#define PMD_RD_FUNC(cnum)	(pmu_conf.pmd_desc[cnum].read_check)
+
+/*
+ * This structure is initialized at boot time and contains
+ * a description of the PMU main characteristic as indicated
+ * by PAL along with a list of inter-registers dependencies and configurations.
+ */
+typedef struct {
+	unsigned long pfm_is_disabled;	/* indicates if perfmon is working properly */
+	unsigned long perf_ovfl_val;	/* overflow value for generic counters   */
+	unsigned long max_counters;	/* upper limit on counter pair (PMC/PMD) */
+	unsigned long num_pmcs ;	/* highest PMC implemented (may have holes) */
+	unsigned long num_pmds;		/* highest PMD implemented (may have holes) */
+	unsigned long impl_regs[16];	/* buffer used to hold implememted PMC/PMD mask */
+	unsigned long num_ibrs;		/* number of instruction debug registers */
+	unsigned long num_dbrs;		/* number of data debug registers */
+	pfm_reg_desc_t *pmc_desc;	/* detailed PMC register descriptions */
+	pfm_reg_desc_t *pmd_desc;	/* detailed PMD register descriptions */
+} pmu_config_t;
+
+
+/*
  * structure used to pass argument to/from remote CPU 
  * using IPI to check and possibly save the PMU context on SMP systems.
  *
@@ -301,22 +349,52 @@
 #define PFM_CMD_NARG(cmd)	(pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_narg)
 #define PFM_CMD_ARG_SIZE(cmd)	(pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_argsize)
 
+typedef struct {
+	int	debug;		/* turn on/off debugging via syslog */
+	int	debug_ovfl;	/* turn on/off debug printk in overflow handler */
+	int	fastctxsw;	/* turn on/off fast (unsecure) ctxsw */
+} pfm_sysctl_t;
+
+typedef struct {
+	unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */
+	unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */
+	unsigned long pfm_recorded_samples_count;
+	unsigned long pfm_full_smpl_buffer_count; /* how many times the sampling buffer was full */
+} pfm_stats_t;
 
 /*
  * perfmon internal variables
  */
 static pmu_config_t	pmu_conf; 	/* PMU configuration */
-static int		pfm_debug_mode;	/* 0= nodebug, >0= debug output on */
 static pfm_session_t	pfm_sessions;	/* global sessions information */
 static struct proc_dir_entry *perfmon_dir; /* for debug only */
-static unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */
-static unsigned long pfm_ovfl_intr_count; /* keep track of spurious ovfl interrupts */
-static unsigned long pfm_recorded_samples_count;
-
+static pfm_stats_t	pfm_stats;
+int __per_cpu_data pfm_syst_wide;
+static int __per_cpu_data pfm_dcr_pp;
+
+/* sysctl() controls */
+static pfm_sysctl_t pfm_sysctl;
+
+static ctl_table pfm_ctl_table[]={
+	{1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,},
+	{2, "debug_ovfl", &pfm_sysctl.debug_ovfl, sizeof(int), 0666, NULL, &proc_dointvec, NULL,},
+	{3, "fastctxsw", &pfm_sysctl.fastctxsw, sizeof(int), 0600, NULL, &proc_dointvec, NULL,},
+	{ 0, },
+};
+static ctl_table pfm_sysctl_dir[] = {
+	{1, "perfmon", NULL, 0, 0755, pfm_ctl_table, },
+ 	{0,},
+};
+static ctl_table pfm_sysctl_root[] = {
+	{1, "kernel", NULL, 0, 0755, pfm_sysctl_dir, },
+ 	{0,},
+};
+static struct ctl_table_header *pfm_sysctl_header;
 
 static unsigned long reset_pmcs[IA64_NUM_PMC_REGS];	/* contains PAL reset values for PMCS */
 
 static void pfm_vm_close(struct vm_area_struct * area);
+
 static struct vm_operations_struct pfm_vm_ops={
 	close: pfm_vm_close
 };
@@ -339,6 +417,14 @@
 #endif
 static void pfm_lazy_save_regs (struct task_struct *ta);
 
+#if   defined(CONFIG_ITANIUM)
+#include "perfmon_itanium.h"
+#elif defined(CONFIG_MCKINLEY)
+#include "perfmon_mckinley.h"
+#else
+#include "perfmon_generic.h"
+#endif
+
 static inline unsigned long
 pfm_read_soft_counter(pfm_context_t *ctx, int i)
 {
@@ -353,7 +439,7 @@
 	 * writing to unimplemented part is ignore, so we do not need to
 	 * mask off top part
 	 */
-	ia64_set_pmd(i, val);
+	ia64_set_pmd(i, val & pmu_conf.perf_ovfl_val);
 }
 
 /*
@@ -388,7 +474,8 @@
 }
 
 /* Here we want the physical address of the memory.
- * This is used when initializing the contents of the area.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
  */
 static inline unsigned long
 pfm_kvirt_to_pa(unsigned long adr)
@@ -398,7 +485,6 @@
 	return pa;
 }
 
-
 static void *
 pfm_rvmalloc(unsigned long size)
 {
@@ -473,7 +559,7 @@
 	 *
 	 * This function cannot remove the buffer from here, because exit_mmap() must first
 	 * complete. Given that there is no other vma related callback in the generic code,
-	 * we have created on own with the linked list of sampling buffer to free which
+	 * we have created our own with the linked list of sampling buffers to free. The list
 	 * is part of the thread structure. In release_thread() we check if the list is
 	 * empty. If not we call into perfmon to free the buffer and psb. That is the only
 	 * way to ensure a safe deallocation of the sampling buffer which works when
@@ -489,16 +575,15 @@
 		psb->psb_next = current->thread.pfm_smpl_buf_list;
 		current->thread.pfm_smpl_buf_list = psb;
 
-		DBprintk(("psb for [%d] smpl @%p size %ld inserted into list\n", 
-			current->pid, psb->psb_hdr, psb->psb_size));
+		DBprintk(("[%d] add smpl @%p size %lu to smpl_buf_list psb_flags=0x%x\n", 
+			current->pid, psb->psb_hdr, psb->psb_size, psb->psb_flags));
 	}
-	DBprintk(("psb vma flag cleared for [%d] smpl @%p size %ld inserted into list\n", 
-			current->pid, psb->psb_hdr, psb->psb_size));
-
+	DBprintk(("[%d] clearing psb_flags=0x%x smpl @%p size %lu\n", 
+			current->pid, psb->psb_flags, psb->psb_hdr, psb->psb_size));
 	/*
-	 * indicate to pfm_context_exit() that the vma has been removed. 
+	 * decrement the number vma for the buffer
 	 */
-	psb->psb_flags &= ~PFM_PSB_VMA;
+	psb->psb_flags &= ~PSB_HAS_VMA;
 
 	UNLOCK_PSB(psb);
 }
@@ -521,7 +606,7 @@
 		printk("perfmon: invalid context mm=%p\n", task->mm);
 		return -1;
 	}
-	psb = ctx->ctx_psb;	
+	psb = ctx->ctx_psb;
 
 	down_write(&task->mm->mmap_sem);
 
@@ -532,14 +617,9 @@
 		printk("perfmon: pid %d unable to unmap sampling buffer @0x%lx size=%ld\n", 
 				task->pid, ctx->ctx_smpl_vaddr, psb->psb_size);
 	}
-	DBprintk(("[%d] do_unmap(0x%lx, %ld)=%d\n", 
-		task->pid, ctx->ctx_smpl_vaddr, psb->psb_size, r));
 
-	/* 
-	 * make sure we suppress all traces of this buffer
-	 * (important for pfm_inherit)
-	 */
-	ctx->ctx_smpl_vaddr = 0;
+	DBprintk(("[%d] do_unmap(0x%lx, %ld)=%d refcnt=%lu psb_flags=0x%x\n", 
+		task->pid, ctx->ctx_smpl_vaddr, psb->psb_size, r, psb->psb_refcnt, psb->psb_flags));
 
 	return 0;
 }
@@ -572,7 +652,7 @@
 	while (size > 0) {
 		page = pfm_kvirt_to_pa(buf);
 
-		if (remap_page_range(vma, addr, page, PAGE_SIZE, PAGE_SHARED)) return -ENOMEM;
+		if (remap_page_range(vma, addr, page, PAGE_SIZE, PAGE_READONLY)) return -ENOMEM;
 		
 		addr  += PAGE_SIZE;
 		buf   += PAGE_SIZE;
@@ -611,17 +691,25 @@
 	void *smpl_buf;
 	pfm_smpl_buffer_desc_t *psb;
 
-	regcount = pfm_smpl_entry_size(which_pmds, 1);
 
 	/* note that regcount might be 0, in this case only the header for each
 	 * entry will be recorded.
 	 */
+	regcount = pfm_smpl_entry_size(which_pmds, 1);
+
+	if ((sizeof(perfmon_smpl_hdr_t)+ entries*sizeof(perfmon_smpl_entry_t)) <= entries) {
+		DBprintk(("requested entries %lu is too big\n", entries));
+		return -EINVAL;
+	}
 
 	/*
 	 * 1 buffer hdr and for each entry a header + regcount PMDs to save
 	 */
 	size = PAGE_ALIGN(  sizeof(perfmon_smpl_hdr_t)
 			  + entries * (sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64)));
+
+	DBprintk(("sampling buffer size=%lu bytes\n", size));
+
 	/*
 	 * check requested size to avoid Denial-of-service attacks
 	 * XXX: may have to refine this test	
@@ -661,8 +749,13 @@
 	}
 	/*
 	 * partially initialize the vma for the sampling buffer
+	 *
+	 * The VM_DONTCOPY flag is very important as it ensures that the mapping
+	 * will never be inherited for any child process (via fork()) which is always 
+	 * what we want.
 	 */
-	vma->vm_flags	     = VM_READ| VM_MAYREAD |VM_RESERVED;
+	vma->vm_mm	     = mm;
+	vma->vm_flags	     = VM_READ| VM_MAYREAD |VM_RESERVED|VM_DONTCOPY;
 	vma->vm_page_prot    = PAGE_READONLY; /* XXX may need to change */
 	vma->vm_ops	     = &pfm_vm_ops; /* necesarry to get the close() callback */
 	vma->vm_pgoff	     = 0;
@@ -680,8 +773,8 @@
 	psb->psb_size    = size; /* aligned size */
 	psb->psb_index   = 0;
 	psb->psb_entries = entries;
-	psb->psb_flags   = PFM_PSB_VMA; /* remember that there is a vma describing the buffer */
 	psb->psb_refcnt  = 1;
+	psb->psb_flags   = PSB_HAS_VMA;
 
 	spin_lock_init(&psb->psb_lock);
 
@@ -691,9 +784,9 @@
 	 */
 	psb->psb_entry_size = sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64);
 
-	DBprintk(("psb @%p entry_size=%ld hdr=%p addr=%p\n", 
+	DBprintk(("psb @%p entry_size=%ld hdr=%p addr=%p refcnt=%lu psb_flags=0x%x\n", 
 		  (void *)psb,psb->psb_entry_size, (void *)psb->psb_hdr, 
-		  (void *)psb->psb_addr));
+		  (void *)psb->psb_addr, psb->psb_refcnt, psb->psb_flags));
 
 	/* initialize some of the fields of user visible buffer header */
 	psb->psb_hdr->hdr_version    = PFM_SMPL_VERSION;
@@ -785,6 +878,11 @@
 	}
 	ctx_flags = pfx->ctx_flags;
 
+	if ((ctx_flags & PFM_FL_INHERIT_MASK) == (PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)) {
+		DBprintk(("invalid inherit mask 0x%x\n",ctx_flags & PFM_FL_INHERIT_MASK));
+		return -EINVAL;
+	}
+
 	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
 		DBprintk(("cpu_mask=0x%lx\n", pfx->ctx_cpu_mask));
 		/*
@@ -823,7 +921,15 @@
 		 * must provide a target for the signal in blocking mode even when
 		 * no counter is configured with PFM_FL_REG_OVFL_NOTIFY
 		 */
-		if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == 0) return -EINVAL;
+		if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == 0) {
+			DBprintk(("must have notify_pid when blocking for [%d]\n", task->pid));
+			return -EINVAL;
+		}
+
+		if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == task->pid) {
+			DBprintk(("cannot notify self when blocking for [%d]\n", task->pid));
+			return -EINVAL;
+		}
 	}
 	/* probably more to add here */
 
@@ -831,7 +937,7 @@
 }
 
 static int
-pfm_create_context(struct task_struct *task, pfm_context_t *ctx, void *req, int count, 
+pfm_context_create(struct task_struct *task, pfm_context_t *ctx, void *req, int count, 
 		   struct pt_regs *regs)
 {
 	pfarg_context_t tmp;
@@ -956,7 +1062,7 @@
 	}
 
 	if (tmp.ctx_smpl_entries) {
-		DBprintk(("sampling entries=%ld\n",tmp.ctx_smpl_entries));
+		DBprintk(("sampling entries=%lu\n",tmp.ctx_smpl_entries));
 
 		ret = pfm_smpl_buffer_alloc(ctx, tmp.ctx_smpl_regs, 
 						 tmp.ctx_smpl_entries, &uaddr);
@@ -982,20 +1088,12 @@
 
 	atomic_set(&ctx->ctx_last_cpu,-1); /* SMP only, means no CPU */
 
-	/* 
-	 * Keep track of the pmds we want to sample
-	 * XXX: may be we don't need to save/restore the DEAR/IEAR pmds
-	 * but we do need the BTB for sure. This is because of a hardware
-	 * buffer of 1 only for non-BTB pmds.
-	 *
-	 * We ignore the unimplemented pmds specified by the user
-	 */
-	ctx->ctx_used_pmds[0]  = tmp.ctx_smpl_regs[0] & pmu_conf.impl_regs[4];
-	ctx->ctx_saved_pmcs[0] = 1; /* always save/restore PMC[0] */
+	/* may be redudant with memset() but at least it's easier to remember */
+	atomic_set(&ctx->ctx_saving_in_progress, 0); 
+	atomic_set(&ctx->ctx_is_busy, 0); 
 
 	sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */
 
-
 	if (copy_to_user(req, &tmp, sizeof(tmp))) {
 		ret = -EFAULT;
 		goto buffer_error;
@@ -1097,21 +1195,22 @@
 			  	current->pid, 
 				flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val));
 	}
+	ia64_srlz_d();
 	/* just in case ! */
 	ctx->ctx_ovfl_regs[0] = 0UL;
 }
 
 static int
-pfm_write_pmcs(struct task_struct *ta, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
+pfm_write_pmcs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
-	struct thread_struct *th = &ta->thread;
+	struct thread_struct *th = &task->thread;
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
 	unsigned int cnum;
 	int i;
 	int ret = 0, reg_retval = 0;
 
 	/* we don't quite support this right now */
-	if (ta != current) return -EINVAL;
+	if (task != current) return -EINVAL;
 
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
@@ -1140,30 +1239,30 @@
 		 * 	- per-task : user monitor
 		 * any other configuration is rejected.
 		 */
-		if (PMC_IS_MONITOR(cnum)) {
-			pfm_monitor_t *p = (pfm_monitor_t *)&tmp.reg_value;
+		if (PMC_IS_MONITOR(cnum) || PMC_IS_COUNTING(cnum)) {
+			DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, tmp.reg_value))); 
 
-			DBprintk(("pmc[%u].pm = %d\n", cnum, p->pmc_pm));
-
-			if (ctx->ctx_fl_system ^ p->pmc_pm) {
-			//if ((ctx->ctx_fl_system == 1 && p->pmc_pm == 0)
-			 //  ||(ctx->ctx_fl_system == 0 && p->pmc_pm == 1)) {
+			if (ctx->ctx_fl_system ^ PMC_PM(cnum, tmp.reg_value)) {
+				DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, tmp.reg_value), ctx->ctx_fl_system));
 				ret = -EINVAL;
 				goto abort_mission;
 			}
-			/*
-			 * enforce generation of overflow interrupt. Necessary on all
-			 * CPUs which do not implement 64-bit hardware counters.
-			 */
-			p->pmc_oi = 1;
 		}
 
 		if (PMC_IS_COUNTING(cnum)) {
+			pfm_monitor_t *p = (pfm_monitor_t *)&tmp.reg_value;
+			/*
+		 	 * enforce generation of overflow interrupt. Necessary on all
+		 	 * CPUs.
+		 	 */
+			p->pmc_oi = 1;
+
 			if (tmp.reg_flags & PFM_REGFL_OVFL_NOTIFY) {
 				/*
 				 * must have a target for the signal
 				 */
 				if (ctx->ctx_notify_task == NULL) {
+					DBprintk(("no notify_task && PFM_REGFL_OVFL_NOTIFY\n"));
 					ret = -EINVAL;
 					goto abort_mission;
 				}
@@ -1177,14 +1276,11 @@
 			ctx->ctx_soft_pmds[cnum].reset_pmds[1] = tmp.reg_reset_pmds[1];
 			ctx->ctx_soft_pmds[cnum].reset_pmds[2] = tmp.reg_reset_pmds[2];
 			ctx->ctx_soft_pmds[cnum].reset_pmds[3] = tmp.reg_reset_pmds[3];
-
-			/*
-			 * needed in case the user does not initialize the equivalent
-			 * PMD. Clearing is done in reset_pmu() so there is no possible
-			 * leak here.
-			 */
-			CTX_USED_PMD(ctx, cnum);
 		}
+		/*
+		 * execute write checker, if any
+		 */
+		if (PMC_WR_FUNC(cnum)) ret = PMC_WR_FUNC(cnum)(task, cnum, &tmp.reg_value);
 abort_mission:
 		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
 
@@ -1204,14 +1300,21 @@
 		 */
 		if (ret != 0) {
 			DBprintk(("[%d] pmc[%u]=0x%lx error %d\n",
-				  ta->pid, cnum, tmp.reg_value, reg_retval));
+				  task->pid, cnum, tmp.reg_value, reg_retval));
 			break;
 		}
 
 		/* 
 		 * We can proceed with this register!
 		 */
-		
+
+		/*
+		 * Needed in case the user does not initialize the equivalent
+		 * PMD. Clearing is done in reset_pmu() so there is no possible
+		 * leak here.
+		 */
+		CTX_USED_PMD(ctx, pmu_conf.pmc_desc[cnum].dep_pmd[0]);
+
 		/* 
 		 * keep copy the pmc, used for register reload
 		 */
@@ -1219,17 +1322,17 @@
 
 		ia64_set_pmc(cnum, tmp.reg_value);
 
-		DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x save_pmcs=0%lx reload_pmcs=0x%lx\n", 
-			  ta->pid, cnum, tmp.reg_value, 
+		DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x used_pmds=0x%lx\n", 
+			  task->pid, cnum, tmp.reg_value, 
 			  ctx->ctx_soft_pmds[cnum].flags, 
-			  ctx->ctx_saved_pmcs[0], ctx->ctx_reload_pmcs[0]));
+			  ctx->ctx_used_pmds[0]));
 
 	}
 	return ret;
 }
 
 static int
-pfm_write_pmds(struct task_struct *ta, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
+pfm_write_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
 	unsigned int cnum;
@@ -1237,7 +1340,7 @@
 	int ret = 0, reg_retval = 0;
 
 	/* we don't quite support this right now */
-	if (ta != current) return -EINVAL;
+	if (task != current) return -EINVAL;
 
 	/* 
 	 * Cannot do anything before PMU is enabled 
@@ -1252,7 +1355,6 @@
 		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
 		cnum = tmp.reg_num;
-
 		if (!PMD_IS_IMPL(cnum)) {
 			ret = -EINVAL;
 			goto abort_mission;
@@ -1266,6 +1368,10 @@
 			ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset;
 
 		}
+		/*
+		 * execute write checker, if any
+		 */
+		if (PMD_WR_FUNC(cnum)) ret = PMD_WR_FUNC(cnum)(task, cnum, &tmp.reg_value);
 abort_mission:
 		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
 
@@ -1282,21 +1388,22 @@
 		 */
 		if (ret != 0) {
 			DBprintk(("[%d] pmc[%u]=0x%lx error %d\n",
-				  ta->pid, cnum, tmp.reg_value, reg_retval));
+				  task->pid, cnum, tmp.reg_value, reg_retval));
 			break;
 		}
 
 		/* keep track of what we use */
-		CTX_USED_PMD(ctx, cnum);
+		CTX_USED_PMD(ctx, pmu_conf.pmd_desc[(cnum)].dep_pmd[0]);
 
 		/* writes to unimplemented part is ignored, so this is safe */
-		ia64_set_pmd(cnum, tmp.reg_value);
+		ia64_set_pmd(cnum, tmp.reg_value & pmu_conf.perf_ovfl_val);
 
 		/* to go away */
 		ia64_srlz_d();
+
 		DBprintk(("[%d] pmd[%u]: soft_pmd=0x%lx  short_reset=0x%lx "
 			  "long_reset=0x%lx hw_pmd=%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx\n",
-				ta->pid, cnum,
+				task->pid, cnum,
 				ctx->ctx_soft_pmds[cnum].val,
 				ctx->ctx_soft_pmds[cnum].short_reset,
 				ctx->ctx_soft_pmds[cnum].long_reset,
@@ -1309,12 +1416,13 @@
 }
 
 static int
-pfm_read_pmds(struct task_struct *ta, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
+pfm_read_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
-	struct thread_struct *th = &ta->thread;
+	struct thread_struct *th = &task->thread;
 	unsigned long val=0;
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
-	int i;
+	unsigned int cnum;
+	int i, ret = 0;
 
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
@@ -1327,14 +1435,25 @@
 
 	/* XXX: ctx locking may be required here */
 
-	DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), ta->pid));
+	DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), task->pid));
 
 	for (i = 0; i < count; i++, req++) {
 		unsigned long reg_val = ~0UL, ctx_val = ~0UL;
 
 		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
-		if (!PMD_IS_IMPL(tmp.reg_num)) goto abort_mission;
+		cnum = tmp.reg_num;
+
+		if (!PMD_IS_IMPL(cnum)) goto abort_mission;
+		/*
+		 * we can only read the register that we use. That includes
+		 * the one we explicitely initialize AND the one we want included
+		 * in the sampling buffer (smpl_regs).
+		 *
+		 * Having this restriction allows optimization in the ctxsw routine
+		 * without compromising security (leaks)
+		 */
+		if (!CTX_IS_USED_PMD(ctx, cnum)) goto abort_mission;
 
 		/*
 		 * If the task is not the current one, then we check if the
@@ -1343,8 +1462,8 @@
 		 */
 		if (atomic_read(&ctx->ctx_last_cpu) == smp_processor_id()){
 			ia64_srlz_d();
-			val = reg_val = ia64_get_pmd(tmp.reg_num);
-			DBprintk(("reading pmd[%u]=0x%lx from hw\n", tmp.reg_num, val));
+			val = reg_val = ia64_get_pmd(cnum);
+			DBprintk(("reading pmd[%u]=0x%lx from hw\n", cnum, val));
 		} else {
 #ifdef CONFIG_SMP
 			int cpu;
@@ -1360,30 +1479,38 @@
 			 */
 			cpu = atomic_read(&ctx->ctx_last_cpu);
 			if (cpu != -1) {
-				DBprintk(("must fetch on CPU%d for [%d]\n", cpu, ta->pid));
-				pfm_fetch_regs(cpu, ta, ctx);
+				DBprintk(("must fetch on CPU%d for [%d]\n", cpu, task->pid));
+				pfm_fetch_regs(cpu, task, ctx);
 			}
 #endif
 			/* context has been saved */
-			val = reg_val = th->pmd[tmp.reg_num];
+			val = reg_val = th->pmd[cnum];
 		}
-		if (PMD_IS_COUNTING(tmp.reg_num)) {
+		if (PMD_IS_COUNTING(cnum)) {
 			/*
 			 * XXX: need to check for overflow
 			 */
 
 			val &= pmu_conf.perf_ovfl_val;
-			val += ctx_val = ctx->ctx_soft_pmds[tmp.reg_num].val;
+			val += ctx_val = ctx->ctx_soft_pmds[cnum].val;
 		} else {
-
-			val = reg_val = ia64_get_pmd(tmp.reg_num);
+			val = reg_val = ia64_get_pmd(cnum);
 		}
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
+
 		tmp.reg_value = val;
 
-		DBprintk(("read pmd[%u] soft_pmd=0x%lx reg=0x%lx pmc=0x%lx\n", 
-					tmp.reg_num, ctx_val, reg_val, 
-					ia64_get_pmc(tmp.reg_num)));
+		/*
+		 * execute read checker, if any
+		 */
+		if (PMD_RD_FUNC(cnum)) {
+			ret = PMD_RD_FUNC(cnum)(task, cnum, &tmp.reg_value);
+		}
+
+		PFM_REG_RETFLAG_SET(tmp.reg_flags, ret);
+
+		DBprintk(("read pmd[%u] ret=%d soft_pmd=0x%lx reg=0x%lx pmc=0x%lx\n", 
+					cnum, ret, ctx_val, reg_val, 
+					ia64_get_pmc(cnum)));
 
 		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
 	}
@@ -1391,7 +1518,7 @@
 abort_mission:
 	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
 	/* 
-	 * XXX: if this fails, we stick we the original failure, flag not updated!
+	 * XXX: if this fails, we stick with the original failure, flag not updated!
 	 */
 	copy_to_user(req, &tmp, sizeof(tmp));
 	return -EINVAL;
@@ -1459,6 +1586,7 @@
  * perfmormance monitoring, so we only decrement the number
  * of "ptraced" debug register users to keep the count up to date
  */
+
 int
 pfm_release_debug_registers(struct task_struct *task)
 {
@@ -1505,13 +1633,6 @@
 	 */
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
-#if 0
-	if (ctx->ctx_fl_frozen==0) {
-		printk("task %d without pmu_frozen set\n", task->pid);
-		return -EINVAL;
-	}
-#endif
-
 	if (task == current) {
 		DBprintk(("restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen));
 
@@ -1554,7 +1675,6 @@
 		up(sem);
 	} else {
 		task->thread.pfm_ovfl_block_reset = 1;
-		set_tsk_thread_flag(current, TIF_NOTIFY_RESUME);
 	}
 #if 0
 	/*
@@ -1629,25 +1749,35 @@
 				current->pid,
 				ctx->ctx_fl_system, PMU_OWNER(),
 				current));
+
 	/* simply stop monitoring but not the PMU */
 	if (ctx->ctx_fl_system) {
 
-		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
-
 		/* disable dcr pp */
 		ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP);
 
+		/* stop monitoring */
+		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
+
+		ia64_srlz_i();
+
 #ifdef CONFIG_SMP
-		local_cpu_data->pfm_dcr_pp  = 0;
+		this_cpu(pfm_dcr_pp)  = 0;
 #else
 		pfm_tasklist_toggle_pp(0);
 #endif
-
 		ia64_psr(regs)->pp = 0;
 
 	} else {
+
+		/* stop monitoring */
 		__asm__ __volatile__ ("rum psr.up;;"::: "memory");
 
+		ia64_srlz_i();
+
+		/*
+		 * clear user level psr.up
+		 */
 		ia64_psr(regs)->up = 0;
 	}
 	return 0;
@@ -1674,7 +1804,7 @@
 		ia64_psr(regs)->up = 0;
 	}
 	/* 
-	 * goes back to default behavior 
+	 * goes back to default behavior: no user level control
 	 * no need to change live psr.sp because useless at the kernel level
 	 */
 	ia64_psr(regs)->sp = 1;
@@ -1686,10 +1816,8 @@
 	return 0;
 }
 
-
-
 static int
-pfm_destroy_context(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
+pfm_context_destroy(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
 	 struct pt_regs *regs)
 {
 	/* we don't quite support this right now */
@@ -1715,15 +1843,14 @@
 		ia64_psr(regs)->up = 0;
 	}
 
-	/* restore security level */
-	ia64_psr(regs)->sp = 1;
-
 skipped_stop:
 	/*
 	 * remove sampling buffer mapping, if any
 	 */
-	if (ctx->ctx_smpl_vaddr) pfm_remove_smpl_mapping(task);
-
+	if (ctx->ctx_smpl_vaddr) {
+		pfm_remove_smpl_mapping(task);
+		ctx->ctx_smpl_vaddr = 0UL;
+	}
 	/* now free context and related state */
 	pfm_context_exit(task);
 
@@ -1734,7 +1861,7 @@
  * does nothing at the moment
  */
 static int
-pfm_unprotect_context(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
+pfm_context_unprotect(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
 	 struct pt_regs *regs)
 {
 	return 0;
@@ -1764,9 +1891,9 @@
 {
 	unsigned int mode = *(unsigned int *)arg;
 
-	pfm_debug_mode = mode == 0 ? 0 : 1;
+	pfm_sysctl.debug = mode == 0 ? 0 : 1;
 
-	printk("perfmon debugging %s\n", pfm_debug_mode ? "on" : "off");
+	printk("perfmon debugging %s\n", pfm_sysctl.debug ? "on" : "off");
 
 	return 0;
 }
@@ -1855,15 +1982,17 @@
 			memset(task->thread.ibr, 0, sizeof(task->thread.ibr));
 
 			/*
-			 * clear hardware registers to make sure we don't leak
-			 * information and pick up stale state
+			 * clear hardware registers to make sure we don't
+			 * pick up stale state
 			 */
 			for (i=0; i < pmu_conf.num_ibrs; i++) {
 				ia64_set_ibr(i, 0UL);
 			}
+			ia64_srlz_i();
 			for (i=0; i < pmu_conf.num_dbrs; i++) {
 				ia64_set_dbr(i, 0UL);
 			}
+			ia64_srlz_d();
 		}
 	}
 
@@ -1924,6 +2053,7 @@
 			CTX_USED_IBR(ctx, rnum);
 
 			ia64_set_ibr(rnum, dbreg.val);
+			ia64_srlz_i();
 
 			thread->ibr[rnum] = dbreg.val;
 
@@ -1932,6 +2062,7 @@
 			CTX_USED_DBR(ctx, rnum);
 
 			ia64_set_dbr(rnum, dbreg.val);
+			ia64_srlz_d();
 
 			thread->dbr[rnum] = dbreg.val;
 
@@ -2031,27 +2162,35 @@
 
 	if (ctx->ctx_fl_system) {
 		
-		/* enable dcr pp */
-		ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP);
-
 #ifdef CONFIG_SMP
-		local_cpu_data->pfm_dcr_pp  = 1;
+		this_cpu(pfm_dcr_pp)  = 1;
 #else
 		pfm_tasklist_toggle_pp(1);
 #endif
+		/* set user level psr.pp */
 		ia64_psr(regs)->pp = 1;
 
+		/* start monitoring at kernel level */
 		__asm__ __volatile__ ("ssm psr.pp;;"::: "memory");
 
+		/* enable dcr pp */
+		ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP);
+
+		ia64_srlz_i();
+
 	} else {
 		if ((task->thread.flags & IA64_THREAD_PM_VALID) == 0) {
 			printk("perfmon: pfm_start task flag not set for [%d]\n", task->pid);
 			return -EINVAL;
 		}
+		/* set user level psr.up */
 		ia64_psr(regs)->up = 1;
+
+		/* start monitoring at kernel level */
 		__asm__ __volatile__ ("sum psr.up;;"::: "memory");
+
+		ia64_srlz_i();
 	}
-	ia64_srlz_d();
 
 	return 0;
 }
@@ -2074,11 +2213,13 @@
 		ia64_psr(regs)->pp = 0;
 		ia64_psr(regs)->up = 0; /* just to make sure! */
 
+		/* make sure monitoring is stopped */
 		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
+		ia64_srlz_i();
 
 #ifdef CONFIG_SMP
-		local_cpu_data->pfm_syst_wide = 1;
-		local_cpu_data->pfm_dcr_pp    = 0;
+		this_cpu(pfm_syst_wide) = 1;
+		this_cpu(pfm_dcr_pp)    = 0;
 #endif
 	} else {
 		/*
@@ -2089,21 +2230,21 @@
 		ia64_psr(regs)->pp = 0; /* just to make sure! */
 		ia64_psr(regs)->up = 0;
 
+		/* make sure monitoring is stopped */
 		__asm__ __volatile__ ("rum psr.up;;"::: "memory");
-		/*
-		 * allow user control (user monitors only)
-		if (task  == ctx->ctx_owner) {
-		 */
-		{
-			DBprintk(("clearing psr.sp for [%d]\n", current->pid));
-			ia64_psr(regs)->sp = 0;
-		}
+		ia64_srlz_i();
+
+		DBprintk(("clearing psr.sp for [%d]\n", current->pid));
+
+		/* allow user level control  */
+		ia64_psr(regs)->sp = 0;
+
+		/* PMU state will be saved/restored on ctxsw */
 		task->thread.flags |= IA64_THREAD_PM_VALID;
 	}
 
 	SET_PMU_OWNER(task);
 
-
 	ctx->ctx_flags.state = PFM_CTX_ENABLED;
 	atomic_set(&ctx->ctx_last_cpu, smp_processor_id());
 
@@ -2114,6 +2255,40 @@
 	return 0;
 }
 
+static int
+pfm_get_pmc_reset(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
+	   struct pt_regs *regs)
+{
+	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
+	unsigned int cnum;
+	int i;
+
+	for (i = 0; i < count; i++, req++) {
+
+		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+
+		cnum = tmp.reg_num;
+
+		if (!PMC_IS_IMPL(cnum)) goto abort_mission;
+
+		tmp.reg_value = reset_pmcs[cnum];
+
+		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
+
+		DBprintk(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, tmp.reg_value)); 
+
+		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+	}
+	return 0;
+abort_mission:
+	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+	/* 
+	 * XXX: if this fails, we stick with the original failure, flag not updated!
+	 */
+	copy_to_user(req, &tmp, sizeof(tmp));
+	return -EINVAL;
+}
+
 /*
  * functions MUST be listed in the increasing order of their index (see permfon.h)
  */
@@ -2121,19 +2296,19 @@
 /* 0  */{ NULL, 0, 0, 0}, /* not used */
 /* 1  */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
 /* 2  */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
-/* 3  */{ pfm_read_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
+/* 3  */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
 /* 4  */{ pfm_stop, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 5  */{ pfm_start, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 6  */{ pfm_enable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 7  */{ pfm_disable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 8  */{ pfm_create_context, PFM_CMD_ARG_READ, 1, sizeof(pfarg_context_t)},
-/* 9  */{ pfm_destroy_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
+/* 8  */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, 1, sizeof(pfarg_context_t)},
+/* 9  */{ pfm_context_destroy, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 10 */{ pfm_restart, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_NOCHK, 0, 0},
 /* 11 */{ pfm_protect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 12 */{ pfm_get_features, PFM_CMD_ARG_WRITE, 0, 0},
 /* 13 */{ pfm_debug, 0, 1, sizeof(unsigned int)},
-/* 14 */{ pfm_unprotect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 15 */{ NULL, 0, 0, 0}, /* not used */
+/* 14 */{ pfm_context_unprotect, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
+/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
 /* 16 */{ NULL, 0, 0, 0}, /* not used */
 /* 17 */{ NULL, 0, 0, 0}, /* not used */
 /* 18 */{ NULL, 0, 0, 0}, /* not used */
@@ -2167,19 +2342,10 @@
 	 * after the task is marked as STOPPED but before pfm_save_regs()
 	 * is completed.
 	 */
-	for (;;) {
-
-		task_lock(task);
-		if (1 /*XXX !task_has_cpu(task)*/) break;
-		task_unlock(task);
-
-		do {
-			if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) return -EBUSY;
-			barrier();
-			cpu_relax();
-		} while (0 /*task_has_cpu(task)*/);
-	}
-	task_unlock(task);
+	if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) return -EBUSY;
+	DBprintk(("before wait_task_inactive [%d] state %ld\n", task->pid, task->state));
+	wait_task_inactive(task);
+	DBprintk(("after wait_task_inactive [%d] state %ld\n", task->pid, task->state));
 #else
 	if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) {
 		DBprintk(("warning [%d] not in stable state %ld\n", task->pid, task->state));
@@ -2273,7 +2439,7 @@
 }
 
 void
-pfm_ovfl_block_reset (void)
+pfm_ovfl_block_reset(void)
 {
 	struct thread_struct *th = &current->thread;
 	pfm_context_t *ctx = current->thread.pfm_context;
@@ -2353,18 +2519,17 @@
 	int j;
 
 
-pfm_recorded_samples_count++;
 	idx = ia64_fetch_and_add(1, &psb->psb_index);
-	DBprintk(("recording index=%ld entries=%ld\n", idx-1, psb->psb_entries));
+	DBprintk_ovfl(("recording index=%ld entries=%ld\n", idx-1, psb->psb_entries));
 
 	/*
-	* XXX: there is a small chance that we could run out on index before resetting
-	* but index is unsigned long, so it will take some time.....
-	* We use > instead of == because fetch_and_add() is off by one (see below)
-	*
-	* This case can happen in non-blocking mode or with multiple processes.
-	* For non-blocking, we need to reload and continue.
-	 */
+	 * XXX: there is a small chance that we could run out on index before resetting
+	 * but index is unsigned long, so it will take some time.....
+	 * We use > instead of == because fetch_and_add() is off by one (see below)
+	 *
+	 * This case can happen in non-blocking mode or with multiple processes.
+	 * For non-blocking, we need to reload and continue.
+ 	 */
 	if (idx > psb->psb_entries) return 0;
 
 	/* first entry is really entry 0, not 1 caused by fetch_and_add */
@@ -2375,7 +2540,7 @@
 	/*
 	 * initialize entry header
 	 */
-	h->pid  = task->pid;
+	h->pid  = current->pid;
 	h->cpu  = smp_processor_id();
 	h->rate = 0; /* XXX: add the sampling rate used here */
 	h->ip   = regs ? regs->cr_iip : 0x0;	/* where did the fault happened */
@@ -2403,24 +2568,27 @@
 		} else {
 			*e = ia64_get_pmd(j); /* slow */
 		}
-		DBprintk(("e=%p pmd%d =0x%lx\n", (void *)e, j, *e));
+		DBprintk_ovfl(("e=%p pmd%d =0x%lx\n", (void *)e, j, *e));
 		e++;
 	}
+	pfm_stats.pfm_recorded_samples_count++;
+
 	/*
 	 * make the new entry visible to user, needs to be atomic
 	 */
 	ia64_fetch_and_add(1, &psb->psb_hdr->hdr_count);
 
-	DBprintk(("index=%ld entries=%ld hdr_count=%ld\n", 
+	DBprintk_ovfl(("index=%ld entries=%ld hdr_count=%ld\n", 
 				idx, psb->psb_entries, psb->psb_hdr->hdr_count));
 	/* 
 	 * sampling buffer full ? 
 	 */
 	if (idx == (psb->psb_entries-1)) {
-		DBprintk(("sampling buffer full\n"));
+		DBprintk_ovfl(("sampling buffer full\n"));
 		/*
 		 * XXX: must reset buffer in blocking mode and lost notified
 		 */
+		pfm_stats.pfm_full_smpl_buffer_count++;
 		return 1;
 	}
 	return 0;
@@ -2433,15 +2601,13 @@
  *	new value of pmc[0]. if 0x0 then unfreeze, else keep frozen
  */
 static unsigned long
-pfm_overflow_handler(struct task_struct *task, u64 pmc0, struct pt_regs *regs)
+pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs)
 {
 	unsigned long mask;
 	struct thread_struct *t;
-	pfm_context_t *ctx;
 	unsigned long old_val;
 	unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL;
 	int i;
-	int my_cpu = smp_processor_id();
 	int ret = 1;
 	struct siginfo si;
 	/*
@@ -2457,18 +2623,7 @@
 	 * valid one, i.e. the one that caused the interrupt.
 	 */
 
-	if (task == NULL) {
-		DBprintk(("owners[%d]=NULL\n", my_cpu));
-		return 0x1;
-	}
 	t   = &task->thread;
-	ctx = task->thread.pfm_context;
-
-	if (!ctx) {
-		printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", 
-			task->pid);
-		return 0;
-	}
 
 	/*
 	 * XXX: debug test
@@ -2490,12 +2645,12 @@
 
 	mask = pmc0 >> PMU_FIRST_COUNTER;
 
-	DBprintk(("pmc0=0x%lx pid=%d iip=0x%lx, %s"
-		  " mode used_pmds=0x%lx save_pmcs=0x%lx reload_pmcs=0x%lx\n", 
+	DBprintk_ovfl(("pmc0=0x%lx pid=%d iip=0x%lx, %s"
+		  " mode used_pmds=0x%lx used_pmcs=0x%lx reload_pmcs=0x%lx\n", 
 			pmc0, task->pid, (regs ? regs->cr_iip : 0), 
 			CTX_OVFL_NOBLOCK(ctx) ? "nonblocking" : "blocking",
 			ctx->ctx_used_pmds[0],
-			ctx->ctx_saved_pmcs[0],
+			ctx->ctx_used_pmcs[0],
 			ctx->ctx_reload_pmcs[0]));
 
 	/*
@@ -2506,7 +2661,7 @@
 		/* skip pmd which did not overflow */
 		if ((mask & 0x1) == 0) continue;
 
-		DBprintk(("PMD[%d] overflowed hw_pmd=0x%lx soft_pmd=0x%lx\n", 
+		DBprintk_ovfl(("pmd[%d] overflowed hw_pmd=0x%lx soft_pmd=0x%lx\n", 
 			  i, ia64_get_pmd(i), ctx->ctx_soft_pmds[i].val));
 
 		/*
@@ -2518,8 +2673,7 @@
 		old_val = ctx->ctx_soft_pmds[i].val;
 		ctx->ctx_soft_pmds[i].val = 1 + pmu_conf.perf_ovfl_val + pfm_read_soft_counter(ctx, i);
 
-
-		DBprintk(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx\n", 
+		DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx\n", 
 			  i, ctx->ctx_soft_pmds[i].val, old_val, 
 			  ia64_get_pmd(i) & pmu_conf.perf_ovfl_val));
 
@@ -2536,7 +2690,7 @@
 
 			ovfl_pmds |= 1UL << i;
 
-			DBprintk(("soft_pmd[%d] overflowed flags=0x%x, ovfl=0x%lx\n", i, ctx->ctx_soft_pmds[i].flags, ovfl_pmds));
+			DBprintk_ovfl(("soft_pmd[%d] overflowed flags=0x%x, ovfl=0x%lx\n", i, ctx->ctx_soft_pmds[i].flags, ovfl_pmds));
 
 			if (PMC_OVFL_NOTIFY(ctx, i)) {
 				ovfl_notify |= 1UL << i;
@@ -2575,7 +2729,8 @@
 	 * No overflow requiring a user level notification
 	 */
 	if (ovfl_notify == 0UL) {
-		pfm_reset_regs(ctx, &ovfl_pmds, PFM_RELOAD_SHORT_RESET);
+		if (ovfl_pmds) 
+			pfm_reset_regs(ctx, &ovfl_pmds, PFM_RELOAD_SHORT_RESET);
 		return 0x0;
 	}
 
@@ -2650,7 +2805,7 @@
 	 	 * necessarily go to the signal handler (if any) when it goes back to
 	 	 * user mode.
 	 	 */
-		DBprintk(("[%d] sending notification to [%d]\n", 
+		DBprintk_ovfl(("[%d] sending notification to [%d]\n", 
 			  task->pid, ctx->ctx_notify_task->pid));
 
 
@@ -2683,7 +2838,7 @@
 		 * before, changing it to NULL will still maintain this invariant.
 		 * Of course, when it is equal to current it cannot change at this point.
 		 */
-		DBprintk(("block=%d notify [%d] current [%d]\n", 
+		DBprintk_ovfl(("block=%d notify [%d] current [%d]\n", 
 			ctx->ctx_fl_block,
 			ctx->ctx_notify_task ? ctx->ctx_notify_task->pid: -1, 
 			current->pid ));
@@ -2694,7 +2849,7 @@
 	} else {
 lost_notify: /* XXX: more to do here, to convert to non-blocking (reset values) */
 
-		DBprintk(("notification task has disappeared !\n"));
+		DBprintk_ovfl(("notification task has disappeared !\n"));
 		/*
 		 * for a non-blocking context, we make sure we do not fall into the 
 		 * pfm_overflow_notify() trap. Also in the case of a blocking context with lost 
@@ -2716,7 +2871,7 @@
 	 */
 	ctx->ctx_fl_frozen = 1;
 
-	DBprintk(("reload pmc0=0x%x must_block=%ld\n",
+	DBprintk_ovfl(("return pmc0=0x%x must_block=%ld\n",
 				ctx->ctx_fl_frozen ? 0x1 : 0x0, t->pfm_ovfl_block_reset));
 
 	return ctx->ctx_fl_frozen ? 0x1 : 0x0;
@@ -2727,8 +2882,9 @@
 {
 	u64 pmc0;
 	struct task_struct *task;
+	pfm_context_t *ctx;
 
-	pfm_ovfl_intr_count++;
+	pfm_stats.pfm_ovfl_intr_count++;
 
 	/* 
 	 * srlz.d done before arriving here
@@ -2742,24 +2898,54 @@
 	 * assumes : if any PM[0].bit[63-1] is set, then PMC[0].fr = 1
 	 */
 	if ((pmc0 & ~0x1UL)!=0UL && (task=PMU_OWNER())!= NULL) {
-
 		/* 
-		 * assumes, PMC[0].fr = 1 at this point 
-		 *
-		 * XXX: change protype to pass &pmc0
+		 * we assume that pmc0.fr is always set here
 		 */
-		pmc0 = pfm_overflow_handler(task, pmc0, regs);
+		ctx = task->thread.pfm_context;
 
-		/* we never explicitely freeze PMU here */
-		if (pmc0 == 0) {
-			ia64_set_pmc(0, 0);
-			ia64_srlz_d();
+		/* sanity check */
+		if (!ctx) {
+			printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", 
+				task->pid);
+			return;
 		}
+#ifdef CONFIG_SMP
+		/*
+		 * Because an IPI has higher priority than the PMU overflow interrupt, it is 
+		 * possible that the handler be interrupted by a request from another CPU to fetch 
+		 * the PMU state of the currently active context. The task may have just been 
+		 * migrated to another CPU which is trying to restore the context. If there was
+		 * a pending overflow interrupt when the task left this CPU, it is possible for
+		 * the handler to get interrupt by the IPI. In which case, we fetch request
+		 * MUST be postponed until the interrupt handler is done. The ctx_is_busy
+		 * flag indicates such a condition. The other CPU must busy wait until it's cleared.
+		 */
+		atomic_set(&ctx->ctx_is_busy, 1);
+#endif
+
+		/* 
+		 * assume PMC[0].fr = 1 at this point 
+		 */
+		pmc0 = pfm_overflow_handler(task, ctx, pmc0, regs);
+
+		/*
+		 * We always clear the overflow status bits and either unfreeze
+		 * or keep the PMU frozen.
+		 */
+		ia64_set_pmc(0, pmc0);
+		ia64_srlz_d();
+
+#ifdef CONFIG_SMP
+		/*
+		 * announce that we are doing with the context
+		 */
+		atomic_set(&ctx->ctx_is_busy, 0);
+#endif
 	} else {
-		pfm_spurious_ovfl_intr_count++;
+		pfm_stats.pfm_spurious_ovfl_intr_count++;
 
-		DBprintk(("perfmon: Spurious PMU overflow interrupt on CPU%d: pmc0=0x%lx owner=%p\n", 
-			smp_processor_id(), pmc0, (void *)PMU_OWNER()));
+		printk("perfmon: Spurious PMU overflow interrupt on CPU%d: pmc0=0x%lx owner=%p\n", 
+			smp_processor_id(), pmc0, (void *)PMU_OWNER());
 	}
 }
 
@@ -2773,27 +2959,30 @@
 #define cpu_is_online(i)        1
 #endif
 	char *p = page;
-	u64 pmc0 = ia64_get_pmc(0);
 	int i;
 
-	p += sprintf(p, "perfmon enabled: %s\n", pmu_conf.pfm_is_disabled ? "No": "Yes");
-
-	p += sprintf(p, "monitors_pmcs0]=0x%lx\n", pmu_conf.monitor_pmcs[0]);
-	p += sprintf(p, "counter_pmcds[0]=0x%lx\n", pmu_conf.counter_pmds[0]);
-	p += sprintf(p, "overflow interrupts=%lu\n", pfm_ovfl_intr_count);
-	p += sprintf(p, "spurious overflow interrupts=%lu\n", pfm_spurious_ovfl_intr_count);
-	p += sprintf(p, "recorded samples=%lu\n", pfm_recorded_samples_count);
-
-	p += sprintf(p, "CPU%d.pmc[0]=%lx\nPerfmon debug: %s\n", 
-			smp_processor_id(), pmc0, pfm_debug_mode ? "On" : "Off");
+	p += sprintf(p, "enabled          : %s\n", pmu_conf.pfm_is_disabled ? "No": "Yes");
+	p += sprintf(p, "fastctxsw        : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No");
+	p += sprintf(p, "ovfl_mask        : 0x%lx\n", pmu_conf.perf_ovfl_val);
+	p += sprintf(p, "overflow intrs   : %lu\n", pfm_stats.pfm_ovfl_intr_count);
+	p += sprintf(p, "spurious intrs   : %lu\n", pfm_stats.pfm_spurious_ovfl_intr_count);
+	p += sprintf(p, "recorded samples : %lu\n", pfm_stats.pfm_recorded_samples_count);
+	p += sprintf(p, "smpl buffer full : %lu\n", pfm_stats.pfm_full_smpl_buffer_count);
 
 #ifdef CONFIG_SMP
-	p += sprintf(p, "CPU%d cpu_data.pfm_syst_wide=%d cpu_data.dcr_pp=%d\n", 
-			smp_processor_id(), local_cpu_data->pfm_syst_wide, local_cpu_data->pfm_dcr_pp);
+	p += sprintf(p, "CPU%d syst_wide   : %d\n"
+			"CPU%d dcr_pp      : %d\n", 
+			smp_processor_id(), 
+			this_cpu(pfm_syst_wide), 
+			smp_processor_id(), 
+			this_cpu(pfm_dcr_pp));
 #endif
 
 	LOCK_PFS();
-	p += sprintf(p, "proc_sessions=%lu\nsys_sessions=%lu\nsys_use_dbregs=%lu\nptrace_use_dbregs=%lu\n", 
+	p += sprintf(p, "proc_sessions    : %lu\n"
+			"sys_sessions     : %lu\n"
+			"sys_use_dbregs   : %lu\n"
+			"ptrace_use_dbregs: %lu\n", 
 			pfm_sessions.pfs_task_sessions, 
 			pfm_sessions.pfs_sys_sessions,
 			pfm_sessions.pfs_sys_use_dbregs,
@@ -2803,12 +2992,28 @@
 
 	for(i=0; i < NR_CPUS; i++) {
 		if (cpu_is_online(i)) {
-			p += sprintf(p, "CPU%d.pmu_owner: %-6d\n",
+			p += sprintf(p, "CPU%d owner : %-6d\n",
 					i, 
 					pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1);
 		}
 	}
 
+	for(i=0; pmd_desc[i].type != PFM_REG_NONE; i++) {
+		p += sprintf(p, "PMD%-2d: %d 0x%lx 0x%lx\n", 
+				i,
+				pmd_desc[i].type, 
+				pmd_desc[i].dep_pmd[0], 
+				pmd_desc[i].dep_pmc[0]); 
+	}
+
+	for(i=0; pmc_desc[i].type != PFM_REG_NONE; i++) {
+		p += sprintf(p, "PMC%-2d: %d 0x%lx 0x%lx\n", 
+				i, 
+				pmc_desc[i].type, 
+				pmc_desc[i].dep_pmd[0], 
+				pmc_desc[i].dep_pmc[0]); 
+	}
+
 	return p - page;
 }
 
@@ -2840,7 +3045,7 @@
 	/*
 	 * propagate the value of the dcr_pp bit to the psr
 	 */
-	ia64_psr(regs)->pp = mode ? local_cpu_data->pfm_dcr_pp : 0;
+	ia64_psr(regs)->pp = mode ? this_cpu(pfm_dcr_pp) : 0;
 }
 #endif
 
@@ -2867,6 +3072,7 @@
 	 * It will be restored from ipsr when going back to user level
 	 */
 	__asm__ __volatile__ ("rum psr.up;;"::: "memory");
+	ia64_srlz_i();
 
 	ctx->ctx_saved_psr = psr;
 
@@ -2922,13 +3128,9 @@
 	for (i=0; mask; i++, mask>>=1) {
 		if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i);
 	}
-	/*
-	 * XXX: simplify to pmc0 only
-	 */
-	mask = ctx->ctx_saved_pmcs[0];
-	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i);
-	}
+
+	/* save pmc0 */
+	t->pmc[0] = ia64_get_pmc(0);
 
 	/* not owned by this CPU */
 	atomic_set(&ctx->ctx_last_cpu, -1);
@@ -2966,6 +3168,12 @@
 		  PMU_OWNER() ? PMU_OWNER()->pid: -1,
 		  atomic_read(&ctx->ctx_saving_in_progress)));
 
+	/* must wait until not busy before retrying whole request */
+	if (atomic_read(&ctx->ctx_is_busy)) {
+		arg->retval = 2;
+		return;
+	}
+
 	/* must wait if saving was interrupted */
 	if (atomic_read(&ctx->ctx_saving_in_progress)) {
 		arg->retval = 1;
@@ -2978,9 +3186,9 @@
 		return;
 	}
 
-	DBprintk(("saving state for [%d] save_pmcs=0x%lx all_pmcs=0x%lx used_pmds=0x%lx\n", 
+	DBprintk(("saving state for [%d] used_pmcs=0x%lx reload_pmcs=0x%lx used_pmds=0x%lx\n", 
 		arg->task->pid,
-		ctx->ctx_saved_pmcs[0],
+		ctx->ctx_used_pmcs[0],
 		ctx->ctx_reload_pmcs[0],
 		ctx->ctx_used_pmds[0]));
 
@@ -2993,17 +3201,15 @@
 
 	/*
 	 * XXX needs further optimization.
-	 * Also must take holes into account
 	 */
 	mask = ctx->ctx_used_pmds[0];
 	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i);
-	}
-	
-	mask = ctx->ctx_saved_pmcs[0];
-	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i);
+		if (mask & 0x1) t->pmd[i] = ia64_get_pmd(i);
 	}
+
+	/* save pmc0 */
+	t->pmc[0] = ia64_get_pmc(0);
+
 	/* not owned by this CPU */
 	atomic_set(&ctx->ctx_last_cpu, -1);
 
@@ -3032,11 +3238,17 @@
 	arg.task   = task;
 	arg.retval = -1;
 
+	if (atomic_read(&ctx->ctx_is_busy)) {
+must_wait_busy:
+		while (atomic_read(&ctx->ctx_is_busy));
+	}
+
 	if (atomic_read(&ctx->ctx_saving_in_progress)) {
 		DBprintk(("no IPI, must wait for [%d] to be saved on [%d]\n", task->pid, cpu));
-
+must_wait_saving:
 		/* busy wait */
 		while (atomic_read(&ctx->ctx_saving_in_progress));
+		DBprintk(("done saving for [%d] on [%d]\n", task->pid, cpu));
 		return;
 	}
 	DBprintk(("calling CPU %d from CPU %d\n", cpu, smp_processor_id()));
@@ -3056,11 +3268,8 @@
 	 * This is the case, where we interrupted the saving which started just at the time we sent the
 	 * IPI.
 	 */
-	if (arg.retval == 1) {
-		DBprintk(("must wait for [%d] to be saved on [%d]\n", task->pid, cpu));
-		while (atomic_read(&ctx->ctx_saving_in_progress));
-		DBprintk(("done saving for [%d] on [%d]\n", task->pid, cpu));
-	}
+	if (arg.retval == 1) goto must_wait_saving;
+	if (arg.retval == 2) goto must_wait_busy;
 }
 #endif /* CONFIG_SMP */
 
@@ -3114,55 +3323,53 @@
 		pfm_fetch_regs(cpu, task, ctx);
 	}
 #endif
-	t   = &task->thread;
+	t = &task->thread;
 
 	/*
-	 * XXX: will be replaced by assembly routine
-	 * We clear all unused PMDs to avoid leaking information
+	 * To avoid leaking information to the user level when psr.sp=0,
+	 * we must reload ALL implemented pmds (even the ones we don't use).
+	 * In the kernel we only allow PFM_READ_PMDS on registers which
+	 * we initialized or requested (sampling) so there is no risk there.
+	 *
+	 * As an optimization, we will only reload the PMD that we use when 
+	 * the context is in protected mode, i.e. psr.sp=1 because then there
+	 * is no leak possible.
 	 */
-	mask = ctx->ctx_used_pmds[0];
+	mask = pfm_sysctl.fastctxsw || ctx->ctx_fl_protected ?  ctx->ctx_used_pmds[0] : ctx->ctx_reload_pmds[0];
 	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) 
-			ia64_set_pmd(i, t->pmd[i]);
-		else
-			ia64_set_pmd(i, 0UL);
+		if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.perf_ovfl_val);
 	}
-	/* XXX: will need to clear all unused pmd, for security */
 
 	/* 
-	 * skip pmc[0] to avoid side-effects, 
-	 * all PMCs are systematically reloaded, unsued get default value
-	 * to avoid picking up stale configuration
+	 * PMC0 is never set in the mask because it is always restored
+	 * separately.  
+	 *
+	 * ALL PMCs are systematically reloaded, unused registers
+	 * get their default (PAL reset) values to avoid picking up 
+	 * stale configuration.
 	 */	
-	mask = ctx->ctx_reload_pmcs[0]>>1;
-	for (i=1; mask; i++, mask>>=1) {
+	mask = ctx->ctx_reload_pmcs[0];
+	for (i=0; mask; i++, mask>>=1) {
 		if (mask & 0x1) ia64_set_pmc(i, t->pmc[i]);
 	}
 
 	/*
-	 * restore debug registers when used for range restrictions.
-	 * We must restore the unused registers to avoid picking up
-	 * stale information.
+	 * we restore ALL the debug registers to avoid picking up 
+	 * stale state.
 	 */
-	mask = ctx->ctx_used_ibrs[0];
-	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) 
+	if (ctx->ctx_fl_using_dbreg) {
+		for (i=0; i < pmu_conf.num_ibrs; i++) {
 			ia64_set_ibr(i, t->ibr[i]);
-		else
-			ia64_set_ibr(i, 0UL);
-	}
-
-	mask = ctx->ctx_used_dbrs[0];
-	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) 
+		}
+		ia64_srlz_i();
+		for (i=0; i < pmu_conf.num_dbrs; i++) {
 			ia64_set_dbr(i, t->dbr[i]);
-		else
-			ia64_set_dbr(i, 0UL);
+		}
 	}
+	ia64_srlz_d();
 
 	if (t->pmc[0] & ~0x1) {
-		ia64_srlz_d();
-		pfm_overflow_handler(task, t->pmc[0], NULL);
+		pfm_overflow_handler(task, ctx, t->pmc[0], NULL);
 	}
 
 	/*
@@ -3215,7 +3422,7 @@
 			 * When restoring context, we must restore ALL pmcs, even the ones 
 			 * that the task does not use to avoid leaks and possibly corruption
 			 * of the sesion because of configuration conflicts. So here, we 
-			 * initializaed the table used in the context switch restore routine.
+			 * initialize the entire set used in the context switch restore routine.
 	 		 */
 			t->pmc[i] = reset_pmcs[i];
 			DBprintk((" pmc[%d]=0x%lx\n", i, reset_pmcs[i]));
@@ -3224,39 +3431,61 @@
 	}
 	/*
 	 * clear reset values for PMD. 
-	 * XX: good up to 64 PMDS. Suppose that zero is a valid value.
+	 * XXX: good up to 64 PMDS. Suppose that zero is a valid value.
 	 */
 	mask = pmu_conf.impl_regs[4];
 	for(i=0; mask; mask>>=1, i++) {
 		if (mask & 0x1) ia64_set_pmd(i, 0UL);
+		t->pmd[i] = 0UL;
 	}
 
 	/*
-	 * On context switched restore, we must restore ALL pmc even
+	 * On context switched restore, we must restore ALL pmc and ALL pmd even
 	 * when they are not actively used by the task. In UP, the incoming process 
-	 * may otherwise pick up left over PMC state from the previous process.
+	 * may otherwise pick up left over PMC, PMD state from the previous process.
 	 * As opposed to PMD, stale PMC can cause harm to the incoming
 	 * process because they may change what is being measured. 
 	 * Therefore, we must systematically reinstall the entire
 	 * PMC state. In SMP, the same thing is possible on the 
-	 * same CPU but also on between 2 CPUs.
+	 * same CPU but also on between 2 CPUs. 
+	 *
+	 * The problem with PMD is information leaking especially
+	 * to user level when psr.sp=0
 	 *
 	 * There is unfortunately no easy way to avoid this problem
-	 * on either UP or SMP. This definitively slows down the 
-	 * pfm_load_regs(). 
+	 * on either UP or SMP. This definitively slows down the
+	 * pfm_load_regs() function. 
 	 */
 	
 	 /*
 	  * We must include all the PMC in this mask to make sure we don't
-	  * see any side effect of the stale state, such as opcode matching
+	  * see any side effect of a stale state, such as opcode matching
 	  * or range restrictions, for instance.
+	  *
+	  * We never directly restore PMC0 so we do not include it in the mask.
 	  */
-	ctx->ctx_reload_pmcs[0] = pmu_conf.impl_regs[0];
+	ctx->ctx_reload_pmcs[0] = pmu_conf.impl_regs[0] & ~0x1;
+	/*
+	 * We must include all the PMD in this mask to avoid picking
+	 * up stale value and leak information, especially directly
+	 * at the user level when psr.sp=0
+	 */
+	ctx->ctx_reload_pmds[0] = pmu_conf.impl_regs[4];
+
+	/* 
+	 * Keep track of the pmds we want to sample
+	 * XXX: may be we don't need to save/restore the DEAR/IEAR pmds
+	 * but we do need the BTB for sure. This is because of a hardware
+	 * buffer of 1 only for non-BTB pmds.
+	 *
+	 * We ignore the unimplemented pmds specified by the user
+	 */
+	ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0] & pmu_conf.impl_regs[4];
+	ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */
 
 	/*
 	 * useful in case of re-enable after disable
 	 */
-	ctx->ctx_used_pmds[0] = 0UL;
 	ctx->ctx_used_ibrs[0] = 0UL;
 	ctx->ctx_used_dbrs[0] = 0UL;
 
@@ -3278,7 +3507,7 @@
 {
 	pfm_context_t *ctx;
 	u64 pmc0;
-	unsigned long mask, mask2, val;
+	unsigned long mask2, val;
 	int i;
 
 	ctx = task->thread.pfm_context;
@@ -3300,22 +3529,28 @@
 	 */
 	if (ctx->ctx_fl_system) {
 
-		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
 
 		/* disable dcr pp */
 		ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP);
 
+		/* stop monitoring */
+		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
+
+		ia64_srlz_i();
+
 #ifdef CONFIG_SMP
-		local_cpu_data->pfm_syst_wide = 0;
-		local_cpu_data->pfm_dcr_pp    = 0;
+		this_cpu(pfm_syst_wide) = 0;
+		this_cpu(pfm_dcr_pp)    = 0;
 #else
 		pfm_tasklist_toggle_pp(0);
 #endif
-
 	} else  {
 
+		/* stop monitoring */
 		__asm__ __volatile__ ("rum psr.up;;"::: "memory");
 
+		ia64_srlz_i();
+
 		/* no more save/restore on ctxsw */
 		current->thread.flags &= ~IA64_THREAD_PM_VALID;
 	}
@@ -3349,7 +3584,7 @@
 	ia64_srlz_d();
 
 	/*
-	 * We don't need to restore psr, because we are on our way out anyway
+	 * We don't need to restore psr, because we are on our way out
 	 */
 
 	/*
@@ -3365,10 +3600,12 @@
 	if (atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) 
 		printk("perfmon: [%d] last_cpu=%d\n", task->pid, atomic_read(&ctx->ctx_last_cpu));
 
-	mask  = pmc0 >> PMU_FIRST_COUNTER;
-	mask2 = ctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER;
-
-	for (i = PMU_FIRST_COUNTER; mask2; i++, mask>>=1, mask2>>=1) {
+	/*
+	 * we save all the used pmds
+	 * we take care of overflows for pmds used as counters
+	 */
+	mask2 = ctx->ctx_used_pmds[0];
+	for (i = 0; mask2; i++, mask2>>=1) {
 
 		/* skip non used pmds */
 		if ((mask2 & 0x1) == 0) continue;
@@ -3376,7 +3613,6 @@
 		val = ia64_get_pmd(i);
 
 		if (PMD_IS_COUNTING(i)) {
-
 			DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", task->pid, i, ctx->ctx_soft_pmds[i].val, val & pmu_conf.perf_ovfl_val));
 
 			/* collect latest results */
@@ -3389,15 +3625,19 @@
 			 */
 			task->thread.pmd[i] = 0;
 
-			/* take care of overflow inline */
-			if (mask & 0x1) {
+			/* 
+			 * take care of overflow inline
+			 */
+			if (pmc0 & (1UL << i)) {
 				ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.perf_ovfl_val;
 				DBprintk(("[%d] pmd[%d] overflowed soft_pmd=0x%lx\n",
 					task->pid, i, ctx->ctx_soft_pmds[i].val));
 			}
 		} else {
 			DBprintk(("[%d] pmd[%d] hw_pmd=0x%lx\n", task->pid, i, val));
-			/* not a counter, just save value as is */
+			/* 
+			 * not a counter, just save value as is
+			 */
 			task->thread.pmd[i] = val;
 		}
 	}
@@ -3409,38 +3649,78 @@
 }
 
 
-
 /*
  * task is the newly created task, pt_regs for new child
  */
 int
 pfm_inherit(struct task_struct *task, struct pt_regs *regs)
 {
-	pfm_context_t *ctx = current->thread.pfm_context;
+	pfm_context_t *ctx;
 	pfm_context_t *nctx;
-	struct thread_struct *th = &task->thread;
+	struct thread_struct *thread;
 	unsigned long m;
 	int i;
 
 	/*
+	 * the new task was copied from parent and therefore points
+	 * to the parent's context at this point
+	 */
+	ctx    = task->thread.pfm_context;
+	thread = &task->thread;
+
+	/*
 	 * make sure child cannot mess up the monitoring session
 	 */
 	 ia64_psr(regs)->sp = 1;
 	 DBprintk(("enabling psr.sp for [%d]\n", task->pid));
 
-	 /*
-	  * remove any sampling buffer mapping from child user 
-	  * address space. Must be done for all cases of inheritance.
-	  */
-	 if (ctx->ctx_smpl_vaddr) pfm_remove_smpl_mapping(task);
+
+	/*
+	 * if there was a virtual mapping for the sampling buffer
+	 * the mapping is NOT inherited across fork() (see VM_DONTCOPY), 
+	 * so we don't have to explicitely remove it here. 
+	 *
+	 *
+	 * Part of the clearing of fields is also done in
+	 * copy_thread() because the fiels are outside the
+	 * pfm_context structure and can affect tasks not
+	 * using perfmon.
+	 */
+
+	/* clear pending notification */
+	task->thread.pfm_ovfl_block_reset = 0;
+
+	/*
+	 * clear cpu pinning restriction for child
+	 */
+	if (ctx->ctx_fl_system) {
+		set_cpus_allowed(task, ctx->ctx_saved_cpus_allowed);
+
+	 	DBprintk(("setting cpus_allowed for [%d] to 0x%lx from 0x%lx\n", 
+			task->pid,
+			ctx->ctx_saved_cpus_allowed, 
+			current->cpus_allowed));
+	}
 
 	/*
 	 * takes care of easiest case first
 	 */
 	if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_NONE) {
+
 		DBprintk(("removing PFM context for [%d]\n", task->pid));
-		task->thread.pfm_context     = NULL;
-		task->thread.pfm_ovfl_block_reset  = 0;
+
+		task->thread.pfm_context = NULL;
+
+		/* 
+		 * we must clear psr.up because the new child does
+		 * not have a context and the PM_VALID flag is cleared
+		 * in copy_thread().
+		 *
+		 * we do not clear psr.pp because it is always
+		 * controlled by the system wide logic and we should
+		 * never be here when system wide is running anyway
+		 */
+	 	ia64_psr(regs)->up = 0;
 
 		/* copy_thread() clears IA64_THREAD_PM_VALID */
 		return 0;
@@ -3454,69 +3734,82 @@
 
 	if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_ONCE) {
 		nctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE;
-		atomic_set(&nctx->ctx_last_cpu, -1);
-
-		/*
-		 * task is not yet visible in the tasklist, so we do 
-		 * not need to lock the newly created context.
-		 * However, we must grab the tasklist_lock to ensure
-		 * that the ctx_owner or ctx_notify_task do not disappear
-		 * while we increment their check counters.
-		 */
-		read_lock(&tasklist_lock);
+		DBprintk(("downgrading to INHERIT_NONE for [%d]\n", task->pid));
+	}
+	/*
+	 * task is not yet visible in the tasklist, so we do 
+	 * not need to lock the newly created context.
+	 * However, we must grab the tasklist_lock to ensure
+	 * that the ctx_owner or ctx_notify_task do not disappear
+	 * while we increment their check counters.
+	 */
+	read_lock(&tasklist_lock);
 
-		if (nctx->ctx_notify_task) 
-			atomic_inc(&nctx->ctx_notify_task->thread.pfm_notifiers_check);
+	if (nctx->ctx_notify_task) 
+		atomic_inc(&nctx->ctx_notify_task->thread.pfm_notifiers_check);
 
-		if (nctx->ctx_owner)
-			atomic_inc(&nctx->ctx_owner->thread.pfm_owners_check);
+	if (nctx->ctx_owner)
+		atomic_inc(&nctx->ctx_owner->thread.pfm_owners_check);
 
-		read_unlock(&tasklist_lock);
+	read_unlock(&tasklist_lock);
 
-		DBprintk(("downgrading to INHERIT_NONE for [%d]\n", task->pid));
 
-		LOCK_PFS();
-		pfm_sessions.pfs_task_sessions++;
-		UNLOCK_PFS();
-	}
+	LOCK_PFS();
+	pfm_sessions.pfs_task_sessions++;
+	UNLOCK_PFS();
 
 	/* initialize counters in new context */
-	m = pmu_conf.counter_pmds[0] >> PMU_FIRST_COUNTER;
+	m = nctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER;
 	for(i = PMU_FIRST_COUNTER ; m ; m>>=1, i++) {
-		if (m & 0x1) {
+		if ((m & 0x1) && pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING) {
 			nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].ival & ~pmu_conf.perf_ovfl_val;
-			th->pmd[i]	      	   = nctx->ctx_soft_pmds[i].ival & pmu_conf.perf_ovfl_val;
+			thread->pmd[i]	      	   = nctx->ctx_soft_pmds[i].ival & pmu_conf.perf_ovfl_val;
 		}
+		/* what about the other pmds? zero or keep as is */
 
 	}
-	/* clear BTB index register */
-	th->pmd[16] = 0;
+	/*
+	 * clear BTB index register
+	 * XXX: CPU-model specific knowledge!
+	 */
+	thread->pmd[16] = 0;
 
-	/* if sampling then increment number of users of buffer */
-	if (nctx->ctx_psb) {
 
-		/*
-		 * XXX: nopt very pretty!
-		 */
+	nctx->ctx_fl_frozen    = 0;
+	nctx->ctx_ovfl_regs[0] = 0UL;
+	atomic_set(&nctx->ctx_last_cpu, -1);
+
+	/*
+	 * here nctx->ctx_psb == ctx->ctx_psb
+	 *
+	 * increment reference count to sampling
+	 * buffer, if any. Note that this is independent
+	 * from the virtual mapping. The latter is never
+	 * inherited while the former will be if context
+	 * is setup to something different from PFM_FL_INHERIT_NONE
+	 */
+	if (nctx->ctx_psb) {
 		LOCK_PSB(nctx->ctx_psb);
+
 		nctx->ctx_psb->psb_refcnt++;
+
+	 	DBprintk(("updated smpl @ %p refcnt=%lu psb_flags=0x%x\n", 
+			ctx->ctx_psb->psb_hdr,
+			ctx->ctx_psb->psb_refcnt,
+			ctx->ctx_psb->psb_flags));
+
 		UNLOCK_PSB(nctx->ctx_psb);
+
 		/*
 	 	 * remove any pointer to sampling buffer mapping
 	 	 */
 		nctx->ctx_smpl_vaddr = 0;
 	}
 
-	nctx->ctx_fl_frozen = 0;
-	nctx->ctx_ovfl_regs[0] = 0UL;
-
 	sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */
 
-	/* clear pending notification */
-	th->pfm_ovfl_block_reset = 0;
-
 	/* link with new task */
-	th->pfm_context    = nctx;
+	thread->pfm_context = nctx;
 
 	DBprintk(("nctx=%p for process [%d]\n", (void *)nctx, task->pid));
 
@@ -3526,7 +3819,7 @@
 	 */
 	if (current->thread.flags & IA64_THREAD_PM_VALID) {
 		DBprintk(("setting PM_VALID for [%d]\n", task->pid));
-		th->flags |= IA64_THREAD_PM_VALID;
+		thread->flags |= IA64_THREAD_PM_VALID;
 	}
 
 	return 0;
@@ -3555,9 +3848,9 @@
 
 		LOCK_PSB(psb);
 
-		DBprintk(("sampling buffer from [%d] @%p size %ld vma_flag=0x%x\n",
+		DBprintk(("sampling buffer from [%d] @%p size %ld refcnt=%lu psb_flags=0x%x\n",
 			task->pid,
-			psb->psb_hdr, psb->psb_size, psb->psb_flags));
+			psb->psb_hdr, psb->psb_size, psb->psb_refcnt, psb->psb_flags));
 
 		/*
 		 * in the case where we are the last user, we may be able to free
@@ -3580,7 +3873,7 @@
 			 *
 			 * See pfm_vm_close() and pfm_cleanup_smpl_buf() for more details.
 			 */
-			if ((psb->psb_flags & PFM_PSB_VMA) == 0) {
+			if ((psb->psb_flags & PSB_HAS_VMA) == 0) {
 
 				DBprintk(("cleaning sampling buffer from [%d] @%p size %ld\n",
 					task->pid,
@@ -3612,7 +3905,7 @@
 	 * direct pointer to a task structure thereby bypassing the tasklist. 
 	 * We must make sure that, if we have task!= NULL, the target task is still 
 	 * present and is identical to the initial task specified 
-	 * during pfm_create_context(). It may already be detached from the tasklist but 
+	 * during pfm_context_create(). It may already be detached from the tasklist but 
 	 * that's okay. Note that it is okay if we miss the deadline and the task scans 
 	 * the list for nothing, it will affect performance but not correctness. 
 	 * The correctness is ensured by using the ctx_lock which prevents the 
@@ -3761,6 +4054,8 @@
 		}
 	}
 	read_unlock(&tasklist_lock);
+
+	atomic_set(&task->thread.pfm_owners_check, 0);
 }
 
 
@@ -3818,6 +4113,8 @@
 		}
 	}
 	read_unlock(&tasklist_lock);
+
+	atomic_set(&task->thread.pfm_notifiers_check, 0);
 }
 
 static struct irqaction perfmon_irqaction = {
@@ -3836,6 +4133,12 @@
 		if (i >= pmu_conf.num_pmcs) break;
 		if (PMC_IS_IMPL(i)) reset_pmcs[i] = ia64_get_pmc(i);
 	}
+#ifdef CONFIG_MCKINLEY
+	/*
+	 * set the 'stupid' enable bit to power the PMU!
+	 */
+	reset_pmcs[4] |= 1UL << 23;
+#endif
 }
 
 /*
@@ -3903,23 +4206,12 @@
 	 */
 	pfm_pmu_snapshot();
 
-	/* 
-	 * list the pmc registers used to control monitors 
-	 * XXX: unfortunately this information is not provided by PAL
-	 *
-	 * We start with the architected minimum and then refine for each CPU model
-	 */
-	pmu_conf.monitor_pmcs[0] = PMM(4)|PMM(5)|PMM(6)|PMM(7);
-
 	/*
-	 * architected counters
+	 * setup the register configuration descriptions for the CPU
 	 */
-	pmu_conf.counter_pmds[0] |= PMM(4)|PMM(5)|PMM(6)|PMM(7);
+	pmu_conf.pmc_desc = pmc_desc;
+	pmu_conf.pmd_desc = pmd_desc;
 
-#ifdef CONFIG_ITANIUM
-	pmu_conf.monitor_pmcs[0] |= PMM(10)|PMM(11)|PMM(12);
-	/* Itanium does not add more counters */
-#endif
 	/* we are all set */
 	pmu_conf.pfm_is_disabled = 0;
 
@@ -3928,6 +4220,8 @@
 	 */
 	perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL);
 
+	pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0);
+
 	spin_lock_init(&pfm_sessions.pfs_lock);
 
 	return 0;
@@ -3941,7 +4235,6 @@
 	ia64_set_pmv(IA64_PERFMON_VECTOR);
 	ia64_srlz_d();
 }
-
 
 #else /* !CONFIG_PERFMON */
 
diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
--- a/arch/ia64/kernel/process.c	Wed May 29 11:43:03 2002
+++ b/arch/ia64/kernel/process.c	Wed May 29 11:43:03 2002
@@ -194,13 +194,15 @@
 		pfm_save_regs(task);
 
 # ifdef CONFIG_SMP
-	if (local_cpu_data->pfm_syst_wide)
+	if (this_cpu(pfm_syst_wide))
 		pfm_syst_wide_update_task(task, 0);
 # endif
 #endif
 
+#ifdef CONFIG_IA32_SUPPORT
 	if (IS_IA32_PROCESS(ia64_task_regs(task)))
 		ia32_save_state(task);
+#endif
 }
 
 void
@@ -214,12 +216,14 @@
 		pfm_load_regs(task);
 
 # ifdef CONFIG_SMP
-	if (local_cpu_data->pfm_syst_wide) pfm_syst_wide_update_task(task, 1);
+	if (this_cpu(pfm_syst_wide)) pfm_syst_wide_update_task(task, 1);
 # endif
 #endif
 
+#ifdef CONFIG_IA32_SUPPORT
 	if (IS_IA32_PROCESS(ia64_task_regs(task)))
 		ia32_load_state(task);
+#endif
 }
 
 /*
@@ -357,6 +361,8 @@
 	 */
 	atomic_set(&p->thread.pfm_notifiers_check, 0);
 	atomic_set(&p->thread.pfm_owners_check, 0);
+	/* clear list of sampling buffer to free for new task */
+	p->thread.pfm_smpl_buf_list = NULL;
 
 	if (current->thread.pfm_context) retval = pfm_inherit(p, child_ptregs);
 #endif
@@ -566,9 +572,8 @@
 		pfm_flush_regs(current);
 
 	/* free debug register resources */
-	if ((current->thread.flags & IA64_THREAD_DBG_VALID) != 0) {
+	if (current->thread.flags & IA64_THREAD_DBG_VALID)
 		pfm_release_debug_registers(current);
-	}
 #endif
 }
 
diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
--- a/arch/ia64/kernel/setup.c	Wed May 29 11:43:01 2002
+++ b/arch/ia64/kernel/setup.c	Wed May 29 11:43:01 2002
@@ -395,7 +395,7 @@
 
 	switch (c->family) {
 	      case 0x07:	memcpy(family, "Itanium", 8); break;
-	      case 0x1f:	memcpy(family, "Itanium 2", 9); break;
+	      case 0x1f:	memcpy(family, "Itanium 2", 10); break;
 	      default:		sprintf(family, "%u", c->family); break;
 	}
 
@@ -559,6 +559,20 @@
 	 */
 	identify_cpu(my_cpu_info);
 
+#ifdef CONFIG_MCKINLEY
+	{
+#define FEATURE_SET 16
+		struct ia64_pal_retval iprv;
+
+		if (my_cpu_info->family == 0x1f) {
+			PAL_CALL_PHYS(iprv, PAL_PROC_GET_FEATURES, 0, FEATURE_SET, 0);
+			if ((iprv.status == 0) && (iprv.v0 & 0x80) && (iprv.v2 & 0x80))
+				PAL_CALL_PHYS(iprv, PAL_PROC_SET_FEATURES,
+				              (iprv.v1 | 0x80), FEATURE_SET, 0);
+		}
+	}
+#endif
+
 	/* Clear the stack memory reserved for pt_regs: */
 	memset(ia64_task_regs(current), 0, sizeof(struct pt_regs));
 
@@ -570,7 +584,7 @@
 	 * shouldn't be affected by this (moral: keep your ia32 locks aligned and you'll
 	 * be fine).
 	 */
-	ia64_set_dcr(  IA64_DCR_DM | IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR
+	ia64_set_dcr(  IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR
 		     | IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC);
 #ifndef CONFIG_SMP
 	ia64_set_fpu_owner(0);
diff -Nru a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
--- a/arch/ia64/kernel/signal.c	Wed May 29 11:43:01 2002
+++ b/arch/ia64/kernel/signal.c	Wed May 29 11:43:01 2002
@@ -143,9 +143,10 @@
 {
 	if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t)))
 		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
+	if (from->si_code < 0) {
+		if (__copy_to_user(to, from, sizeof(siginfo_t)))
+			return -EFAULT;
+	} else {
 		int err;
 
 		/*
diff -Nru a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c
--- a/arch/ia64/lib/swiotlb.c	Wed May 29 11:43:03 2002
+++ b/arch/ia64/lib/swiotlb.c	Wed May 29 11:43:03 2002
@@ -478,6 +478,17 @@
 	return SG_ENT_PHYS_ADDRESS(sg);
 }
 
+/*
+ * Return whether the given PCI device DMA address mask can be supported properly.  For
+ * example, if your device can only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
+int
+swiotlb_pci_dma_supported (struct pci_dev *hwdev, u64 mask)
+{
+	return 1;
+}
+
 EXPORT_SYMBOL(swiotlb_init);
 EXPORT_SYMBOL(swiotlb_map_single);
 EXPORT_SYMBOL(swiotlb_unmap_single);
@@ -488,3 +499,4 @@
 EXPORT_SYMBOL(swiotlb_dma_address);
 EXPORT_SYMBOL(swiotlb_alloc_consistent);
 EXPORT_SYMBOL(swiotlb_free_consistent);
+EXPORT_SYMBOL(swiotlb_pci_dma_supported);
diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
--- a/arch/ia64/mm/init.c	Wed May 29 11:43:02 2002
+++ b/arch/ia64/mm/init.c	Wed May 29 11:43:02 2002
@@ -206,7 +206,6 @@
 	printk("%d pages shared\n", shared);
 	printk("%d pages swap cached\n", cached);
 	printk("%ld pages in page table cache\n", pgtable_cache_size);
-	printk("%ld buffermem pages\n", nr_buffermem_pages());
 #endif /* !CONFIG_DISCONTIGMEM */
 }
 
@@ -251,7 +250,7 @@
 void __init
 ia64_mmu_init (void *my_cpu_data)
 {
-	unsigned long flags, rid, pta, impl_va_bits;
+	unsigned long psr, rid, pta, impl_va_bits;
 	extern void __init tlb_init (void);
 #ifdef CONFIG_DISABLE_VHPT
 #	define VHPT_ENABLE_BIT	0
@@ -263,7 +262,7 @@
 	 * Set up the kernel identity mapping for regions 6 and 5.  The mapping for region
 	 * 7 is setup up in _start().
 	 */
-	ia64_clear_ic(flags);
+	psr = ia64_clear_ic();
 
 	rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET);
 	ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (IA64_GRANULE_SHIFT << 2));
@@ -277,7 +276,7 @@
 	ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR,
 		 pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)), PAGE_SHIFT);
 
-	__restore_flags(flags);
+	ia64_set_psr(psr);
 	ia64_srlz_i();
 
 	/*
diff -Nru a/arch/ia64/sn/io/Makefile b/arch/ia64/sn/io/Makefile
--- a/arch/ia64/sn/io/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/ia64/sn/io/Makefile	Wed May 29 11:43:02 2002
@@ -18,7 +18,7 @@
 O_TARGET := sgiio.o
 
 ifeq ($(CONFIG_MODULES),y)
-export-objs = pciio.o hcl.o
+export-objs = pciio.o hcl.o pci_dma.o
 endif
 
 obj-y  := stubs.o sgi_if.o pciio.o xtalk.o xbow.o xswitch.o klgraph_hack.o \
diff -Nru a/arch/ia64/sn/io/pci_dma.c b/arch/ia64/sn/io/pci_dma.c
--- a/arch/ia64/sn/io/pci_dma.c	Wed May 29 11:43:02 2002
+++ b/arch/ia64/sn/io/pci_dma.c	Wed May 29 11:43:02 2002
@@ -4,6 +4,9 @@
  * for more details.
  *
  * Copyright (C) 2000,2002 Silicon Graphics, Inc. All rights reserved.
+ *
+ * Routines for PCI DMA mapping.  See Documentation/DMA-mapping.txt for
+ * a description of how these routines should be used.
  */
 
 #include <linux/types.h>
@@ -12,6 +15,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/module.h>
 
 #include <asm/delay.h>
 #include <asm/io.h>
@@ -46,7 +50,7 @@
 	/*
 	 * Darn, we need to get the maps allocated for this bus.
 	 */
-	for (i=0; i<MAX_PCI_XWIDGET; i++) {
+	for (i = 0; i < MAX_PCI_XWIDGET; i++) {
 		if (busnum_to_pcibr_vhdl[i] == pci_bus) {
 			sn1_dma_map = busnum_to_atedmamaps[i];
 		}
@@ -314,22 +318,18 @@
 		}
 
 		/*
-		 * It is a 32bit card and we cannot do Direct mapping.
-		 * Let's 32Bit Page map the request.
+		 * It is a 32 bit card and we cannot do direct mapping,
+		 * so we use an ATE.
 		 */
-		dma_map = NULL;
-#ifdef CONFIG_IA64_SGI_SN1
-		dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, 
-				PCIIO_BYTE_STREAM | PCIIO_DMA_DATA);
-#else
-		dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, PCIIO_DMA_DATA);
-#endif
+		dma_map = 0;
+		dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length,
+					     DMA_DATA_FLAGS);
 		if (!dma_map) {
-			printk("pci_map_sg: Unable to allocate anymore 32Bits Page Map entries.\n");
+			printk(KERN_ERR "sn_pci_map_sg: Unable to allocate "
+			       "anymore 32 bit page map entries.\n");
 			BUG();
 		}
-		dma_addr = (dma_addr_t)pciio_dmamap_addr(dma_map, temp_ptr, sg->length);
-		/* printk("pci_map_sg: dma_map 0x%p Phys Addr 0x%p dma_addr 0x%p\n", dma_map, temp_ptr, dma_addr); */
+		dma_addr = pciio_dmamap_addr(dma_map, phys_addr, sg->length);
 		sg->address = (char *)dma_addr;
 		sg->page = (char *)dma_map;
 		
@@ -372,7 +372,17 @@
 
 }
 
-/*
+/**
+ * sn_pci_map_single - map a single region for DMA
+ * @hwdev: device to map for
+ * @ptr: kernel virtual address of the region to map
+ * @size: size of the region
+ * @direction: DMA direction
+ *
+ * Map the region pointed to by @ptr for DMA and return the
+ * DMA address.   Also known as platform_pci_map_single() by
+ * the IA64 machvec code.
+ *
  * We map this to the one step pciio_dmamap_trans interface rather than
  * the two step pciio_dmamap_alloc/pciio_dmamap_addr because we have
  * no way of saving the dmamap handle from the alloc to later free
diff -Nru a/arch/ia64/sn/kernel/misctest.c b/arch/ia64/sn/kernel/misctest.c
--- a/arch/ia64/sn/kernel/misctest.c	Wed May 29 11:43:03 2002
+++ b/arch/ia64/sn/kernel/misctest.c	Wed May 29 11:43:03 2002
@@ -75,7 +75,7 @@
 	if (mcatest == 5) {
 		int zzzspec(long);
 		int	i;
-		long	flags, dcr, res, val, addr=0xff00000000UL;
+		long	psr, dcr, res, val, addr=0xff00000000UL;
 
 		dcr = ia64_get_dcr();
 		for (i=0; i<5; i++) {
@@ -87,11 +87,11 @@
 			ia64_set_dcr(dcr);
 			res = ia64_sn_probe_io_slot(0xff00000000UL, 8, &val);
 			printk("zzzspec: probe %ld, 0x%lx\n", res, val);
-			ia64_clear_ic(flags);
+			psr = ia64_clear_ic();
 			ia64_itc(0x2, 0xe00000ff00000000UL,
 			          pte_val(pfn_pte(0xff00000000UL >> PAGE_SHIFT,
 				  __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW))), _PAGE_SIZE_256M);
-			local_irq_restore(flags);
+			ia64_set_psr(psr);
 			ia64_srlz_i ();
 		}
 
diff -Nru a/arch/ia64/sn/kernel/sn1/Makefile b/arch/ia64/sn/kernel/sn1/Makefile
--- a/arch/ia64/sn/kernel/sn1/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/ia64/sn/kernel/sn1/Makefile	Wed May 29 11:43:03 2002
@@ -32,14 +32,10 @@
 # http://oss.sgi.com/projects/GenInfo/NoticeExplan
 #
 
-EXTRA_CFLAGS    := -DLITTLE_ENDIAN
+O_TARGET := sn1.a
 
-all: sn1.a
+obj-y := cache.o error.o iomv.o synergy.o sn1_smp.o
 
-O_TARGET        = sn1.a
-
-obj-y          = cache.o error.o iomv.o synergy.o sn1_smp.o
-
-clean::
+EXTRA_CFLAGS := -DLITTLE_ENDIAN
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/ia64/sn/kernel/sn2/Makefile b/arch/ia64/sn/kernel/sn2/Makefile
--- a/arch/ia64/sn/kernel/sn2/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/ia64/sn/kernel/sn2/Makefile	Wed May 29 11:43:03 2002
@@ -32,14 +32,11 @@
 # http://oss.sgi.com/projects/GenInfo/NoticeExplan
 #
 
-EXTRA_CFLAGS    := -DLITTLE_ENDIAN
-
-all: sn2.a
-
-O_TARGET        = sn2.a
+O_TARGET := sn2.a
 
-obj-y          = cache.o iomv.o sn2_smp.o
+obj-y := cache.o iomv.o sn2_smp.o
 
-clean::
+EXTRA_CFLAGS    := -DLITTLE_ENDIAN
 
 include $(TOPDIR)/Rules.make
+
diff -Nru a/arch/ia64/tools/Makefile b/arch/ia64/tools/Makefile
--- a/arch/ia64/tools/Makefile	Wed May 29 11:43:01 2002
+++ b/arch/ia64/tools/Makefile	Wed May 29 11:43:01 2002
@@ -33,11 +33,11 @@
 
 comma	:= ,
 
-print_offsets: print_offsets.c FORCE_RECOMPILE
+print_offsets: print_offsets.c FORCE
 	$(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) \
 		print_offsets.c -o $@
 
-FORCE_RECOMPILE:
+FORCE:
 
 else
 
diff -Nru a/arch/ia64/tools/print_offsets.awk b/arch/ia64/tools/print_offsets.awk
--- a/arch/ia64/tools/print_offsets.awk	Wed May 29 11:43:03 2002
+++ b/arch/ia64/tools/print_offsets.awk	Wed May 29 11:43:03 2002
@@ -7,6 +7,8 @@
 	print " * This file was generated by arch/ia64/tools/print_offsets.awk."
 	print " *"
 	print " */"
+	print ""
+	print "#define CLONE_IDLETASK_BIT	12"
 }
 
 # look for .tab:
diff -Nru a/arch/ia64/tools/print_offsets.c b/arch/ia64/tools/print_offsets.c
--- a/arch/ia64/tools/print_offsets.c	Wed May 29 11:43:03 2002
+++ b/arch/ia64/tools/print_offsets.c	Wed May 29 11:43:03 2002
@@ -53,6 +53,7 @@
     { "UNW_FRAME_INFO_SIZE",		sizeof (struct unw_frame_info) },
     { "", 0 },			/* spacer */
     { "IA64_TASK_THREAD_KSP_OFFSET",	offsetof (struct task_struct, thread.ksp) },
+    { "IA64_TASK_PID_OFFSET",		offsetof (struct task_struct, pid) },
     { "IA64_PT_REGS_CR_IPSR_OFFSET",	offsetof (struct pt_regs, cr_ipsr) },
     { "IA64_PT_REGS_CR_IIP_OFFSET",	offsetof (struct pt_regs, cr_iip) },
     { "IA64_PT_REGS_CR_IFS_OFFSET",	offsetof (struct pt_regs, cr_ifs) },
@@ -161,6 +162,7 @@
     { "IA64_SIGFRAME_ARG2_OFFSET",		offsetof (struct sigframe, arg2) },
     { "IA64_SIGFRAME_HANDLER_OFFSET",		offsetof (struct sigframe, handler) },
     { "IA64_SIGFRAME_SIGCONTEXT_OFFSET",	offsetof (struct sigframe, sc) },
+    /* for assembly files which can't include sched.h: */
     { "IA64_CLONE_VFORK",		CLONE_VFORK },
     { "IA64_CLONE_VM",			CLONE_VM },
 };
@@ -198,6 +200,8 @@
 		  tab[i].name, space, tab[i].value, tab[i].value);
 	}
     }
+
+  printf ("\n#define CLONE_IDLETASK_BIT	%ld\n", ia64_fls (CLONE_IDLETASK));
 
   printf ("\n#endif /* _ASM_IA64_OFFSETS_H */\n");
   return 0;
diff -Nru a/arch/ia64/vmlinux.lds.S b/arch/ia64/vmlinux.lds.S
--- a/arch/ia64/vmlinux.lds.S	Wed May 29 11:43:02 2002
+++ b/arch/ia64/vmlinux.lds.S	Wed May 29 11:43:02 2002
@@ -41,7 +41,8 @@
 
   /* Read-only data */
 
-  __gp = ALIGN(16) + 0x200000;	/* gp must be 16-byte aligned for exc. table */
+  . = ALIGN(16);
+  __gp = . + 0x200000;	/* gp must be 16-byte aligned for exc. table */
 
   /* Global data */
   _data = .;
diff -Nru a/arch/m68k/fpsp040/Makefile b/arch/m68k/fpsp040/Makefile
--- a/arch/m68k/fpsp040/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/m68k/fpsp040/Makefile	Wed May 29 11:43:03 2002
@@ -1,17 +1,10 @@
 #
 # Makefile for Linux arch/m68k/fpsp040 source directory
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-EXTRA_AFLAGS := -traditional
-
-OS_TARGET := fpsp.o
+O_TARGET := fpsp.o
 
-OS_OBJS   := bindec.o binstr.o decbin.o do_func.o gen_except.o get_op.o \
+obj-y    := bindec.o binstr.o decbin.o do_func.o gen_except.o get_op.o \
 	    kernel_ex.o res_func.o round.o sacos.o sasin.o satan.o satanh.o \
 	    scosh.o setox.o sgetem.o sint.o slog2.o slogn.o \
 	    smovecr.o srem_mod.o scale.o \
@@ -19,11 +12,9 @@
 	    x_bsun.o x_fline.o x_operr.o x_ovfl.o x_snan.o x_store.o \
 	    x_unfl.o x_unimp.o x_unsupp.o bugfix.o skeleton.o
 
-all:	$(OS_TARGET)
+EXTRA_AFLAGS := -traditional
+EXTRA_LDFLAGS := -x
 
 include $(TOPDIR)/Rules.make
 
 $(OS_OBJS): fpsp.h
-
-$(OS_TARGET): $(OS_OBJS) fpsp.h
-	$(LD) -x -r -o $(OS_TARGET) $(OS_OBJS)
diff -Nru a/arch/m68k/ifpsp060/Makefile b/arch/m68k/ifpsp060/Makefile
--- a/arch/m68k/ifpsp060/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/m68k/ifpsp060/Makefile	Wed May 29 11:43:02 2002
@@ -4,17 +4,11 @@
 # License.  See the file "README.legal" in the main directory of this archive
 # for more details.
 
-EXTRA_AFLAGS := -traditional
-
-OS_TARGET := ifpsp.o
+O_TARGET := ifpsp.o
 
-OS_OBJS	  := fskeleton.o iskeleton.o os.o
+obj-y := fskeleton.o iskeleton.o os.o
 
-all:	$(OS_TARGET)
+EXTRA_AFLAGS := -traditional
+EXTRA_LDFLAGS := -x
 
 include $(TOPDIR)/Rules.make
-
-$(OS_OBJS):
-
-$(OS_TARGET): $(OS_OBJS)
-	$(LD) -x -r -o $(OS_TARGET) $(OS_OBJS)
diff -Nru a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
--- a/arch/m68k/kernel/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/m68k/kernel/Makefile	Wed May 29 11:43:03 2002
@@ -1,22 +1,15 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-EXTRA_AFLAGS := -traditional
+O_TARGET := kernel.o
 
 ifndef CONFIG_SUN3
-all: head.o kernel.o
+  EXTRA_TARGETS := head.o
 else
-all: sun3-head.o kernel.o
+  EXTRA_TARGETS := sun3-head.o
 endif 
 
-O_TARGET := kernel.o
-
 export-objs	:= setup.o m68k_ksyms.o
 
 obj-y		:= entry.o process.o traps.o ints.o signal.o ptrace.o \
@@ -24,6 +17,10 @@
 
 obj-$(CONFIG_PCI)	+= bios32.o
 
+EXTRA_AFLAGS := -traditional
+
+include $(TOPDIR)/Rules.make
+
 head.o: head.S m68k_defs.h
 
 entry.o: entry.S m68k_defs.h
@@ -39,4 +36,3 @@
 	rm m68k_defs.s
 -include m68k_defs.d
 
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
--- a/arch/m68k/kernel/signal.c	Wed May 29 11:43:02 2002
+++ b/arch/m68k/kernel/signal.c	Wed May 29 11:43:02 2002
@@ -190,41 +190,6 @@
 };
 
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
-		int err;
-
-		/* If you change siginfo_t structure, please be sure
-		   this code is fixed accordingly.
-		   It should never copy any pad contained in the structure
-		   to avoid security leaks, but must copy the generic
-		   3 ints plus the relevant union member.  */
-		err = __put_user(from->si_signo, &to->si_signo);
-		err |= __put_user(from->si_errno, &to->si_errno);
-		err |= __put_user((short)from->si_code, &to->si_code);
-		/* First 32bits of unions are always present.  */
-		err |= __put_user(from->si_pid, &to->si_pid);
-		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
-		case __SI_CHLD >> 16:
-			err |= __put_user(from->si_utime, &to->si_utime);
-			err |= __put_user(from->si_stime, &to->si_stime);
-			err |= __put_user(from->si_status, &to->si_status);
-		default:
-			err |= __put_user(from->si_uid, &to->si_uid);
-			break;
-		/* case __SI_RT: This is not generated by the kernel as of now.  */
-		}
-		return err;
-	}
-}
-
 static unsigned char fpu_version = 0;	/* version number of fpu, set by setup_frame */
 
 static inline int restore_fpu_state(struct sigcontext *sc)
diff -Nru a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile
--- a/arch/mips/au1000/common/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/mips/au1000/common/Makefile	Wed May 29 11:43:03 2002
@@ -5,14 +5,6 @@
 #
 # Makefile for the Alchemy Au1000 CPU, generic files.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-EXTRA_AFLAGS := $(CFLAGS)
-
-all: au1000.o
 
 O_TARGET := au1000.o
 
@@ -22,7 +14,9 @@
 obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o             
 obj-$(CONFIG_BLK_DEV_INITRD) += ramdisk.o
 
-ramdisk.o: 
-	mkramobj ramdisk ramdisk.o
+EXTRA_AFLAGS := $(CFLAGS)
 
 include $(TOPDIR)/Rules.make
+
+ramdisk.o: 
+	mkramobj ramdisk ramdisk.o
diff -Nru a/arch/mips/au1000/pb1000/Makefile b/arch/mips/au1000/pb1000/Makefile
--- a/arch/mips/au1000/pb1000/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/mips/au1000/pb1000/Makefile	Wed May 29 11:43:02 2002
@@ -5,12 +5,6 @@
 #
 # Makefile for the Alchemy Semiconductor PB1000 board.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-all: pb1000.o
 
 O_TARGET := pb1000.o
 
diff -Nru a/arch/mips/baget/Makefile b/arch/mips/baget/Makefile
--- a/arch/mips/baget/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/mips/baget/Makefile	Wed May 29 11:43:03 2002
@@ -2,13 +2,6 @@
 # Makefile for the Baget specific kernel interface routines
 # under Linux.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-all: baget.a 
 
 O_TARGET := baget.a
 
@@ -18,10 +11,11 @@
 obj-$(CONFIG_SERIAL)	+= vacserial.o
 obj-$(CONFIG_VAC_RTC)	+= vacrtc.o
 
+include $(TOPDIR)/Rules.make
+
 bagetIRQ.o : bagetIRQ.S
 	$(CC) $(CFLAGS) -c -o $@ $<
 
-
 ##################### Baget Loader stuff ########################
 
 image: ../../../vmlinux
@@ -61,4 +55,3 @@
 clean:
 	rm -f balo balo.h dummy.c image image.bin
 
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
--- a/arch/mips/boot/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/mips/boot/Makefile	Wed May 29 11:43:03 2002
@@ -47,6 +47,4 @@
 	rm -f addinitrd
 	rm -f elf2ecoff
 
-dummy:
-
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile
--- a/arch/mips/dec/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/mips/dec/Makefile	Wed May 29 11:43:02 2002
@@ -1,20 +1,13 @@
 #
 # Makefile for the DECstation family specific parts of the kernel
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
 
 O_TARGET := dec.o
 
-all: dec.o
-
 export-objs := wbflush.o
+
 obj-y	 := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o wbflush.o
 
 obj-$(CONFIG_PROM_CONSOLE)	+= promcon.o
-
-int-handler.o:	int-handler.S
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips/dec/boot/Makefile b/arch/mips/dec/boot/Makefile
--- a/arch/mips/dec/boot/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/mips/dec/boot/Makefile	Wed May 29 11:43:03 2002
@@ -1,16 +1,10 @@
 #
 # Makefile for the DECstation family specific parts of the kernel
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
 
 netboot: all
 	mipsel-linux-ld -N -G 0 -T ld.ecoff ../../boot/zImage \
 		dec_boot.o ramdisk.img -o nbImage
-
-all: dec_boot.o
 
 O_TARGET := dec_boot.o
 
diff -Nru a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile
--- a/arch/mips/dec/prom/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/mips/dec/prom/Makefile	Wed May 29 11:43:02 2002
@@ -2,25 +2,14 @@
 # Makefile for the DECstation prom monitor library routines
 # under Linux.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-EXTRA_AFLAGS := $(CFLAGS)
-
-OBJS  = init.o memory.o cmdline.o identify.o locore.o
+L_TARGET := rexlib.a
 
-all: 	rexlib.a
+obj-y := init.o memory.o cmdline.o identify.o locore.o
 
-rexlib.a: $(OBJS)
-	$(AR) rcs rexlib.a $(OBJS)
-	sync
+EXTRA_AFLAGS := $(CFLAGS)
 
-locore.o: locore.S
+include $(TOPDIR)/Rules.make
 
 dep:
 	$(CPP) $(CPPFLAGS) -M *.c > .depend
-
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips/ite-boards/generic/Makefile b/arch/mips/ite-boards/generic/Makefile
--- a/arch/mips/ite-boards/generic/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/mips/ite-boards/generic/Makefile	Wed May 29 11:43:02 2002
@@ -5,14 +5,6 @@
 #
 # Makefile for the ITE 8172 (qed-4n-s01b) board, generic files.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-EXTRA_AFLAGS := $(CFLAGS)
-
-all: it8172.o
 
 O_TARGET := it8172.o
 
@@ -29,5 +21,7 @@
 ifdef CONFIG_REMOTE_DEBUG
  obj-y += dbg_io.o             
 endif
+
+EXTRA_AFLAGS := $(CFLAGS)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips/ite-boards/ivr/Makefile b/arch/mips/ite-boards/ivr/Makefile
--- a/arch/mips/ite-boards/ivr/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/mips/ite-boards/ivr/Makefile	Wed May 29 11:43:03 2002
@@ -6,18 +6,12 @@
 # Makefile for the Globespan IVR board,
 # board-specific files.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-all: ivr.o
 
 O_TARGET := ivr.o
 
 obj-y := init.o 
 
-obj-CONFIG_PCI += pci_fixup.o
-obj-CONFIG_BLK_DEV_INITRD += le_ramdisk.o
+obj-$(CONFIG_PCI) += pci_fixup.o
+obj-$(CONFIG_BLK_DEV_INITRD) += le_ramdisk.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips/ite-boards/qed-4n-s01b/Makefile b/arch/mips/ite-boards/qed-4n-s01b/Makefile
--- a/arch/mips/ite-boards/qed-4n-s01b/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/mips/ite-boards/qed-4n-s01b/Makefile	Wed May 29 11:43:03 2002
@@ -6,27 +6,14 @@
 # Makefile for the ITE 8172 (qed-4n-s01b) board, board
 # specific files.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-all: ite.o
 
 O_TARGET := ite.o
 
 obj-y := init.o 
+obj-$(CONFIG_PCI) += pci_fixup.o
+obj-$(CONFIG_BLK_DEV_INITRD) += le_ramdisk.o
 
-ifdef CONFIG_PCI
-obj-y += pci_fixup.o
-endif
-
-ifdef CONFIG_BLK_DEV_INITRD
-obj-y += le_ramdisk.o
-endif
-
+include $(TOPDIR)/Rules.make
 
 dep:
 	$(CPP) -M *.c > .depend
-
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips/jazz/Makefile b/arch/mips/jazz/Makefile
--- a/arch/mips/jazz/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/mips/jazz/Makefile	Wed May 29 11:43:02 2002
@@ -1,20 +1,12 @@
 #
 # Makefile for the Jazz family specific parts of the kernel
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-EXTRA_AFLAGS := $(CFLAGS)
-
-all: jazz.o
 
 O_TARGET := jazz.o
 
 obj-y	 := int-handler.o irq.o jazzdma.o reset.o rtc-jazz.o setup.o \
 	    floppy-jazz.o kbd-jazz.o
 
-int-handler.o: int-handler.S
+EXTRA_AFLAGS := $(CFLAGS)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
--- a/arch/mips/kernel/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/mips/kernel/Makefile	Wed May 29 11:43:02 2002
@@ -1,16 +1,11 @@
 #
 # Makefile for the Linux/MIPS kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
 
 # EXTRA_AFLAGS = -mips3 -mcpu=r4000 # not used?
 
-all:	kernel.o head.o init_task.o
-
-O_TARGET := kernel.o
+O_TARGET	:= kernel.o
+EXTRA_TARGETS	:= head.o init_task.o
 
 obj-y				+= branch.o process.o signal.o entry.o \
 				   traps.o ptrace.o vm86.o ioport.o reset.o \
@@ -53,8 +48,5 @@
 obj-$(CONFIG_NEW_PCI)          += pci.o
 obj-$(CONFIG_PCI_AUTO)         += pci_auto.o
 endif
-
-entry.o: entry.S
-head.o: head.S
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
--- a/arch/mips/kernel/signal.c	Wed May 29 11:43:03 2002
+++ b/arch/mips/kernel/signal.c	Wed May 29 11:43:03 2002
@@ -37,41 +37,6 @@
 
 extern asmlinkage void syscall_trace(void);
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
-		int err;
-
-		/* If you change siginfo_t structure, please be sure
-		   this code is fixed accordingly.
-		   It should never copy any pad contained in the structure
-		   to avoid security leaks, but must copy the generic
-		   3 ints plus the relevant union member.  */
-		err = __put_user(from->si_signo, &to->si_signo);
-		err |= __put_user(from->si_errno, &to->si_errno);
-		err |= __put_user((short)from->si_code, &to->si_code);
-		/* First 32bits of unions are always present.  */
-		err |= __put_user(from->si_pid, &to->si_pid);
-		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
-		case __SI_CHLD >> 16:
-			err |= __put_user(from->si_utime, &to->si_utime);
-			err |= __put_user(from->si_stime, &to->si_stime);
-			err |= __put_user(from->si_status, &to->si_status);
-		default:
-			err |= __put_user(from->si_uid, &to->si_uid);
-			break;
-		/* case __SI_RT: This is not generated by the kernel as of now.  */
-		}
-		return err;
-	}
-}
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -522,9 +487,11 @@
 }
 
 static inline void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
-	siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
+		struct pt_regs * regs)
 {
+	struct k_sigaction *ka = &current->sig->action[sig-1];
+
 	if (ka->sa.sa_flags & SA_SIGINFO)
 		setup_rt_frame(ka, regs, sig, oldset, info);
 	else
@@ -566,8 +533,8 @@
 
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
 {
-	struct k_sigaction *ka;
 	siginfo_t info;
+	int sig_nr;
 
 #ifdef CONFIG_BINFMT_IRIX
 	if (current->personality != PER_LINUX)
@@ -577,99 +544,12 @@
 	if (!oldset)
 		oldset = &current->blocked;
 
-	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sig->action[signr-1];
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP:
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		if (regs->regs[0])
 			syscall_restart(regs, ka);
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, ka, &info, oldset, regs);
+		handle_signal(signr, &info, oldset, regs);
 		return 1;
 	}
 
diff -Nru a/arch/mips/mips-boards/atlas/Makefile b/arch/mips/mips-boards/atlas/Makefile
--- a/arch/mips/mips-boards/atlas/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/mips/mips-boards/atlas/Makefile	Wed May 29 11:43:03 2002
@@ -22,13 +22,6 @@
 # Makefile for the MIPS Atlas specific kernel interface routines
 # under Linux.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-all: atlas.o
 
 O_TARGET := atlas.o
 
diff -Nru a/arch/mips/philips/nino/Makefile b/arch/mips/philips/nino/Makefile
--- a/arch/mips/philips/nino/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/mips/philips/nino/Makefile	Wed May 29 11:43:02 2002
@@ -1,23 +1,17 @@
 #
 # Makefile for the Philips Nino specific parts of the kernel
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
 
 O_TARGET := nino.o
 
-all: nino.o
-
 obj-y	 := int-handler.o setup.o irq.o time.o reset.o rtc.o prom.o power.o
 
-int-handler.o: int-handler.S
-
 obj-$(CONFIG_REMOTE_DEBUG)	+= kgdb.o
 
 obj-$(CONFIG_BLK_DEV_INITRD)	+= ramdisk.o
 
+include $(TOPDIR)/Rules.make
+
 ramdisk.o:
 		$(MAKE) -C ramdisk
 		mv ramdisk/ramdisk.o ramdisk.o
@@ -25,4 +19,3 @@
 clean:
 		rm -f *.o
 
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips/sgi/kernel/Makefile b/arch/mips/sgi/kernel/Makefile
--- a/arch/mips/sgi/kernel/Makefile	Wed May 29 11:43:01 2002
+++ b/arch/mips/sgi/kernel/Makefile	Wed May 29 11:43:01 2002
@@ -2,21 +2,12 @@
 # Makefile for the SGI specific kernel interface routines
 # under Linux.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-EXTRA_AFLAGS := $(CFLAGS)
 
 O_TARGET := ip22-kern.o
 
-all: ip22-kern.o indyIRQ.o
-
 obj-y	+= indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o system.o \
 	   indyIRQ.o reset.o setup.o time.o
 
-indyIRQ.o: indyIRQ.S
+EXTRA_AFLAGS := $(CFLAGS)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile
--- a/arch/mips/sni/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/mips/sni/Makefile	Wed May 29 11:43:02 2002
@@ -1,19 +1,11 @@
 #
 # Makefile for the SNI specific part of the kernel
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-EXTRA_AFLAGS := $(CFLAGS)
-
-all:	sni.o int-handler.o
 
 O_TARGET := sni.o
 
 obj-y	 := int-handler.o io.o irq.o pci.o pcimt_scache.o reset.o setup.o
 
-int-handler.o: int-handler.S
+EXTRA_AFLAGS := $(CFLAGS)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips64/boot/Makefile b/arch/mips64/boot/Makefile
--- a/arch/mips64/boot/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/mips64/boot/Makefile	Wed May 29 11:43:03 2002
@@ -35,6 +35,4 @@
 mrproper:
 	rm -f vmlinux.ecoff addinitrd elf2ecoff
 
-dummy:
-
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips64/kernel/Makefile b/arch/mips64/kernel/Makefile
--- a/arch/mips64/kernel/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/mips64/kernel/Makefile	Wed May 29 11:43:02 2002
@@ -1,18 +1,11 @@
 #
 # Makefile for the Linux/MIPS kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
 
-EXTRA_AFLAGS := $(CFLAGS)
-
-all:	kernel.o head.o init_task.o
+O_TARGET	:= kernel.o
+EXTRA_TARGETS	:= head.o init_task.o
 
-O_TARGET := kernel.o
-
-export-objs = mips64_ksyms.o
+export-objs	:= mips64_ksyms.o
 
 obj-y	:= branch.o entry.o proc.o process.o ptrace.o r4k_cache.o r4k_fpu.o \
 	   r4k_genex.o r4k_switch.o r4k_tlb.o r4k_tlb_debug.o r4k_tlb_glue.o \
@@ -26,5 +19,6 @@
 
 AFLAGS_r4k_genex.o := -P
 AFLAGS_r4k_tlb_glue.o := -P
+EXTRA_AFLAGS := $(CFLAGS)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips64/kernel/signal.c b/arch/mips64/kernel/signal.c
--- a/arch/mips64/kernel/signal.c	Wed May 29 11:43:02 2002
+++ b/arch/mips64/kernel/signal.c	Wed May 29 11:43:02 2002
@@ -543,10 +543,11 @@
 	force_sig(SIGSEGV, current);
 }
 
-static inline void handle_signal(unsigned long sig, struct k_sigaction *ka,
-				 siginfo_t *info, sigset_t *oldset,
-				 struct pt_regs *regs)
+static inline void handle_signal(unsigned long sig, siginfo_t *info,
+		sigset_t *oldset, struct pt_regs *regs)
 {
+	struct k_sigaction *ka = &current->sig->action[sig-1];
+
 	if (ka->sa.sa_flags & SA_SIGINFO)
 		setup_rt_frame(ka, regs, sig, oldset, info);
 	else
@@ -589,8 +590,8 @@
 
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
 {
-	struct k_sigaction *ka;
 	siginfo_t info;
+	int signr;
 
 #ifdef CONFIG_BINFMT_ELF32
 	if (current->thread.mflags & MF_32BIT) {
@@ -601,99 +602,12 @@
 	if (!oldset)
 		oldset = &current->blocked;
 
-	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sig->action[signr-1];
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP:
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		if (regs->regs[0])
 			syscall_restart(regs, ka);
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, ka, &info, oldset, regs);
+		handle_signal(signr, &info, oldset, regs);
 		return 1;
 	}
 
diff -Nru a/arch/mips64/kernel/signal32.c b/arch/mips64/kernel/signal32.c
--- a/arch/mips64/kernel/signal32.c	Wed May 29 11:43:03 2002
+++ b/arch/mips64/kernel/signal32.c	Wed May 29 11:43:03 2002
@@ -625,9 +625,11 @@
 }
 
 static inline void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
-	siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+handle_signal(unsigned long sig siginfo_t *info, sigset_t *oldset,
+		struct pt_regs * regs)
 {
+	struct k_sigaction *ka = &current->sig->action[sig-1];
+
 	if (ka->sa.sa_flags & SA_SIGINFO)
 		setup_rt_frame(ka, regs, sig, oldset, info);
 	else
@@ -667,105 +669,18 @@
 
 asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs)
 {
-	struct k_sigaction *ka;
 	siginfo_t info;
+	int signr;
 
 	if (!oldset)
 		oldset = &current->blocked;
 
-	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sig->action[signr-1];
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP:
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		if (regs->regs[0])
 			syscall_restart(regs, ka);
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, ka, &info, oldset, regs);
+		handle_signal(signr, &info, oldset, regs);
 		return 1;
 	}
 
diff -Nru a/arch/mips64/mips-boards/atlas/Makefile b/arch/mips64/mips-boards/atlas/Makefile
--- a/arch/mips64/mips-boards/atlas/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/mips64/mips-boards/atlas/Makefile	Wed May 29 11:43:02 2002
@@ -22,13 +22,6 @@
 # Makefile for the MIPS Atlas specific kernel interface routines
 # under Linux.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-all: atlas.o
 
 O_TARGET := atlas.o
 
diff -Nru a/arch/mips64/mips-boards/generic/Makefile b/arch/mips64/mips-boards/generic/Makefile
--- a/arch/mips64/mips-boards/generic/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/mips64/mips-boards/generic/Makefile	Wed May 29 11:43:02 2002
@@ -21,20 +21,13 @@
 #
 # Makefile for the MIPS boards generic routines under Linux.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-EXTRA_AFLAGS := $(CFLAGS)
-
-all: mipsboards.o
 
 O_TARGET := mipsboards.o
 
 obj-y                           := mipsIRQ.o pci.o reset.o display.o init.o \
                                    memory.o printf.o cmdline.o time.o
 obj-$(CONFIG_REMOTE_DEBUG)      += gdb_hook.o
+
+EXTRA_AFLAGS := $(CFLAGS)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips64/mips-boards/malta/Makefile b/arch/mips64/mips-boards/malta/Makefile
--- a/arch/mips64/mips-boards/malta/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/mips64/mips-boards/malta/Makefile	Wed May 29 11:43:02 2002
@@ -22,13 +22,6 @@
 # Makefile for the MIPS Malta specific kernel interface routines
 # under Linux.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-all: malta.o
 
 O_TARGET := malta.o
 
diff -Nru a/arch/mips64/sgi-ip32/Makefile b/arch/mips64/sgi-ip32/Makefile
--- a/arch/mips64/sgi-ip32/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/mips64/sgi-ip32/Makefile	Wed May 29 11:43:03 2002
@@ -2,23 +2,15 @@
 # Makefile for the SGI specific kernel interface routines
 # under Linux.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-EXTRA_AFLAGS := $(CFLAGS)
-
-O_TARGET := ip32-kern.a
+O_TARGET	:= ip32-kern.a
+EXTRA_TARGETS	:= ip32-irq-glue.o
 
-all: ip32-kern.a ip32-irq-glue.o
+obj-y		+= ip32-irq.o ip32-rtc.o ip32-setup.o ip32-irq-glue.o \
+	 	   ip32-berr.o ip32-timer.o crime.o
 
-obj-y	+= ip32-irq.o ip32-rtc.o ip32-setup.o ip32-irq-glue.o \
-	 ip32-berr.o ip32-timer.o crime.o
+obj-$(CONFIG_PCI) += ip32-pci.o ip32-pci-dma.o
 
-ifdef CONFIG_PCI
-obj-y   += ip32-pci.o ip32-pci-dma.o
-endif
+EXTRA_AFLAGS := $(CFLAGS)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/parisc/Makefile b/arch/parisc/Makefile
--- a/arch/parisc/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/parisc/Makefile	Wed May 29 11:43:02 2002
@@ -55,16 +55,7 @@
 ifdef CONFIG_KWDB
 SUBDIRS := $(SUBDIRS) arch/parisc/kdb
 DRIVERS := $(DRIVERS) arch/parisc/kdb/kdb.o
-
-arch/parisc/kdb: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/parisc/kdb
 endif
-
-arch/parisc/kernel: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/parisc/kernel
-
-arch/parisc/mm: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/parisc/mm
 
 palo: vmlinux
 	export TOPDIR=`pwd`; export CONFIG_STI_CONSOLE=$(CONFIG_STI_CONSOLE); \
diff -Nru a/arch/parisc/hpux/Makefile b/arch/parisc/hpux/Makefile
--- a/arch/parisc/hpux/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/parisc/hpux/Makefile	Wed May 29 11:43:03 2002
@@ -1,16 +1,11 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-all: hpux.o
-O_TARGET = hpux.o
-O_OBJS = entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o
+O_TARGET := hpux.o
 
-.o.S:	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o
+obj-y := entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o
+
+EXTRA_AFLAGS := -traditional
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile
--- a/arch/parisc/kernel/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/parisc/kernel/Makefile	Wed May 29 11:43:02 2002
@@ -1,26 +1,20 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-all: kernel.o init_task.o pdc_cons.o process.o head.o
-O_TARGET = kernel.o
+O_TARGET	:= kernel.o
+EXTRA_TARGETS	:= head.o init_task.o process.o pdc_cons.o
 
 # Object file lists.
 
-obj-y		+= cache.o setup.o traps.o time.o irq.o \
-		syscall.o entry.o sys_parisc.o pdc.o ptrace.o hardware.o \
-		inventory.o drivers.o semaphore.o pa7300lc.o pci-dma.o \
-		signal.o hpmc.o \
-		real1.o real2.o led.o parisc_ksyms.o
+obj-y	     	:= cache.o setup.o traps.o time.o irq.o \
+		   syscall.o entry.o sys_parisc.o pdc.o ptrace.o hardware.o \
+		   inventory.o drivers.o semaphore.o pa7300lc.o pci-dma.o \
+		   signal.o hpmc.o \
+		   real1.o real2.o led.o parisc_ksyms.o
 
 export-objs	:= parisc_ksyms.o
 
-
 obj-$(CONFIG_PCI) += pci.o
 obj-$(CONFIG_VT) += keyboard.o
 obj-$(CONFIG_PCI_LBA) += lba_pci.o
@@ -32,6 +26,6 @@
 # obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o
 obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o
 
-EXTRA_AFLAGS := -traditional
+EXTRA_AFLAGS	:= -traditional
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
--- a/arch/parisc/kernel/signal.c	Wed May 29 11:43:02 2002
+++ b/arch/parisc/kernel/signal.c	Wed May 29 11:43:02 2002
@@ -432,10 +432,11 @@
  */	
 
 static long
-handle_signal(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset,
+handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
 	      struct pt_regs *regs, int in_syscall)
 {
+	struct k_sigaction *ka = &current->sig->action[sig-1];
+
 #if DEBUG_SIG
 	printk("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n",
 	       sig, ka, info, oldset, regs);
@@ -473,6 +474,7 @@
 {
 	siginfo_t info;
 	struct k_sigaction *ka;
+	int signr;
 
 #if DEBUG_SIG
 	printk("do_signal(oldset=0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n",
@@ -490,102 +492,8 @@
 	printk("do_signal: oldset %08lx:%08lx\n", oldset->sig[0], oldset->sig[1]);
 #endif
 
-	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-#if DEBUG_SIG
-		printk("do_signal: signr=%ld, pid=%d\n", signr, current->pid);
-#endif
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			set_current_state(TASK_STOPPED);
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sig->action[signr-1];
-#if DEBUG_SIG
-		printk("sa_handler is %lx\n", ka->sa.sa_handler);
-#endif
-		if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP:
-				set_current_state(TASK_STOPPED);
-				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (signr == SIGQUIT) /* Userspace debugging */
-					show_regs(regs);
-				if (do_coredump(signr, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		/* Restart a system call if necessary. */
 		if (in_syscall) {
 			/* Check the return code */
@@ -598,6 +506,7 @@
 				break;
 
 			case -ERESTARTSYS:
+				ka = &current->sig->action[signr-1];
 				if (!(ka->sa.sa_flags & SA_RESTART)) {
 #if DEBUG_SIG
 					printk("ERESTARTSYS: putting -EINTR\n");
@@ -619,7 +528,7 @@
 		/* Whee!  Actually deliver the signal.  If the
 		   delivery failed, we need to continue to iterate in
 		   this loop so we can deliver the SIGSEGV... */
-		if (handle_signal(signr, ka, &info, oldset, regs, in_syscall)) {
+		if (handle_signal(signr, &info, oldset, regs, in_syscall)) {
 #if DEBUG_SIG
 			printk("Exiting do_signal (success), regs->gr[28] = %ld\n", regs->gr[28]);
 #endif
diff -Nru a/arch/ppc/8260_io/uart.c b/arch/ppc/8260_io/uart.c
--- a/arch/ppc/8260_io/uart.c	Wed May 29 11:43:01 2002
+++ b/arch/ppc/8260_io/uart.c	Wed May 29 11:43:01 2002
@@ -183,10 +183,6 @@
 #define TX_NUM_FIFO	4
 #define TX_BUF_SIZE	32
 
-#ifndef MIN
-#define MIN(a,b)	((a) < (b) ? (a) : (b))
-#endif
-
 /* The async_struct in serial.h does not really give us what we
  * need, so define our own here.
  */
@@ -1016,7 +1012,7 @@
 	bdp = info->tx_cur;
 
 	while (1) {
-		c = MIN(count, TX_BUF_SIZE);
+		c = min(count, TX_BUF_SIZE);
 
 		if (c <= 0)
 			break;
@@ -1763,7 +1759,7 @@
 	 */
 	char_time = 1;
 	if (timeout)
-		char_time = MIN(char_time, timeout);
+		char_time = min(char_time, timeout);
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 	printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
 	printk("jiff=%lu...", jiffies);
diff -Nru a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c
--- a/arch/ppc/8xx_io/uart.c	Wed May 29 11:43:02 2002
+++ b/arch/ppc/8xx_io/uart.c	Wed May 29 11:43:02 2002
@@ -183,10 +183,6 @@
 #define TX_NUM_FIFO	4
 #define TX_BUF_SIZE	32
 
-#ifndef MIN
-#define MIN(a,b)	((a) < (b) ? (a) : (b))
-#endif
-
 /* The async_struct in serial.h does not really give us what we
  * need, so define our own here.
  */
@@ -1098,7 +1094,7 @@
 	bdp = info->tx_cur;
 
 	while (1) {
-		c = MIN(count, TX_BUF_SIZE);
+		c = min(count, TX_BUF_SIZE);
 
 		if (c <= 0)
 			break;
@@ -1807,7 +1803,7 @@
 	 */
 	char_time = 1;
 	if (timeout)
-		char_time = MIN(char_time, timeout);
+		char_time = min(char_time, timeout);
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 	printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
 	printk("jiff=%lu...", jiffies);
diff -Nru a/arch/ppc/Config.help b/arch/ppc/Config.help
--- a/arch/ppc/Config.help	Wed May 29 11:43:02 2002
+++ b/arch/ppc/Config.help	Wed May 29 11:43:02 2002
@@ -340,8 +340,15 @@
   other useful pieces of information.  Sometimes this information is
   not present or incorrect.
 
-  Unless you expect to boot on a PReP system, there is not need to
+  Unless you expect to boot on a PReP system, there is no need to
   select Y.
+
+PReP residual data available in /proc/residual
+CONFIG_PROC_PREPRESIDUAL
+  Enabling this option will create a /proc/residual file which allows
+  you to get at the residual data on PReP systems.  You will need a tool
+  (lsresidual) to parse it.  If you aren't on a PReP system, you don't
+  want this.
 
 CONFIG_ADB
   Apple Desktop Bus (ADB) support is for support of devices which
diff -Nru a/arch/ppc/boot/chrp/main.c b/arch/ppc/boot/chrp/main.c
--- a/arch/ppc/boot/chrp/main.c	Wed May 29 11:43:01 2002
+++ b/arch/ppc/boot/chrp/main.c	Wed May 29 11:43:01 2002
@@ -46,6 +46,8 @@
 
 static char scratch[SCRATCH_SIZE];	/* 1MB of scratch space for gunzip */
 
+typedef void (*kernel_start_t)(int, int, void *, unsigned int, unsigned int);
+
 void
 chrpboot(int a1, int a2, void *prom)
 {
@@ -93,10 +95,10 @@
     make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_chrp,
 		    (PROG_START + PROG_SIZE));
     
-    sa = (unsigned long)PROG_START;
+    sa = PROG_START;
     printf("start address = 0x%x\n\r", sa);
 
-    (*(void (*)())sa)(a1, a2, prom, initrd_start, initrd_size);
+    (*(kernel_start_t)sa)(a1, a2, prom, initrd_start, initrd_size);
 
     printf("returned?\n\r");
 
diff -Nru a/arch/ppc/boot/chrp/start.c b/arch/ppc/boot/chrp/start.c
--- a/arch/ppc/boot/chrp/start.c	Wed May 29 11:43:01 2002
+++ b/arch/ppc/boot/chrp/start.c	Wed May 29 11:43:01 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.start.c 1.8 07/25/01 18:13:07 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Copyright (C) Paul Mackerras 1997.
@@ -11,7 +11,7 @@
  */
 #include <stdarg.h>
 
-int (*prom)();
+int (*prom)(void *args);
 
 void *chosen_handle;
 void *stdin;
@@ -30,7 +30,7 @@
 void
 start(int a1, int a2, void *promptr)
 {
-    prom = (int (*)()) promptr;
+    prom = promptr;
     chosen_handle = finddevice("/chosen");
     if (chosen_handle == (void *) -1)
 	exit();
@@ -65,7 +65,7 @@
     args.addr = ptr;
     args.len = nb;
     args.actual = -1;
-    (*prom)(&args);
+    prom(&args);
     return args.actual;
 }
 
@@ -211,7 +211,7 @@
 }
 
 int
-readchar()
+readchar(void)
 {
     char ch;
 
diff -Nru a/arch/ppc/boot/common/crt0.S b/arch/ppc/boot/common/crt0.S
--- a/arch/ppc/boot/common/crt0.S	Wed May 29 11:43:03 2002
+++ b/arch/ppc/boot/common/crt0.S	Wed May 29 11:43:03 2002
@@ -69,7 +69,7 @@
 	bdnz	1b			# If we are not done yet, keep clearing
 2:
 
-#ifdef CONFIG_4xx
+#ifdef CONFIG_40x
 	## Set up the stack
 
 	lis	r9,_start@h		# r9 = &_start (text section entry)
diff -Nru a/arch/ppc/boot/common/misc-simple.c b/arch/ppc/boot/common/misc-simple.c
--- a/arch/ppc/boot/common/misc-simple.c	Wed May 29 11:43:02 2002
+++ b/arch/ppc/boot/common/misc-simple.c	Wed May 29 11:43:02 2002
@@ -67,7 +67,7 @@
 extern unsigned long serial_init(int chan, void *ignored);
 extern void serial_close(unsigned long com_port);
 extern void gunzip(void *, int, unsigned char *, int *);
-extern void setup_legacy(void);
+extern void serial_fixups(void);
 
 struct bi_record *
 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
@@ -76,7 +76,7 @@
 	char *cp, ch;
 	struct bi_record *rec, *birecs;
 
-	setup_legacy();
+	serial_fixups();
 	com_port = serial_init(0, NULL);
 
 	/* assume the chunk below 8M is free */
diff -Nru a/arch/ppc/boot/common/relocate.S b/arch/ppc/boot/common/relocate.S
--- a/arch/ppc/boot/common/relocate.S	Wed May 29 11:43:02 2002
+++ b/arch/ppc/boot/common/relocate.S	Wed May 29 11:43:02 2002
@@ -9,7 +9,7 @@
  *	   trini@mvista.com
  * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
  *
- * Copyright 2001 MontaVista Software Inc.
+ * Copyright 2001-2002 MontaVista Software Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -188,10 +188,11 @@
 	bl	decompress_kernel
 
 	/*
-	 * Make sure the kernel knows we don't have things set  in
+	 * Make sure the kernel knows we don't have things set in
 	 * registers.  -- Tom
 	 */
 	li	r4,0
+	li	r5,0
 	li	r6,0
 
 	/*
diff -Nru a/arch/ppc/boot/pmac/chrpmain.c b/arch/ppc/boot/pmac/chrpmain.c
--- a/arch/ppc/boot/pmac/chrpmain.c	Wed May 29 11:43:01 2002
+++ b/arch/ppc/boot/pmac/chrpmain.c	Wed May 29 11:43:01 2002
@@ -41,6 +41,8 @@
 
 #define SCRATCH_SIZE	(128 << 10)
 
+typedef void (*kernel_start_t)(int, int, void *);
+
 void boot(int a1, int a2, void *prom)
 {
     unsigned sa, len;
@@ -90,7 +92,7 @@
     sa = (unsigned long)PROG_START;
     printf("start address = 0x%x\n", sa);
 
-    (*(void (*)())sa)(a1, a2, prom);
+    (*(kernel_start_t)sa)(a1, a2, prom);
 
     printf("returned?\n");
 
diff -Nru a/arch/ppc/boot/pmac/coffmain.c b/arch/ppc/boot/pmac/coffmain.c
--- a/arch/ppc/boot/pmac/coffmain.c	Wed May 29 11:43:01 2002
+++ b/arch/ppc/boot/pmac/coffmain.c	Wed May 29 11:43:01 2002
@@ -47,6 +47,8 @@
 
 static char heap[SCRATCH_SIZE];
 
+typedef void (*kernel_start_t)(int, int, void *);
+
 void boot(int a1, int a2, void *prom)
 {
     unsigned sa, len;
@@ -95,7 +97,7 @@
     sa = (unsigned long)PROG_START;
     printf("start address = 0x%x\n", sa);
 
-    (*(void (*)())sa)(a1, a2, prom);
+    (*(kernel_start_t)sa)(a1, a2, prom);
 
     printf("returned?\n");
 
diff -Nru a/arch/ppc/boot/pmac/start.c b/arch/ppc/boot/pmac/start.c
--- a/arch/ppc/boot/pmac/start.c	Wed May 29 11:43:02 2002
+++ b/arch/ppc/boot/pmac/start.c	Wed May 29 11:43:02 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.start.c 1.10 07/25/01 18:13:07 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Copyright (C) Paul Mackerras 1997.
@@ -14,7 +14,7 @@
 extern int strlen(const char *s);
 extern void boot(int a1, int a2, void *prom);
 
-int (*prom)();
+int (*prom)(void *);
 
 void *chosen_handle;
 void *stdin;
@@ -29,7 +29,7 @@
 void
 start(int a1, int a2, void *promptr)
 {
-    prom = (int (*)()) promptr;
+    prom = (int (*)(void *)) promptr;
     chosen_handle = finddevice("/chosen");
     if (chosen_handle == (void *) -1)
 	exit();
diff -Nru a/arch/ppc/boot/prep/misc.c b/arch/ppc/boot/prep/misc.c
--- a/arch/ppc/boot/prep/misc.c	Wed May 29 11:43:01 2002
+++ b/arch/ppc/boot/prep/misc.c	Wed May 29 11:43:01 2002
@@ -75,7 +75,7 @@
 
 extern void _put_MSR(unsigned int val);
 extern unsigned long serial_init(int chan, void *ignored);
-extern void setup_legacy(void);
+extern void serial_fixups(void);
 
 void
 writel(unsigned int val, unsigned int address)
@@ -134,7 +134,7 @@
 	int start_multi = 0;
 	unsigned int pci_viddid, pci_did, tulip_pci_base, tulip_base;
 
-	setup_legacy();
+	serial_fixups();
 #if defined(CONFIG_SERIAL_CONSOLE)
 	com_port = serial_init(0, NULL);
 #endif /* CONFIG_SERIAL_CONSOLE */
diff -Nru a/arch/ppc/boot/simple/chrpmap.S b/arch/ppc/boot/simple/chrpmap.S
--- a/arch/ppc/boot/simple/chrpmap.S	Wed May 29 11:43:02 2002
+++ b/arch/ppc/boot/simple/chrpmap.S	Wed May 29 11:43:02 2002
@@ -3,15 +3,15 @@
  *
  * Author: Tom Rini <trini@mvista.com>
  *
- * This will go and setup ISA_io to 0xFE00000.
+ * This will go and setup ISA_io to 0xFE00000 and return.
  */
 
 #include <asm/ppc_asm.h>
 
 	.text
 
-	.globl setup_legacy
-setup_legacy:
+	.globl serial_fixups
+serial_fixups:
 	lis	r3,ISA_io@h	/* Load ISA_io */
 	ori	r3,r3,ISA_io@l
 	lis	r4,0xFE00	/* Load the value, 0xFE00000 */
diff -Nru a/arch/ppc/boot/simple/direct.S b/arch/ppc/boot/simple/direct.S
--- a/arch/ppc/boot/simple/direct.S	Wed May 29 11:43:03 2002
+++ b/arch/ppc/boot/simple/direct.S	Wed May 29 11:43:03 2002
@@ -4,11 +4,12 @@
  * Author: Tom Rini <trini@mvista.com>
  *
  * This is an empty function for machines which use SERIAL_IO_MEM
- * and don't need ISA_io set to anything but 0;
+ * and don't need ISA_io set to anything but 0, or perform any other
+ * serial fixups.
  */
 
 	.text
 
-	.globl setup_legacy
-setup_legacy:
+	.globl serial_fixups
+serial_fixups:
 	blr
diff -Nru a/arch/ppc/boot/simple/embed_config.c b/arch/ppc/boot/simple/embed_config.c
--- a/arch/ppc/boot/simple/embed_config.c	Wed May 29 11:43:01 2002
+++ b/arch/ppc/boot/simple/embed_config.c	Wed May 29 11:43:01 2002
@@ -4,9 +4,17 @@
 
 /* Board specific functions for those embedded 8xx boards that do
  * not have boot monitor support for board information.
+ *
+ * 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 <linux/types.h>
 #include <linux/config.h>
+#include <linux/string.h>
+#include <asm/io.h>
 #ifdef CONFIG_8xx
 #include <asm/mpc8xx.h>
 #endif
@@ -14,12 +22,6 @@
 #include <asm/mpc8260.h>
 #include <asm/immap_8260.h>
 #endif
-#ifdef CONFIG_4xx
-#include <asm/io.h>
-#endif
-#if defined(CONFIG_405GP) || defined(CONFIG_NP405H) || defined(CONFIG_NP405L)
-#include <linux/netdevice.h>
-#endif
 
 /* For those boards that don't provide one.
 */
@@ -222,6 +224,23 @@
 	bd->bi_memsize = size * 1024 * 1024;
 }
 #endif /* LITE || CLASSIC || EP405 */
+#if defined(CONFIG_EP405)
+static void
+rpx_nvramsize(bd_t *bd, u_char *cp)
+{
+	uint	size;
+
+	size = 0;
+
+	while (*cp != '\n') {
+		size *= 10;
+		size += (*cp) - '0';
+		cp++;
+	}
+
+	bd->bi_nvramsize = size * 1024;
+}
+#endif /* CONFIG_EP405 */
 
 #endif	/* Embedded Planet boards */
 
@@ -641,7 +660,11 @@
 #ifdef CONFIG_TREEBOOT
 /* This could possibly work for all treeboot roms.
 */
+#if defined(CONFIG_ASH)
+#define BOARD_INFO_VECTOR       0xFFF80B50 /* openbios 1.19 moved this vector down  - armin */
+#else
 #define	BOARD_INFO_VECTOR	0xFFFE0B50
+#endif
 
 void
 embed_config(bd_t **bdp)
@@ -658,8 +681,8 @@
 	/* shut down the Ethernet controller that the boot rom
 	 * sometimes leaves running.
 	 */
-	mtdcr(DCRN_MALCR, MALCR_MMSR);                /* 1st reset MAL */
-	while (mfdcr(DCRN_MALCR) & MALCR_MMSR) {};    /* wait for the reset */
+	mtdcr(DCRN_MALCR(DCRN_MAL_BASE), MALCR_MMSR);     /* 1st reset MAL */
+	while (mfdcr(DCRN_MALCR(DCRN_MAL_BASE)) & MALCR_MMSR) {}; /* wait for the reset */	
 	emacp->em0mr0 = 0x20000000;        /* then reset EMAC */
 	eieio();
 #endif
@@ -684,24 +707,20 @@
 			bd->bi_pci_enetaddr[i] = *cp++;
 #endif
 		}
+		bd->bi_tbfreq = 200 * 1000 * 1000;
 		bd->bi_intfreq = 200000000;
 		bd->bi_busfreq = 100000000;
 #ifdef CONFIG_PCI
 		bd->bi_pci_busfreq = 66666666;
 #endif
-		/* Yeah, this look weird, but on Redwood 4 they are
-		 * different object in the structure.  When RW5 uses
-		 * OpenBIOS, it requires a special value.
-		 */
+	}
+	/* Yeah, this look weird, but on Redwood 4 they are
+	 * different object in the structure.  When RW5 uses
+	 * OpenBIOS, it requires a special value.
+	 */
 #ifdef CONFIG_REDWOOD_5
-	bd->bi_intfreq = 200 * 1000 * 1000;
-	bd->bi_busfreq = 0;
-
-		bd->bi_tbfreq = 27 * 1000 * 1000;
-#elif CONFIG_REDWOOD_4
-		bd->bi_tbfreq = bd->bi_intfreq;
+	bd->bi_tbfreq = 27 * 1000 * 1000;
 #endif
-	}
 }
 #endif
 
@@ -751,6 +770,13 @@
 	        	                }
                 	}
 
+			if (*cp == 'N') {
+				cp++;
+				if (*cp == 'V') {
+					cp += 2;
+					rpx_nvramsize(bd, cp);
+				}
+			}
 			while ((*cp != '\n') && (*cp != 0xff))
 			      cp++;
 
@@ -768,6 +794,31 @@
 	bd->bi_busfreq   = 100000000;
 	bd->bi_pci_busfreq= 33000000 ;
 #endif
+}
+#endif
+
+#ifdef CONFIG_RAINIER
+/* Rainier uses vxworks bootrom */
+void
+embed_config(bd_t **bdp)
+{
+	u_char	*cp;
+	int	i;
+	bd_t	*bd;
+	
+	bd = &bdinfo;
+	*bdp = bd;
+
+	bd->bi_memsize   = (32 * 1024 * 1024) ;
+	bd->bi_intfreq = 133000000; //the internal clock is 133 MHz
+	bd->bi_busfreq   = 100000000;
+	bd->bi_pci_busfreq= 33000000;
+
+	cp = (u_char *)def_enet_addr;
+	for (i=0; i<6; i++) {
+		bd->bi_enetaddr[i] = *cp++;
+	}
+
 }
 #endif
 
diff -Nru a/arch/ppc/boot/simple/legacy.S b/arch/ppc/boot/simple/legacy.S
--- a/arch/ppc/boot/simple/legacy.S	Wed May 29 11:43:02 2002
+++ b/arch/ppc/boot/simple/legacy.S	Wed May 29 11:43:02 2002
@@ -3,15 +3,15 @@
  *
  * Author: Tom Rini <trini@mvista.com>
  *
- * This will go and setup ISA_io to 0x8000000.
+ * This will go and setup ISA_io to 0x8000000 and return.
  */
 
 #include <asm/ppc_asm.h>
 
 	.text
 
-	.globl setup_legacy
-setup_legacy:
+	.globl serial_fixups
+serial_fixups:
 	lis	r3,ISA_io@h	/* Load ISA_io */
 	ori	r3,r3,ISA_io@l
 	lis	r4,0x8000	/* Load the value, 0x8000000 */
diff -Nru a/arch/ppc/boot/simple/misc-embedded.c b/arch/ppc/boot/simple/misc-embedded.c
--- a/arch/ppc/boot/simple/misc-embedded.c	Wed May 29 11:43:02 2002
+++ b/arch/ppc/boot/simple/misc-embedded.c	Wed May 29 11:43:02 2002
@@ -54,7 +54,7 @@
 char compiled_string[] = CONFIG_CMDLINE;
 #endif
 char ramroot_string[] = "root=/dev/ram";
-char netroot_string[] = "root=/dev/nfs rw ip=auto";
+char netroot_string[] = "root=/dev/nfs rw ip=on";
 
 /* Serial port to use. */
 unsigned long com_port;
diff -Nru a/arch/ppc/boot/utils/Makefile b/arch/ppc/boot/utils/Makefile
--- a/arch/ppc/boot/utils/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/ppc/boot/utils/Makefile	Wed May 29 11:43:02 2002
@@ -7,7 +7,7 @@
 
 HOSTCFLAGS += -I$(TOPDIR)/arch/$(ARCH)/boot/include
 
-all: dummy
+all: FORCE
 
 # Simple programs with 1 file and no extra CFLAGS
 UTILS = addnote hack-coff mkprep mknote mkbugboot mktree \
diff -Nru a/arch/ppc/config.in b/arch/ppc/config.in
--- a/arch/ppc/config.in	Wed May 29 11:43:01 2002
+++ b/arch/ppc/config.in	Wed May 29 11:43:01 2002
@@ -18,11 +18,15 @@
 define_bool CONFIG_PPC32 y
 choice 'Processor Type'	\
 	"6xx/7xx/74xx/8260	CONFIG_6xx	\
-	 4xx			CONFIG_4xx	\
+	 40x			CONFIG_40x	\
 	 POWER3               	CONFIG_POWER3	\
 	 8xx			CONFIG_8xx	\
 	 iSeries		CONFIG_PPC_ISERIES"	6xx
 
+if [ "$CONFIG_40x" = "y" ]; then
+  define_bool CONFIG_4xx y
+fi
+
 if [ "$CONFIG_6xx" = "y" ]; then
    bool 'MPC8260 CPM Support' CONFIG_8260
 fi
@@ -52,17 +56,21 @@
 	 Willow		CONFIG_WILLOW"	Willow
 fi
 
-if [ "$CONFIG_4xx" = "y" ]; then
+if [ "$CONFIG_40x" = "y" ]; then
     choice 'Machine Type'			\
 	"Ash		CONFIG_ASH		\
 	 Ceder		CONFIG_CEDER		\
 	 CPCI405	CONFIG_CPCI405 		\
-	 EP405		CONFIG_EP405 		\
+	 EP405/EP405PC	CONFIG_EP405 		\
 	 Oak		CONFIG_OAK 		\
 	 Redwood-4	CONFIG_REDWOOD_4 	\
 	 Redwood-5	CONFIG_REDWOOD_5 	\
 	 Tivo		CONFIG_TIVO 		\
 	 Walnut		CONFIG_WALNUT"	Walnut
+
+   if [ "$CONFIG_EP405" = "y" ]; then
+      bool 'EP405PC Support' CONFIG_EP405PC
+   fi  
 fi
 
 if [ "$CONFIG_8xx" = "y" ]; then
@@ -182,7 +190,7 @@
    bool 'Math emulation' CONFIG_MATH_EMULATION
 fi
 
-if [ "$CONFIG_4xx" = "y" ]; then
+if [ "$CONFIG_40x" = "y" ]; then
 # It's often necessary to know the specific 4xx processor type.
 # Fortunately, it is impled (so far) from the board type, so we
 # don't need to ask more redundant questions.
@@ -238,11 +246,9 @@
    bool 'Blue Logic DMA' CONFIG_405_DMA
    dep_bool 'Power Management support (experimental)' CONFIG_PM $CONFIG_EXPERIMENTAL
 
-   if [ "$CONFIG_4xx" = "y" ]; then
-      choice 'TTYS0 device and default console'	\
+   choice 'TTYS0 device and default console'	\
 	"UART0  CONFIG_UART0_TTYS0		\
 	 UART1	CONFIG_UART0_TTYS1"		UART0
-   fi
 
    define_bool CONFIG_IBM405_ERR51 y
    define_bool CONFIG_NOT_COHERENT_CACHE y
@@ -282,7 +288,7 @@
    if [ "$CONFIG_8xx" = "y" ]; then
       bool "Pinned Kernel TLBs (860 ONLY)" CONFIG_PIN_TLB
    fi
-   if [ "$CONFIG_4xx" = "y" ]; then
+   if [ "$CONFIG_40x" = "y" ]; then
       bool "Pinned Kernel TLBs" CONFIG_PIN_TLB
    fi
    if [ "$CONFIG_ALL_PPC" != "y" ]; then
@@ -362,6 +368,7 @@
    bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
    bool 'Support for RTAS (RunTime Abstraction Services) in /proc' CONFIG_PPC_RTAS
    bool 'Support for PReP Residual Data' CONFIG_PREP_RESIDUAL
+   dep_bool '  Support for reading of PReP Residual Data in /proc' CONFIG_PROC_PREPRESIDUAL $CONFIG_PREP_RESIDUAL
 fi
 
 bool 'Default bootloader kernel arguments' CONFIG_CMDLINE_BOOL
@@ -574,15 +581,15 @@
    source arch/ppc/8260_io/Config.in
 fi
 
-if [ "$CONFIG_4xx" = "y"]; then
+if [ "$CONFIG_40x" = "y" ]; then
    mainmenu_option next_comment
-   comment 'IBM 4xx options'
+   comment 'IBM 40x options'
    if [ "$CONFIG_STB03xxx" = "y" ]; then
       bool 'STB IR Keyboard' CONFIG_STB_KB
       bool 'SICC Serial port' CONFIG_SERIAL_SICC
       if [ "$CONFIG_SERIAL_SICC" = "y" -a "$CONFIG_UART0_TTYS1" = "y" ]; then
-         define_bool CONFIG_UART1_DFLT_CONSOLE y	
-         define_bool CONFIG_SERIAL_SICC_CONSOLE y
+	 define_bool CONFIG_UART1_DFLT_CONSOLE y	
+	 define_bool CONFIG_SERIAL_SICC_CONSOLE y
       fi
    fi
    endmenu
@@ -621,8 +628,8 @@
 fi
 if [ "$CONFIG_4xx" = "y" -o "$CONFIG_GT64260" = "y"		\
      -o "$CONFIG_LOPEC" = "y" -o "$CONFIG_MCPN765" = "y"	\
-     -o "$CONFIG_PRPMC800" = "y" -o "$CONFIG_SANDPOINT" = "y"	\
-     -o "$CONFIG_ZX4500" = "y" ]; then
+     -o "$CONFIG_PPLUS" = "y" -o "$CONFIG_PRPMC800" = "y"	\
+     -o "$CONFIG_SANDPOINT" = "y" -o "$CONFIG_ZX4500" = "y" ]; then
    bool 'Support for early boot texts over serial port' CONFIG_SERIAL_TEXT_DEBUG
 fi
 endmenu
diff -Nru a/arch/ppc/iSeries/Makefile b/arch/ppc/iSeries/Makefile
--- a/arch/ppc/iSeries/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/ppc/iSeries/Makefile	Wed May 29 11:43:02 2002
@@ -1,11 +1,6 @@
 #
 # Makefile for Linux arch/ppc/iSeries source directory
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := iSeries.o
 export-objs := iSeries_ksyms.o
@@ -13,7 +8,7 @@
 
 obj-$(CONFIG_PCI) += XmPciLpEvent.o iSeries_FlightRecorder.o iSeries_IoMmTable.o iSeries_VpdInfo.o iSeries_fixup.o iSeries_irq.o iSeries_pci.o iSeries_pci_proc.o iSeries_reset_device.o
 
-all: iSeries.o
+include $(TOPDIR)/Rules.make
 
 LparData.c:: ReleaseData.h
 
@@ -23,4 +18,3 @@
 clean:
 	rm -f ReleaseData.h
 
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
--- a/arch/ppc/kernel/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/ppc/kernel/Makefile	Wed May 29 11:43:02 2002
@@ -3,11 +3,6 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
 ifdef CONFIG_PPC64BRIDGE
 EXTRA_AFLAGS		:= -Wa,-mppc64bridge
@@ -21,13 +16,12 @@
 
 # Start off with 'head.o', change as needed.
 HEAD-y				:= head.o
-HEAD-$(CONFIG_4xx)		:= head_4xx.o
+HEAD-$(CONFIG_40x)		:= head_4xx.o
 HEAD-$(CONFIG_8xx)		:= head_8xx.o
 HEAD-$(CONFIG_PPC_ISERIES)	:= iSeries_head.o
 
-all: $(HEAD-y) kernel.o
-
-O_TARGET := kernel.o
+O_TARGET 	:= kernel.o
+EXTRA_TARGETS	:= $(HEAD-y)
 
 export-objs			:= ppc_ksyms.o time.o ppc405_dma.o
 
@@ -54,19 +48,18 @@
 endif
 obj-$(CONFIG_8xx)		+= m8xx_setup.o ppc8xx_pic.o
 ifeq ($(CONFIG_8xx),y)
-obj-$(CONFIG_PCI)		+= qspan_pci.o
-ifndef CONFIG_MATH_EMULATION
+obj-$(CONFIG_PCI)		+= qspan_pci.o i8259.o
+ifneq ($(CONFIG_MATH_EMULATION),n)
 obj-y				+= softemu8xx.o
 endif
 endif
-obj-$(CONFIG_MBX)		+= i8259.o
 obj-$(CONFIG_ALL_PPC)		+= prom_init.o prom.o open_pic.o \
 					indirect_pci.o i8259.o
 obj-$(CONFIG_ADIR)		+= i8259.o indirect_pci.o pci_auto.o \
 					todc_time.o
 obj-$(CONFIG_EV64260)		+= gt64260_common.o gt64260_pic.o \
 					indirect_pci.o todc_time.o pci_auto.o
-obj-$(CONFIG_GEMINI)		+= open_pic.o
+obj-$(CONFIG_GEMINI)		+= open_pic.o i8259.o
 obj-$(CONFIG_K2)		+= i8259.o indirect_pci.o todc_time.o \
 					pci_auto.o
 obj-$(CONFIG_LOPEC)		+= mpc10x_common.o indirect_pci.o pci_auto.o \
diff -Nru a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c
--- a/arch/ppc/kernel/cputable.c	Wed May 29 11:43:03 2002
+++ b/arch/ppc/kernel/cputable.c	Wed May 29 11:43:03 2002
@@ -283,7 +283,7 @@
 	__setup_cpu_8xx	/* Empty */
     },
 #endif /* CONFIG_8xx */
-#ifdef CONFIG_4xx
+#ifdef CONFIG_40x
     {	/* 403GC */
     	0xffffff00, 0x00200200, "403GC",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
@@ -333,7 +333,38 @@
 	16, 8,
 	0, /*__setup_cpu_405 */
     },
-#endif /* CONFIG_4xx */
+    {	/* NP4GS3 */
+    	0xffff0000, 0x40B10000, "NP4GS3",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+    	PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+	16, 8,
+	0, /*__setup_cpu_405 */
+    },
+    {   /* NP405H */
+        0xffff0000, 0x41410000, "NP405H",
+        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+        PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+        16, 8,
+        0, /*__setup_cpu_405 */
+     },
+
+#endif /* CONFIG_40x */
+#ifdef CONFIG_440
+    { /* 440GP Rev. B */
+        0xf0000fff, 0x40000440, "440GP Rev. B",
+        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+        PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+        32, 32,
+        0, /*__setup_cpu_440 */
+    },
+    { /* 440GP Rev. C */
+        0xf0000fff, 0x40000481, "440GP Rev. C",
+        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+        PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+        32, 32,
+        0, /*__setup_cpu_440 */
+    },
+#endif /* CONFIG_440 */
 #if !CLASSIC_PPC
     {	/* default match */
     	0x00000000, 0x00000000, "(generic PPC)",
diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
--- a/arch/ppc/kernel/head.S	Wed May 29 11:43:01 2002
+++ b/arch/ppc/kernel/head.S	Wed May 29 11:43:01 2002
@@ -507,7 +507,6 @@
 	lwz	r2,0(r2)		/* get pmd entry */
 	rlwinm.	r2,r2,0,0,19		/* extract address of pte page */
 	beq-	InstructionAddressInvalid	/* return if no mapping */
-	tophys(r2,r2)
 	rlwimi	r2,r3,22,20,29		/* insert next 10 bits of address */
 	lwz	r3,0(r2)		/* get linux-style pte */
 	andc.	r1,r1,r3		/* check access & ~permission */
@@ -582,7 +581,6 @@
 	lwz	r2,0(r2)		/* get pmd entry */
 	rlwinm.	r2,r2,0,0,19		/* extract address of pte page */
 	beq-	DataAddressInvalid	/* return if no mapping */
-	tophys(r2,r2)
 	rlwimi	r2,r3,22,20,29		/* insert next 10 bits of address */
 	lwz	r3,0(r2)		/* get linux-style pte */
 	andc.	r1,r1,r3		/* check access & ~permission */
@@ -655,7 +653,6 @@
 	lwz	r2,0(r2)		/* get pmd entry */
 	rlwinm.	r2,r2,0,0,19		/* extract address of pte page */
 	beq-	DataAddressInvalid	/* return if no mapping */
-	tophys(r2,r2)
 	rlwimi	r2,r3,22,20,29		/* insert next 10 bits of address */
 	lwz	r3,0(r2)		/* get linux-style pte */
 	andc.	r1,r1,r3		/* check access & ~permission */
diff -Nru a/arch/ppc/kernel/i8259.c b/arch/ppc/kernel/i8259.c
--- a/arch/ppc/kernel/i8259.c	Wed May 29 11:43:03 2002
+++ b/arch/ppc/kernel/i8259.c	Wed May 29 11:43:03 2002
@@ -21,17 +21,37 @@
 
 int i8259_pic_irq_offset;
 
-/* Acknowledge the irq using the PCI host bridge's interrupt acknowledge
- * feature. (Polling is somehow broken on some IBM and Motorola PReP boxes.)
+/*
+ * Acknowledge the IRQ using either the PCI host bridge's interrupt
+ * acknowledge feature or poll.  How i8259_init() is called determines
+ * which is called.  It should be noted that polling is broken on some
+ * IBM and Motorola PReP boxes so we must use the int-ack feature on them.
  */
-int i8259_irq(struct pt_regs *regs)
+int
+i8259_irq(struct pt_regs *regs)
 {
 	int irq;
 
-	spin_lock/*_irqsave*/(&i8259_lock/*, flags*/);
+	spin_lock(&i8259_lock);
 
-	irq = *pci_intack;
-	if (irq==7) {
+	/* Either int-ack or poll for the IRQ */
+	if (pci_intack)
+		irq = *pci_intack;
+	else {
+		/* Perform an interrupt acknowledge cycle on controller 1. */
+		outb(0x0C, 0x20);		/* prepare for poll */
+		irq = inb(0x20) & 7;
+		if (irq == 2 ) {
+			/*
+			 * Interrupt is cascaded so perform interrupt
+			 * acknowledge on controller 2.
+			 */
+			outb(0x0C, 0xA0);	/* prepare for poll */
+			irq = (inb(0xA0) & 7) + 8;
+		}
+	}
+
+	if (irq == 7) {
 		/*
 		 * This may be a spurious interrupt.
 		 *
@@ -39,47 +59,13 @@
 		 * significant bit is not set then there is no valid
 		 * interrupt.
 		 */
-		if(~inb(0x20)&0x80) {
+		if (!pci_intack)
+			outb(0x0B, 0x20);	/* ISR register */
+		if(~inb(0x20) & 0x80)
 			irq = -1;
-		}
 	}
-	spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
-	return irq;
-}
-
-/* Poke the 8259's directly using poll commands. */
-int i8259_poll(void)
-{
-	int irq;
 
-	spin_lock/*_irqsave*/(&i8259_lock/*, flags*/);
-	/*
-	 * Perform an interrupt acknowledge cycle on controller 1
-	 */
-	outb(0x0C, 0x20); /* prepare for poll */
-	irq = inb(0x20) & 7;
-	if (irq == 2) {
-		/*
-		 * Interrupt is cascaded so perform interrupt
-		 * acknowledge on controller 2
-		 */
-		outb(0x0C, 0xA0); /* prepare for poll */
-		irq = (inb(0xA0) & 7) + 8;
-	} else if (irq==7) {
-		/*
-		 * This may be a spurious interrupt
-		 *
-		 * Read the interrupt status register. If the most
-		 * significant bit is not set then there is no valid
-		 * interrupt
-		 */
-		outb(0x0b, 0x20);
-		if(~inb(0x20)&0x80) {
-			spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
-			return -1;
-		}
-	}
-	spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
+	spin_unlock(&i8259_lock);
 	return irq;
 }
 
@@ -171,11 +157,13 @@
 	"8259 edge control", 0x4d0, 0x4d1, IORESOURCE_BUSY
 };
 
-/* i8259_init()
+/*
+ * i8259_init()
  * intack_addr - PCI interrupt acknowledge (real) address which will return
  *               the active irq from the 8259
  */
-void __init i8259_init(long intack_addr)
+void __init
+i8259_init(long intack_addr)
 {
 	unsigned long flags;
 
@@ -209,9 +197,6 @@
 	request_resource(&ioport_resource, &pic2_iores);
 	request_resource(&ioport_resource, &pic_edgectrl_iores);
 
-	/* XXX remove me after board maintainers fix their i8259_init calls */
-	if (intack_addr == 0)
-		panic("You must supply a PCI interrupt acknowledge address to i8259_init()\n");
-
-	pci_intack = ioremap(intack_addr, 1);
+	if (intack_addr != 0)
+		pci_intack = ioremap(intack_addr, 1);
 }
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S	Wed May 29 11:43:02 2002
+++ b/arch/ppc/kernel/misc.S	Wed May 29 11:43:02 2002
@@ -354,7 +354,7 @@
  * Flush MMU TLB
  */
 _GLOBAL(_tlbia)
-#if defined(CONFIG_4xx) && defined(CONFIG_PIN_TLB)
+#if defined(CONFIG_40x) && defined(CONFIG_PIN_TLB)
 	/* This needs to be coordinated with other pinning functions since
 	 * we don't keep a memory location of number of entries to reduce
 	 * cache pollution during these operations.
@@ -401,14 +401,14 @@
 	tlbia
 	sync
 #endif /* CONFIG_SMP */
-#endif /* CONFIG_4xx */
+#endif /* defined(CONFIG_40x) && defined(CONFIG_PIN_TLB) */
 	blr	
 
 /*
  * Flush MMU TLB for a particular address
  */
 _GLOBAL(_tlbie)
-#ifdef CONFIG_4xx
+#ifdef CONFIG_40x
 	tlbsx.	r3, 0, r3
 	bne	10f
 	sync
@@ -418,7 +418,7 @@
 	tlbwe	r3, r3, TLB_TAG
 	isync
 10:
-#else
+#else /* ! CONFIG_40x */
 #if defined(CONFIG_SMP)
 	rlwinm	r8,r1,0,0,18
 	lwz	r8,TI_CPU(r8)
@@ -451,7 +451,7 @@
 	tlbie	r3
 	sync
 #endif /* CONFIG_SMP */
-#endif /* CONFIG_4xx */
+#endif /* ! CONFIG_40x */
 	blr
 
 /*
@@ -463,7 +463,7 @@
 	isync
 	lis	r5, IDC_INVALL@h
 	mtspr	IC_CST, r5
-#elif defined(CONFIG_4xx)
+#elif defined(CONFIG_40x)
 #ifdef CONFIG_403GCX
 	li      r3, 512
 	mtctr   r3
diff -Nru a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
--- a/arch/ppc/kernel/open_pic.c	Wed May 29 11:43:03 2002
+++ b/arch/ppc/kernel/open_pic.c	Wed May 29 11:43:03 2002
@@ -799,26 +799,20 @@
 
 #endif /* CONFIG_SMP */
 
-/* This one may be merged with PReP and CHRP */
 int
 openpic_get_irq(struct pt_regs *regs)
 {
-/*
- * Clean up needed. -VAL
- */
 	int irq = openpic_irq();
 
-	/* Management of the cascade should be moved out of here */
-
-	/* Yep - because openpic !=> i8259, for one thing. -VAL */
-	if (open_pic_irq_offset && irq == open_pic_irq_offset)
-	{
-#ifndef CONFIG_GEMINI
-		irq = i8259_irq(regs); /* get IRQ from cascade */
-#endif
+	/*
+	 * This needs to be cleaned up.  We don't necessarily have
+	 * an i8259 cascaded or even a cascade.
+	 */
+	if (open_pic_irq_offset && irq == open_pic_irq_offset) {
+		/* Get the IRQ from the cascade. */
+		irq = i8259_irq(regs);
 		openpic_eoi();
-	}
-	if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
+	} else if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
 		irq = -1;
 	return irq;
 }
diff -Nru a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c
--- a/arch/ppc/kernel/ppc-stub.c	Wed May 29 11:43:02 2002
+++ b/arch/ppc/kernel/ppc-stub.c	Wed May 29 11:43:02 2002
@@ -514,7 +514,7 @@
 	unsigned int tt;		/* Trap type code for powerpc */
 	unsigned char signo;		/* Signal that we map this trap into */
 } hard_trap_info[] = {
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_40x)
 	{ 0x100, SIGINT  },		/* critical input interrupt */
 	{ 0x200, SIGSEGV },		/* machine check */
 	{ 0x300, SIGSEGV },		/* data storage */
@@ -613,7 +613,7 @@
 	sigval = computeSignal(regs->trap);
 	ptr = remcomOutBuffer;
 
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_40x)
 	*ptr++ = 'S';
 	*ptr++ = hexchars[sigval >> 4];
 	*ptr++ = hexchars[sigval & 0xf];
@@ -785,7 +785,7 @@
  * some location may have changed something that is in the instruction cache.
  */
 			kgdb_flush_cache_all();
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_40x)
 			strcpy(remcomOutBuffer, "OK");
 			putpacket(remcomOutBuffer);
 #endif
@@ -802,7 +802,7 @@
 
 		case 's':
 			kgdb_flush_cache_all();
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_40x)
 			regs->msr |= MSR_DE;
 			regs->dbcr0 |= (DBCR0_IDM | DBCR0_IC);
 			set_msr(msr);
diff -Nru a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
--- a/arch/ppc/kernel/signal.c	Wed May 29 11:43:02 2002
+++ b/arch/ppc/kernel/signal.c	Wed May 29 11:43:02 2002
@@ -40,13 +40,9 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
 extern void sigreturn_exit(struct pt_regs *);
 
-#define GP_REGS_SIZE	MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs))
+#define GP_REGS_SIZE	min(sizeof(elf_gregset_t), sizeof(struct pt_regs))
 
 /* 
  * These are the flags in the MSR that the user is allowed to change
@@ -62,41 +58,6 @@
 
 int do_signal(sigset_t *oldset, struct pt_regs *regs);
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
-		int err;
-
-		/* If you change siginfo_t structure, please be sure
-		   this code is fixed accordingly.
-		   It should never copy any pad contained in the structure
-		   to avoid security leaks, but must copy the generic
-		   3 ints plus the relevant union member.  */
-		err = __put_user(from->si_signo, &to->si_signo);
-		err |= __put_user(from->si_errno, &to->si_errno);
-		err |= __put_user((short)from->si_code, &to->si_code);
-		/* First 32bits of unions are always present.  */
-		err |= __put_user(from->si_pid, &to->si_pid);
-		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
-		case __SI_CHLD >> 16:
-			err |= __put_user(from->si_utime, &to->si_utime);
-			err |= __put_user(from->si_stime, &to->si_stime);
-			err |= __put_user(from->si_status, &to->si_status);
-		default:
-			err |= __put_user(from->si_uid, &to->si_uid);
-			break;
-		/* case __SI_RT: This is not generated by the kernel as of now.  */
-		}
-		return err;
-	}
-}
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -426,12 +387,12 @@
  * OK, we're invoking a handler
  */
 static void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
-	      unsigned long *newspp, unsigned long frame)
+handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
+	struct pt_regs * regs, unsigned long *newspp, unsigned long frame)
 {
 	struct sigcontext_struct *sc;
 	struct rt_sigframe *rt_sf;
+	struct k_sigaction *ka = &current->sig->action[sig-1];
 
 	if (TRAP(regs) == 0x0C00 /* System Call! */
 	    && ((int)regs->result == -ERESTARTNOHAND ||
@@ -454,7 +415,7 @@
 		    || __put_user(&rt_sf->info, &rt_sf->pinfo)
 		    || __put_user(&rt_sf->uc, &rt_sf->puc)
 		    /* Put the siginfo */
-		    || __copy_to_user(&rt_sf->info, info, sizeof(*info))
+		    || copy_siginfo_to_user(&rt_sf->info, info)
 		    /* Create the ucontext */
 		    || __put_user(0, &rt_sf->uc.uc_flags)
 		    || __put_user(0, &rt_sf->uc.uc_link)
@@ -515,101 +476,16 @@
 	siginfo_t info;
 	struct k_sigaction *ka;
 	unsigned long frame, newsp;
+	int signr;
 
 	if (!oldset)
 		oldset = &current->blocked;
 
 	newsp = frame = 0;
 
-	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->parent->pid;
-				info.si_uid = current->parent->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		ka = &current->sig->action[signr-1];
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP:
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				if (!(current->parent->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
 		if ( (ka->sa.sa_flags & SA_ONSTACK)
 		     && (! on_sig_stack(regs->gpr[1])))
 			newsp = (current->sas_ss_sp + current->sas_ss_size);
@@ -618,8 +494,7 @@
 		newsp = frame = newsp - sizeof(struct sigregs);
 
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
-		break;
+		handle_signal(signr, &info, oldset, regs, &newsp, frame);
 	}
 
 	if (TRAP(regs) == 0x0C00 /* System Call! */ &&
diff -Nru a/arch/ppc/mm/Makefile b/arch/ppc/mm/Makefile
--- a/arch/ppc/mm/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/ppc/mm/Makefile	Wed May 29 11:43:02 2002
@@ -21,7 +21,7 @@
 
 obj-$(CONFIG_PPC_STD_MMU)	+= hashtable.o ppc_mmu.o tlb.o
 obj-$(CONFIG_PPC_ISERIES)	+= iSeries_hashtable.o iSeries_mmu.o tlb.o
-obj-$(CONFIG_4xx)		+= 4xx_mmu.o
+obj-$(CONFIG_40x)		+= 4xx_mmu.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)	+= cachemap.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
--- a/arch/ppc/platforms/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/ppc/platforms/Makefile	Wed May 29 11:43:03 2002
@@ -3,23 +3,16 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
 ifdef CONFIG_PPC64BRIDGE
 EXTRA_AFLAGS		:= -Wa,-mppc64bridge
 endif
-ifdef CONFIG_4xx
+ifdef CONFIG_40x
 EXTRA_AFLAGS		:= -Wa,-m405
 endif
 
 # Extra CFLAGS so we don't have to do relative includes
 CFLAGS_pmac_setup.o	+= -I$(TOPDIR)/arch/$(ARCH)/mm
-
-all: platform.o
 
 O_TARGET := platform.o
 
diff -Nru a/arch/ppc/platforms/ep405.c b/arch/ppc/platforms/ep405.c
--- a/arch/ppc/platforms/ep405.c	Wed May 29 11:43:01 2002
+++ b/arch/ppc/platforms/ep405.c	Wed May 29 11:43:01 2002
@@ -32,42 +32,51 @@
 #define DBG(x...)
 #endif
 
-void *ep405_bcsr;
-void *ep405_nvram;
+u8 *ep405_bcsr;
+u8 *ep405_nvram;
+
+static struct {
+	u8 cpld_xirq_select;
+	int pci_idsel;
+	int irq;
+} ep405_devtable[] = {
+#ifdef CONFIG_EP405PC
+	{0x07, 0x0E, 25},		/* EP405PC: USB */
+#endif
+};
+#define EP405_DEVTABLE_SIZE (sizeof(ep405_devtable)/sizeof(ep405_devtable[0]))
 
 int __init
 ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
 {
-	static char pci_irq_table[][4] =
-	    /*
-	     *      PCI IDSEL/INTPIN->INTLINE
-	     *      A       B       C       D
-	     */
-	{
-		{28, 28, 28, 28},	/* IDSEL 1 - PCI slot 1 */
-		{29, 29, 29, 29},	/* IDSEL 2 - PCI slot 2 */
-		{30, 30, 30, 30},	/* IDSEL 3 - PCI slot 3 */
-		{31, 31, 31, 31},	/* IDSEL 4 - PCI slot 4 */
-	};
-	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
-	return PCI_IRQ_TABLE_LOOKUP;
+	int i;
+
+	/* AFAICT this is only called a few times during PCI setup, so
+	   performance is not critical */
+	for (i = 0; i < EP405_DEVTABLE_SIZE; i++) {
+		if (idsel == ep405_devtable[i].pci_idsel)
+			return ep405_devtable[i].irq;
+	}
+	return -1;
 };
 
 void __init
 board_setup_arch(void)
 {
+	bd_t *bip = (bd_t *) __res;
+
 #ifdef CONFIG_PPC_RTC
-	/* FIXME: what if NVRAM size is not 512k */
-	TODC_INIT(TODC_TYPE_DS1557, ep405_nvram, ep405_nvram, ep405_nvram, 8);
-#endif				/* CONFIG_PPC_RTC */
+	if (bip->bi_nvramsize == 512*1024) {
+		/* FIXME: we should properly handle NVRTCs of different sizes */
+		TODC_INIT(TODC_TYPE_DS1557, ep405_nvram, ep405_nvram, ep405_nvram, 8);
+	}
+#endif
 }
 
 void __init
-bios_fixup(struct pci_controller *hose, void *pcil0_base)
+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
 {
-
 	unsigned int bar_response, bar;
-	struct pcil0_regs *pcip;
 	/*
 	 * Expected PCI mapping:
 	 *
@@ -82,29 +91,7 @@
 	 *
 	 */
 
-#ifdef DEBUG
-	int i;
-	pcip = (struct pcil0_regs *) pcil0_base;
-
-	printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
-	printk("PCI bridge regs before fixup \n");
-	for (i = 0; i <= 3; i++) {
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
-	}
-	printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
-	printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
-	printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
-	printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
-
-#else
-	pcip = (struct pcil0_regs *) pcil0_base;
-#endif
-	/* added for IBM boot rom version 1.15 bios bar changes  -AK */
-
-	/* Disable region first */
+	/* Disable region zero first */
 	out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
 	/* PLB starting addr, PCI: 0x80000000 */
 	out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
@@ -133,6 +120,11 @@
 	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
 	out_le32((void *) &(pcip->ptm2ms), 0x00000000);
 
+	/* Configure PTM (PCI->PLB) region 1 */
+	out_le32((void *) &(pcip->ptm1la), 0x00000000); /* PLB base address */
+	/* Disable PTM region 2 */
+	out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+
 	/* Zero config bars */
 	for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
 		early_write_config_dword(hose, hose->first_busno,
@@ -146,42 +138,60 @@
 		    PCI_FUNC(hose->first_busno), bar, bar_response);
 	}
 	/* end work arround */
-
-#ifdef DEBUG
-	printk("PCI bridge regs after fixup \n");
-	for (i = 0; i <= 3; i++) {
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
-	}
-	printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
-	printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
-	printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
-	printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
-#endif
 }
 
 void __init
 board_io_mapping(void)
 {
+	bd_t *bip = (bd_t *) __res;
+
 	ep405_bcsr = ioremap(EP405_BCSR_PADDR, EP405_BCSR_SIZE);
-	ep405_nvram = ioremap(EP405_NVRAM_PADDR, EP405_NVRAM_SIZE);
+
+	if (bip->bi_nvramsize > 0) {
+		ep405_nvram = ioremap(EP405_NVRAM_PADDR, bip->bi_nvramsize);
+	}
 }
 
 void __init
 board_setup_irq(void)
 {
+	int i;
+
+	/* Workaround for a bug in the firmware it incorrectly sets
+	   the IRQ polarities for XIRQ0 and XIRQ1 */
+	mtdcr(DCRN_UIC_PR(DCRN_UIC0_BASE), 0xffffff80); /* set the polarity */
+	mtdcr(DCRN_UIC_SR(DCRN_UIC0_BASE), 0x00000060); /* clear bogus interrupts */
+
+	/* Activate the XIRQs from the CPLD */
+	writeb(0xf0, ep405_bcsr+10);
+
+	/* Set up IRQ routing */
+	for (i = 0; i < EP405_DEVTABLE_SIZE; i++) {
+		if ( (ep405_devtable[i].irq >= 25)
+		     && (ep405_devtable[i].irq) <= 31) {
+			writeb(ep405_devtable[i].cpld_xirq_select, ep405_bcsr+5);
+			writeb(ep405_devtable[i].irq - 25, ep405_bcsr+6);
+		}
+	}
 }
 
 void __init
 board_init(void)
 {
+	bd_t *bip = (bd_t *) __res;
+
 #ifdef CONFIG_PPC_RTC
-	ppc_md.time_init = todc_time_init;
-	ppc_md.set_rtc_time = todc_set_rtc_time;
-	ppc_md.get_rtc_time = todc_get_rtc_time;
+	/* FIXME: we should be able to access the NVRAM even if PPC_RTC is not configured */
 	ppc_md.nvram_read_val = todc_direct_read_val;
 	ppc_md.nvram_write_val = todc_direct_write_val;
+
+	if (bip->bi_nvramsize == 512*1024) {
+		ppc_md.time_init = todc_time_init;
+		ppc_md.set_rtc_time = todc_set_rtc_time;
+		ppc_md.get_rtc_time = todc_get_rtc_time;
+	} else {
+		printk("EP405: NVRTC size is not 512k (not a DS1557).  Not sure what to do with it\n");
+	}
+
 #endif
 }
diff -Nru a/arch/ppc/platforms/ep405.h b/arch/ppc/platforms/ep405.h
--- a/arch/ppc/platforms/ep405.h	Wed May 29 11:43:01 2002
+++ b/arch/ppc/platforms/ep405.h	Wed May 29 11:43:01 2002
@@ -22,37 +22,20 @@
 	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
 	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
 	unsigned int	 bi_pci_busfreq;	/* PCI Bus speed, in Hz */
+	unsigned int	 bi_nvramsize;		/* Size of the NVRAM/RTC */
 } bd_t;
 
 /* Some 4xx parts use a different timebase frequency from the internal clock.
 */
 #define bi_tbfreq bi_intfreq
 
-extern void *ep405_bcsr;
-extern void *ep405_nvram;
+extern u8 *ep405_bcsr;
+extern u8 *ep405_nvram;
 
 /* Map for the BCSR and NVRAM space */
 #define EP405_BCSR_PADDR	((uint)0xf4000000)
 #define EP405_BCSR_SIZE		((uint)16)
 #define EP405_NVRAM_PADDR	((uint)0xf4200000)
-/* FIXME: what if the board has something other than 512k NVRAM */
-#define EP405_NVRAM_SIZE	((uint)512*1024)
-
-/* Early initialization address mapping for block_io.
- * Standard 405GP map.
- */
-#define PPC4xx_PCI_IO_PADDR	((uint)PPC405_PCI_PHY_IO_BASE)
-#define PPC4xx_PCI_IO_VADDR	PPC4xx_PCI_IO_PADDR
-#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
-#define PPC4xx_PCI_CFG_PADDR	((uint)PPC405_PCI_CONFIG_ADDR)
-#define PPC4xx_PCI_CFG_VADDR	PPC4xx_PCI_CFG_PADDR
-#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
-#define PPC4xx_PCI_LCFG_PADDR	((uint)0xef400000)
-#define PPC4xx_PCI_LCFG_VADDR	PPC4xx_PCI_LCFG_PADDR
-#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
-#define PPC4xx_ONB_IO_PADDR	((uint)0xef600000)
-#define PPC4xx_ONB_IO_VADDR	PPC4xx_ONB_IO_PADDR
-#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
 
 /* serial defines */
 #define BASE_BAUD		399193
diff -Nru a/arch/ppc/platforms/ibm405.h b/arch/ppc/platforms/ibm405.h
--- a/arch/ppc/platforms/ibm405.h	Wed May 29 11:43:01 2002
+++ b/arch/ppc/platforms/ibm405.h	Wed May 29 11:43:01 2002
@@ -32,6 +32,9 @@
  *
  *	Version 1.0 (02/01/17) - A. Kuster
  *	Initial version	 - moved 405  specific out of the other core.h's
+ *
+ *	Version 1.0 (02/08/02) - A. Kuster
+ *	removed DCRN_UIC1_BASE to NP405L & H
  */
 
 #ifdef __KERNEL__
@@ -57,7 +60,6 @@
 #define DCRN_CHCR0	(DCRN_CHCR_BASE + 0x0)	/* Chip Control Register 1 */
 #define DCRN_CHCR1	(DCRN_CHCR_BASE + 0x1)	/* Chip Control Register 2 */
 #endif
-#define CHR1_CETE	0x00800000	/* CPU external timer enable */
 #define CHR1_PCIPW	0x00008000	/* PCI Int enable/Peripheral Write enable */
 
 #ifdef DCRN_CHPSR_BASE
@@ -211,25 +213,38 @@
 #define IOCR_SCS	0x00000002
 #define IOCR_SPC	0x00000001
 
-#ifdef DCRN_MAL_BASE
-#define DCRN_MALCR		(DCRN_MAL_BASE + 0x0)	/* MAL Configuration */
-#define DCRN_MALDBR		(DCRN_MAL_BASE + 0x3)	/* Debug Register */
-#define DCRN_MALESR		(DCRN_MAL_BASE + 0x1)	/* Error Status */
-#define DCRN_MALIER		(DCRN_MAL_BASE + 0x2)	/* Interrupt Enable */
-#define DCRN_MALTXCARR		(DCRN_MAL_BASE + 0x5)	/* TX Channed Active Reset Register */
-#define DCRN_MALTXCASR		(DCRN_MAL_BASE + 0x4)	/* TX Channel Active Set Register */
-#define DCRN_MALTXDEIR		(DCRN_MAL_BASE + 0x7)	/* Tx Descriptor Error Interrupt */
-#define DCRN_MALTXEOBISR	(DCRN_MAL_BASE + 0x6)	/* Tx End of Buffer Interrupt Status */
-#define DCRN_MALRXCARR		(DCRN_MAL_BASE + 0x11)	/* RX Channed Active Reset Register */
-#define DCRN_MALRXCASR		(DCRN_MAL_BASE + 0x10)	/* RX Channel Active Set Register */
-#define DCRN_MALRXDEIR		(DCRN_MAL_BASE + 0x13)	/* Rx Descriptor Error Interrupt */
-#define DCRN_MALRXEOBISR	(DCRN_MAL_BASE + 0x12)	/* Rx End of Buffer Interrupt Status */
-#define DCRN_MALRXCTP0R		(DCRN_MAL_BASE + 0x40)	/* Channel Rx 0 Channel Table Pointer */
-#define DCRN_MALTXCTP0R		(DCRN_MAL_BASE + 0x20)	/* Channel Tx 0 Channel Table Pointer */
-#define DCRN_MALTXCTP1R		(DCRN_MAL_BASE + 0x21)	/* Channel Tx 1 Channel Table Pointer */
-#define DCRN_MALRCBS0		(DCRN_MAL_BASE + 0x60)	/* Channel Rx 0 Channel Buffer Size */
-#endif
-	/* DCRN_MALCR */
+#define DCRN_MALCR(base)	(base + 0x0)	/* MAL Configuration */
+#define DCRN_MALDBR(base)	((base) + 0x3)	/* Debug Register */
+#define DCRN_MALESR(base)	((base) + 0x1)	/* Error Status */
+#define DCRN_MALIER(base)	((base) + 0x2)	/* Interrupt Enable */
+#define DCRN_MALTXCARR(base)	((base) + 0x5)	/* TX Channed Active Reset Register */
+#define DCRN_MALTXCASR(base)	((base) + 0x4)	/* TX Channel Active Set Register */
+#define DCRN_MALTXDEIR(base)	((base) + 0x7)	/* Tx Descriptor Error Interrupt */
+#define DCRN_MALTXEOBISR(base)	((base) + 0x6)	/* Tx End of Buffer Interrupt Status */
+#define DCRN_MALRXCARR(base)	((base) + 0x11)	/* RX Channed Active Reset Register */
+#define DCRN_MALRXCASR(base)	((base) + 0x10)	/* RX Channel Active Set Register */
+#define DCRN_MALRXDEIR(base)	((base) + 0x13)	/* Rx Descriptor Error Interrupt */
+#define DCRN_MALRXEOBISR(base)	((base) + 0x12)	/* Rx End of Buffer Interrupt Status */
+#define DCRN_MALRXCTP0R(base)	((base) + 0x40)	/* Channel Rx 0 Channel Table Pointer */
+#define DCRN_MALRXCTP1R(base)	((base) + 0x41)	/* Channel Rx 1 Channel Table Pointer */
+#define DCRN_MALTXCTP0R(base)	((base) + 0x20)	/* Channel Tx 0 Channel Table Pointer */
+#define DCRN_MALTXCTP1R(base)	((base) + 0x21)	/* Channel Tx 1 Channel Table Pointer */
+#define DCRN_MALTXCTP2R(base)	((base) + 0x22)	/* Channel Tx 2 Channel Table Pointer */
+#define DCRN_MALTXCTP3R(base)	((base) + 0x23)	/* Channel Tx 3 Channel Table Pointer */
+#define DCRN_MALRCBS0(base)	((base) + 0x60)	/* Channel Rx 0 Channel Buffer Size */
+#define DCRN_MALRCBS1(base)	((base) + 0x61)	/* Channel Rx 1 Channel Buffer Size */
+
+/* EMAC DCRN's */
+#define DCRN_MALRXCTP2R(base)	((base) + 0x42)	/* Channel Rx 2 Channel Table Pointer */
+#define DCRN_MALRXCTP3R(base)	((base) + 0x43)	/* Channel Rx 3 Channel Table Pointer */
+#define DCRN_MALTXCTP4R(base)	((base) + 0x24)	/* Channel Tx 4 Channel Table Pointer */
+#define DCRN_MALTXCTP5R(base)	((base) + 0x25)	/* Channel Tx 5 Channel Table Pointer */
+#define DCRN_MALTXCTP6R(base)	((base) + 0x26)	/* Channel Tx 6 Channel Table Pointer */
+#define DCRN_MALTXCTP7R(base)	((base) + 0x27)	/* Channel Tx 7 Channel Table Pointer */
+#define DCRN_MALRCBS2(base)	((base) + 0x62)	/* Channel Rx 2 Channel Buffer Size */
+#define DCRN_MALRCBS3(base)	((base) + 0x63)	/* Channel Rx 3 Channel Buffer Size */
+
+ /* DCRN_MALCR */
 #define MALCR_MMSR		0x80000000	/* MAL Software reset */
 #define MALCR_PLBP_1		0x00400000	/* MAL reqest priority: */
 #define MALCR_PLBP_2		0x00800000	/* lowsest is 00 */
@@ -294,28 +309,14 @@
 #define DCRN_POB0_BESR1	(DCRN_POB0_BASE + 0x4)
 #endif
 
-#ifdef DCRN_UIC0_BASE
-#define DCRN_UIC0_SR	(DCRN_UIC0_BASE + 0x0)
-#define DCRN_UIC0_ER	(DCRN_UIC0_BASE + 0x2)
-#define DCRN_UIC0_CR	(DCRN_UIC0_BASE + 0x3)
-#define DCRN_UIC0_PR	(DCRN_UIC0_BASE + 0x4)
-#define DCRN_UIC0_TR	(DCRN_UIC0_BASE + 0x5)
-#define DCRN_UIC0_MSR	(DCRN_UIC0_BASE + 0x6)
-#define DCRN_UIC0_VR	(DCRN_UIC0_BASE + 0x7)
-#define DCRN_UIC0_VCR	(DCRN_UIC0_BASE + 0x8)
-#endif
-
-#ifdef DCRN_UIC1_BASE
-#define DCRN_UIC1_SR	(DCRN_UIC1_BASE + 0x0)
-#define DCRN_UIC1_SRS	(DCRN_UIC1_BASE + 0x1)
-#define DCRN_UIC1_ER	(DCRN_UIC1_BASE + 0x2)
-#define DCRN_UIC1_CR	(DCRN_UIC1_BASE + 0x3)
-#define DCRN_UIC1_PR	(DCRN_UIC1_BASE + 0x4)
-#define DCRN_UIC1_TR	(DCRN_UIC1_BASE + 0x5)
-#define DCRN_UIC1_MSR	(DCRN_UIC1_BASE + 0x6)
-#define DCRN_UIC1_VR	(DCRN_UIC1_BASE + 0x7)
-#define DCRN_UIC1_VCR	(DCRN_UIC1_BASE + 0x8)
-#endif
+#define DCRN_UIC_SR(base)	(base + 0x0)
+#define DCRN_UIC_ER(base)	(base + 0x2)
+#define DCRN_UIC_CR(base)	(base + 0x3)
+#define DCRN_UIC_PR(base)	(base + 0x4)
+#define DCRN_UIC_TR(base)	(base + 0x5)
+#define DCRN_UIC_MSR(base)	(base + 0x6)
+#define DCRN_UIC_VR(base)	(base + 0x7)
+#define DCRN_UIC_VCR(base)	(base + 0x8)
 
 #ifdef DCRN_SDRAM0_BASE
 #define DCRN_SDRAM0_CFGADDR	(DCRN_SDRAM0_BASE + 0x0)	/* Memory Controller Address */
diff -Nru a/arch/ppc/platforms/ibm405gp.h b/arch/ppc/platforms/ibm405gp.h
--- a/arch/ppc/platforms/ibm405gp.h	Wed May 29 11:43:01 2002
+++ b/arch/ppc/platforms/ibm405gp.h	Wed May 29 11:43:01 2002
@@ -36,6 +36,13 @@
  *
  *	Version 1.1 02/01/17 - A. Kuster
  *	Moved offsets to ibm405.h
+ *
+ *	Version 1.2 05/01/02 - Armin
+ *	 added IIC_PORT_DFNS
+ *
+ *	Version 1.3 - armin
+ *	  removed iic & uart num defines
+ *	  and IIC_PORT_DFNS
  */
 
 #ifdef __KERNEL__
@@ -88,30 +95,36 @@
 #define UART1_INT	1
 
 #define PCIL0_BASE	0xEF400000
-#define UART0_IO_BASE	(u8 *) 0xEF600300
-#define UART1_IO_BASE	(u8 *) 0xEF600400
+#define UART0_IO_BASE	0xEF600300
+#define UART1_IO_BASE	0xEF600400
 #define IIC0_BASE	0xEF600500
 #define OPB0_BASE	0xEF600600
 #define GPIO0_BASE	0xEF600700
 #define EMAC0_BASE	0xEF600800
 
 #define EMAC_NUMS	1
-#define UART_NUMS	2
+#define IIC0_IRQ	2
+#define IIC1_IRQ	0
+
+#define IIC_OWN		0x55
+#define IIC_CLOCK	50
 #define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
 
 #define STD_UART_OP(num)					\
 	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
 		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
-		iomem_base: UART##num##_IO_BASE,		\
+		iomem_base: (u8 *)UART##num##_IO_BASE,		\
 		io_type: SERIAL_IO_MEM},
 
 #if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_DEBUG_IO_BASE	UART0_IO_BASE
 #define SERIAL_PORT_DFNS	\
 	STD_UART_OP(0)		\
 	STD_UART_OP(1)
 #endif
 
 #if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_DEBUG_IO_BASE	UART1_IO_BASE
 #define SERIAL_PORT_DFNS	\
 	STD_UART_OP(1)		\
 	STD_UART_OP(0)
@@ -123,6 +136,11 @@
 #define DCRN_CPMSR_BASE		0x0B8
 #define DCRN_CPMFR_BASE		0x0BA
 
+#define CHR0_U0EC	0x00000080	/* Select external clock for UART0 */
+#define CHR0_U1EC	0x00000040	/* Select external clock for UART1 */
+#define CHR0_UDIV	0x0000003E	/* UART internal clock divisor */
+#define CHR1_CETE	0x00800000	/* CPU external timer enable */
+
 #define DCRN_CHPSR_BASE         0x0B4
 #define  PSR_PLL_FWD_MASK        0xC0000000
 #define  PSR_PLL_FDBACK_MASK     0x30000000
@@ -169,6 +187,7 @@
 #define DCRN_POB0_BASE		0x0A0
 #define DCRN_SDRAM0_BASE	0x010
 #define DCRN_UIC0_BASE		0x0C0
+#define UIC0 DCRN_UIC0_BASE
 
 #include <platforms/ibm405.h>
 
diff -Nru a/arch/ppc/platforms/ibm_ocp.h b/arch/ppc/platforms/ibm_ocp.h
--- a/arch/ppc/platforms/ibm_ocp.h	Wed May 29 11:43:03 2002
+++ b/arch/ppc/platforms/ibm_ocp.h	Wed May 29 11:43:03 2002
@@ -1,5 +1,5 @@
 /*
- * ibm_ips.h
+ * ibm_ocp.h
  *
  *	This was dirived from the ppc4xx.h and all 405GP specific definition and board
  *	inclusions where moved here.
@@ -36,8 +36,8 @@
  */
 
 #ifdef __KERNEL__
-#ifndef __ASM_IBM_IPS_H__
-#define __ASM_IBM_IPS_H__
+#ifndef __ASM_IBM_OCP_H__
+#define __ASM_IBM_OCP_H__
 
 #ifndef __ASSEMBLY__
 #include <linux/types.h>
@@ -188,5 +188,5 @@
 } ide_t;
 
 #endif				/* __ASSEMBLY__ */
-#endif				/* __ASM_IBM_IPS_H__ */
+#endif				/* __ASM_IBM_OCP_H__ */
 #endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/lopec_pci.c b/arch/ppc/platforms/lopec_pci.c
--- a/arch/ppc/platforms/lopec_pci.c	Wed May 29 11:43:01 2002
+++ b/arch/ppc/platforms/lopec_pci.c	Wed May 29 11:43:01 2002
@@ -6,7 +6,7 @@
  * Author: Dan Cox
  *         danc@mvista.com (or, alternately, source@mvista.com)
  *
- * Copyright 2001 MontaVista Software Inc.
+ * Copyright 2001-2002 MontaVista Software Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -14,18 +14,11 @@
  * option) any later version.
  */
 
-#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/slab.h>
 
 #include <asm/machdep.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
 #include <asm/pci-bridge.h>
-#include <asm/open_pic.h>
 #include <asm/mpc10x.h>
 
 static inline int __init
diff -Nru a/arch/ppc/platforms/lopec_setup.c b/arch/ppc/platforms/lopec_setup.c
--- a/arch/ppc/platforms/lopec_setup.c	Wed May 29 11:43:01 2002
+++ b/arch/ppc/platforms/lopec_setup.c	Wed May 29 11:43:01 2002
@@ -15,34 +15,23 @@
  */
 
 #include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/time.h>
 #include <linux/types.h>
-#include <linux/major.h>
-#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/pci_ids.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
 #include <linux/ide.h>
-#include <linux/irq.h>
 #include <linux/seq_file.h>
+#include <linux/blk.h>
 #include <linux/console.h>
 
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-#include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/time.h>
-#include <asm/delay.h>
-#include <asm/irq.h>
 #include <asm/open_pic.h>
 #include <asm/i8259.h>
-#include <asm/pci-bridge.h>
 #include <asm/todc.h>
 #include <asm/bootinfo.h>
 #include <asm/mpc10x.h>
+#include <asm/hw_irq.h>
 
 extern void lopec_find_bridges(void);
 
@@ -230,7 +219,7 @@
 	i8259_init(0xfef00000);
 }
 
-void __init
+static int __init
 lopec_request_io(void)
 {
 	outb(0x00, 0x4d0);
@@ -242,9 +231,11 @@
 	request_region(0x80, 0x10, "dma page reg");
 	request_region(0xa0, 0x20, "pic2");
 	request_region(0xc0, 0x20, "dma2");
+	
+	return 0;
 }
 
-arch_initcall(lopec_request_io);
+device_initcall(lopec_request_io);
 
 static void __init
 lopec_map_io(void)
diff -Nru a/arch/ppc/platforms/mcpn765_setup.c b/arch/ppc/platforms/mcpn765_setup.c
--- a/arch/ppc/platforms/mcpn765_setup.c	Wed May 29 11:43:01 2002
+++ b/arch/ppc/platforms/mcpn765_setup.c	Wed May 29 11:43:01 2002
@@ -6,7 +6,7 @@
  * Author: Mark A. Greer
  *         mgreer@mvista.com
  *
- * Copyright 2001 MontaVista Software Inc.
+ * Copyright 2001-2002 MontaVista Software Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -31,7 +31,6 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/ide.h>
-#include <linux/irq.h>
 #include <linux/seq_file.h>
 
 #include <asm/system.h>
@@ -125,7 +124,7 @@
 	OpenPIC_NumInitSenses = sizeof(mcpn765_openpic_initsenses);
 
 	printk("Motorola MCG MCPN765 cPCI Non-System Board\n");
-	printk("MCPN765 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n");
+	printk("MCPN765 port (MontaVista Software, Inc. (source@mvista.com))\n");
 
 	if ( ppc_md.progress )
 		ppc_md.progress("mcpn765_setup_arch: exit", 0);
diff -Nru a/arch/ppc/platforms/pplus_setup.c b/arch/ppc/platforms/pplus_setup.c
--- a/arch/ppc/platforms/pplus_setup.c	Wed May 29 11:43:03 2002
+++ b/arch/ppc/platforms/pplus_setup.c	Wed May 29 11:43:03 2002
@@ -72,7 +72,6 @@
 #include <asm/todc.h>
 #include <asm/bootinfo.h>
 
-#undef CONFIG_SERIAL_TEXT_DEBUG
 #undef DUMP_DBATS
 
 TODC_ALLOC();
@@ -500,9 +499,7 @@
 
 #ifdef CONFIG_SERIAL_TEXT_DEBUG
 	ppc_md.progress = pplus_progress;
-#else /* !CONFIG_SERIAL_TEXT_DEBUG */
-	ppc_md.progress = NULL;
-#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#endif
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	ppc_ide_md.default_irq = pplus_ide_default_irq;
diff -Nru a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
--- a/arch/ppc/platforms/prep_setup.c	Wed May 29 11:43:03 2002
+++ b/arch/ppc/platforms/prep_setup.c	Wed May 29 11:43:03 2002
@@ -117,9 +117,6 @@
 {
 	extern char *Motherboard_map_name;
 	int cachew;
-#ifdef CONFIG_PREP_RESIDUAL
-	int i;
-#endif
 
 	seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
 
@@ -180,6 +177,8 @@
 no_l2:
 #ifdef CONFIG_PREP_RESIDUAL
 	if (res->ResidualLength != 0) {
+		int i;
+
 		/* print info about SIMMs */
 		seq_printf(m, "simms\t\t: ");
 		for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
@@ -812,8 +811,8 @@
 	io_block_mapping(0xf0000000, PREP_ISA_MEM_BASE, 0x08000000, _PAGE_IO);
 }
 
-static void __init
-prep_init2(void)
+static int __init
+prep_request_io(void)
 {
 #ifdef CONFIG_NVRAM
 	request_region(PREP_NVRAM_AS0, 0x8, "nvram");
@@ -822,8 +821,12 @@
 	request_region(0x40,0x20,"timer");
 	request_region(0x80,0x10,"dma page reg");
 	request_region(0xc0,0x20,"dma2");
+
+	return 0;
 }
 
+device_initcall(prep_request_io);
+
 void __init
 prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
 		unsigned long r6, unsigned long r7)
@@ -863,7 +866,6 @@
 	ppc_md.init_IRQ       = prep_init_IRQ;
 	/* this gets changed later on if we have an OpenPIC -- Cort */
 	ppc_md.get_irq        = i8259_irq;
-	ppc_md.init           = prep_init2;
 
 	ppc_md.restart        = prep_restart;
 	ppc_md.power_off      = prep_power_off;
diff -Nru a/arch/ppc/platforms/residual.c b/arch/ppc/platforms/residual.c
--- a/arch/ppc/platforms/residual.c	Wed May 29 11:43:02 2002
+++ b/arch/ppc/platforms/residual.c	Wed May 29 11:43:02 2002
@@ -876,3 +876,38 @@
 	};
 	return 0; /* not found */
 }
+
+#ifdef CONFIG_PROC_PREPRESIDUAL
+static int proc_prep_residual_read(char * buf, char ** start, off_t off,
+		int count, int *eof, void *data)
+{
+	int n;
+
+	n = res->ResidualLength - off;
+	if (n < 0) {
+		*eof = 1;
+		n = 0;
+	}
+	else {
+		if (n > count)
+			n = count;
+		else
+			*eof = 1;
+
+		memcpy(buf, (char *)res + off, n);
+		*start = buf;
+	}
+
+	return n;
+}
+
+void __init
+proc_prep_residual_init(void)
+{
+	if (res->ResidualLength)
+		create_proc_read_entry("residual", S_IRUGO, NULL,
+					proc_prep_residual_read, NULL);
+}
+
+__initcall(proc_prep_residual_init);
+#endif
diff -Nru a/arch/ppc/platforms/sandpoint_setup.c b/arch/ppc/platforms/sandpoint_setup.c
--- a/arch/ppc/platforms/sandpoint_setup.c	Wed May 29 11:43:03 2002
+++ b/arch/ppc/platforms/sandpoint_setup.c	Wed May 29 11:43:03 2002
@@ -6,7 +6,7 @@
  * Author: Mark A. Greer
  *         mgreer@mvista.com
  *
- * Copyright 2000, 2001 MontaVista Software Inc.
+ * Copyright 2000-2002 MontaVista Software Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -71,7 +71,6 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/ide.h>
-#include <linux/irq.h>
 #include <linux/seq_file.h>
 
 #include <asm/system.h>
@@ -180,7 +179,7 @@
 #endif
 
 	printk("Motorola SPS Sandpoint Test Platform\n");
-	printk("Sandpoint port (C) 2000, 2001 MontaVista Software, Inc. (source@mvista.com)\n");
+	printk("Sandpoint port (MontaVista Software, Inc. (source@mvista.com))\n");
 
 	/* The Sandpoint rom doesn't enable any caches.  Do that now.
 	 * The 7450 portion will also set up the L3s once I get enough
diff -Nru a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
--- a/arch/ppc64/kernel/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/ppc64/kernel/Makefile	Wed May 29 11:43:02 2002
@@ -1,19 +1,13 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
 EXTRA_CFLAGS = -mno-minimal-toc
 
 KHEAD := head.o
 
-all: $(KHEAD) kernel.o
-
-O_TARGET := kernel.o
+O_TARGET	:= kernel.o
+EXTRA_TARGETS	:= $(KHEAD)
 
 export-objs         := ppc_ksyms.o setup.o
 
diff -Nru a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c
--- a/arch/ppc64/kernel/signal.c	Wed May 29 11:43:01 2002
+++ b/arch/ppc64/kernel/signal.c	Wed May 29 11:43:01 2002
@@ -65,41 +65,6 @@
 extern long sys_wait4(pid_t pid, unsigned int *stat_addr,
 		     int options, /*unsigned long*/ struct rusage *ru);
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
-		int err;
-
-		/* If you change siginfo_t structure, please be sure
-		   this code is fixed accordingly.
-		   It should never copy any pad contained in the structure
-		   to avoid security leaks, but must copy the generic
-		   3 ints plus the relevant union member.  */
-		err = __put_user(from->si_signo, &to->si_signo);
-		err |= __put_user(from->si_errno, &to->si_errno);
-		err |= __put_user((short)from->si_code, &to->si_code);
-		/* First 32bits of unions are always present.  */
-		err |= __put_user(from->si_pid, &to->si_pid);
-		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
-		case __SI_CHLD >> 16:
-			err |= __put_user(from->si_utime, &to->si_utime);
-			err |= __put_user(from->si_stime, &to->si_stime);
-			err |= __put_user(from->si_status, &to->si_status);
-		default:
-			err |= __put_user(from->si_uid, &to->si_uid);
-			break;
-		/* case __SI_RT: This is not generated by the kernel as of now.  */
-		}
-		return err;
-	}
-}
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -544,12 +509,12 @@
  * OK, we're invoking a handler
  */
 static void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
-	      unsigned long *newspp, unsigned long frame)
+handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
+	struct pt_regs * regs, unsigned long *newspp, unsigned long frame)
 {
 	struct sigcontext_struct *sc;
         struct rt_sigframe *rt_sf;
+	struct k_sigaction *ka = &current->sig->action[sig-1];
 
 	if (regs->trap == 0x0C00 /* System Call! */
 	    && ((int)regs->result == -ERESTARTNOHAND ||
@@ -633,6 +598,7 @@
 	siginfo_t info;
 	struct k_sigaction *ka;
 	unsigned long frame, newsp;
+	int signr;
 
 	/*
 	 * If the current thread is 32 bit - invoke the
@@ -646,103 +612,9 @@
 
 	newsp = frame = 0;
 
-	for (;;) {
-		unsigned long signr;
-
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - (pre) dequeueing signal - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - (aft) dequeueing signal - signal=%lx - pid=%ld current=%lx comm=%s \n", signr, current->pid, current, current->comm);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->parent->pid;
-				info.si_uid = current->parent->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		ka = &current->sig->action[signr-1];
-
-  
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - ka=%p, action handler=%lx \n", ka, ka->sa.sa_handler);
-
-		if (ka->sa.sa_handler == SIG_IGN) {
-                        PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_IGN logic \n");
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-                        PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_DFL logic \n");
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP:
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				if (!(current->parent->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
 		if ( (ka->sa.sa_flags & SA_ONSTACK)
 		     && (! on_sig_stack(regs->gpr[1])))
 			newsp = (current->sas_ss_sp + current->sas_ss_size);
@@ -753,9 +625,8 @@
 		/* Whee!  Actually deliver the signal.  */
   
                 PPCDBG(PPCDBG_SIGNAL, "do_signal - GOING TO RUN SIGNAL HANDLER - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-		handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
+		handle_signal(signr, &info, oldset, regs, &newsp, frame);
                 PPCDBG(PPCDBG_SIGNAL, "do_signal - after running signal handler - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-                break;
 	}
 
 	if (regs->trap == 0x0C00 /* System Call! */ &&
diff -Nru a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c
--- a/arch/ppc64/kernel/signal32.c	Wed May 29 11:43:03 2002
+++ b/arch/ppc64/kernel/signal32.c	Wed May 29 11:43:03 2002
@@ -1187,13 +1187,13 @@
  * OK, we're invoking a handler
  */
 static void
-handle_signal32(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
-	      unsigned int *newspp, unsigned int frame)
+handle_signal32(unsigned long sig, siginfo_t *info, sigset_t *oldset,
+	struct pt_regs * regs, unsigned int *newspp, unsigned int frame)
 {
 	struct sigcontext32_struct *sc;
 	struct rt_sigframe_32 *rt_stack_frame;
 	siginfo_t32 siginfo32bit;
+	struct k_sigaction *ka = &current->sig->action[sig-1];
 
 	if (regs->trap == 0x0C00 /* System Call! */
 	    && ((int)regs->result == -ERESTARTNOHAND ||
@@ -1337,114 +1337,23 @@
 	siginfo_t info;
 	struct k_sigaction *ka;
 	unsigned int frame, newsp;
+	int signr;
 
 	if (!oldset)
 		oldset = &current->blocked;
 
 	newsp = frame = 0;
 
-	for (;;) {
-		unsigned long signr;
-		
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-		ifppcdebug(PPCDBG_SYS32) {
-			if (signr)
-				udbg_printf("do_signal32 - processing signal=%2lx - pid=%ld, comm=%s \n", signr, current->pid, current->comm);
-		}
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->parent->pid;
-				info.si_uid = current->parent->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		ka = &current->sig->action[signr-1];
 
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP:
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				if (!(current->parent->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
 		PPCDBG(PPCDBG_SIGNAL, " do signal :sigaction flags = %lx \n" ,ka->sa.sa_flags);
 		PPCDBG(PPCDBG_SIGNAL, " do signal :on sig stack  = %lx \n" ,on_sig_stack(regs->gpr[1]));
 		PPCDBG(PPCDBG_SIGNAL, " do signal :reg1  = %lx \n" ,regs->gpr[1]);
 		PPCDBG(PPCDBG_SIGNAL, " do signal :alt stack  = %lx \n" ,current->sas_ss_sp);
 		PPCDBG(PPCDBG_SIGNAL, " do signal :alt stack size  = %lx \n" ,current->sas_ss_size);
 
-
-
 		if ( (ka->sa.sa_flags & SA_ONSTACK)
 		     && (! on_sig_stack(regs->gpr[1])))
 		{
@@ -1454,8 +1363,7 @@
 		newsp = frame = newsp - sizeof(struct sigregs32);
 
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal32(signr, ka, &info, oldset, regs, &newsp, frame);
-		break;
+		handle_signal32(signr, &info, oldset, regs, &newsp, frame);
 	}
 
 	if (regs->trap == 0x0C00 /* System Call! */ &&
@@ -1468,9 +1376,8 @@
 	}
 
 	if (newsp == frame)
-	{
 		return 0;		/* no signals delivered */
-	}
+
 	// Invoke correct stack setup routine 
 	if (ka->sa.sa_flags & SA_SIGINFO) 
 		setup_rt_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
diff -Nru a/arch/s390/Makefile b/arch/s390/Makefile
--- a/arch/s390/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/s390/Makefile	Wed May 29 11:43:02 2002
@@ -32,7 +32,7 @@
 SUBDIRS := $(SUBDIRS) arch/s390/mm arch/s390/kernel arch/s390/lib \
            drivers/s390 arch/s390/math-emu
 CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES)
-DRIVERS := $(DRIVERS) drivers/s390/io.o
+DRIVERS := $(DRIVERS) drivers/s390/built-in.o
 LIBS := $(TOPDIR)/arch/s390/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390/lib/lib.a
 
 ifeq ($(CONFIG_MATHEMU),y)
@@ -43,15 +43,6 @@
 
 listing: vmlinux
 	@$(MAKEBOOT) listing
-
-arch/s390/kernel: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/s390/kernel
-
-arch/s390/mm: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/s390/mm
-
-drivers/s390: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=drivers/s390
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
diff -Nru a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
--- a/arch/s390/kernel/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/s390/kernel/Makefile	Wed May 29 11:43:03 2002
@@ -1,17 +1,9 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-all: kernel.o head.o init_task.o
-
-O_TARGET := kernel.o
 
-EXTRA_AFLAGS := -traditional
+O_TARGET	:= kernel.o
+EXTRA_TARGETS	:= head.o init_task.o
 
 export-objs	:= debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o
 obj-y	:= entry.o bitmap.o traps.o time.o process.o irq.o \
@@ -25,6 +17,8 @@
 # Kernel debugging
 #
 obj-$(CONFIG_REMOTE_DEBUG)	+= gdb-stub.o #gdb-low.o 
+
+EXTRA_AFLAGS := -traditional
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
--- a/arch/s390/kernel/signal.c	Wed May 29 11:43:02 2002
+++ b/arch/s390/kernel/signal.c	Wed May 29 11:43:02 2002
@@ -49,41 +49,6 @@
 
 asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
-		int err;
-
-		/* If you change siginfo_t structure, please be sure
-		   this code is fixed accordingly.
-		   It should never copy any pad contained in the structure
-		   to avoid security leaks, but must copy the generic
-		   3 ints plus the relevant union member.  */
-		err = __put_user(from->si_signo, &to->si_signo);
-		err |= __put_user(from->si_errno, &to->si_errno);
-		err |= __put_user((short)from->si_code, &to->si_code);
-		/* First 32bits of unions are always present.  */
-		err |= __put_user(from->si_pid, &to->si_pid);
-		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
-		case __SI_CHLD >> 16:
-			err |= __put_user(from->si_utime, &to->si_utime);
-			err |= __put_user(from->si_stime, &to->si_stime);
-			err |= __put_user(from->si_status, &to->si_status);
-		default:
-			err |= __put_user(from->si_uid, &to->si_uid);
-			break;
-		/* case __SI_RT: This is not generated by the kernel as of now.  */
-		}
-		return err;
-	}
-}
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -409,9 +374,11 @@
  */	
 
 static void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
+	struct pt_regs * regs)
 {
+	struct k_sigaction *ka = &current->sig->action[sig-1];
+
 	/* Are we from a system call? */
 	if (regs->trap == __LC_SVC_OLD_PSW) {
 		/* If so, check system call restarting.. */
@@ -462,7 +429,7 @@
 int do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
 	siginfo_t info;
-	struct k_sigaction *ka;
+	int signr;
 
 	/*
 	 * We want the common case to go fast, which
@@ -476,100 +443,10 @@
 	if (!oldset)
 		oldset = &current->blocked;
 
-	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			set_current_state(TASK_STOPPED);
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sig->action[signr-1];
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP: {
-				struct signal_struct *sig;
-				set_current_state(TASK_STOPPED);
-				current->exit_code = signr;
-				sig = current->p_pptr->sig;
-				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-			}
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-                                if (do_coredump(signr, regs))
-                                        exit_code |= 0x80;
-                                /* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, ka, &info, oldset, regs);
+		handle_signal(signr, &info, oldset, regs);
 		return 1;
 	}
 
diff -Nru a/arch/s390x/Makefile b/arch/s390x/Makefile
--- a/arch/s390x/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/s390x/Makefile	Wed May 29 11:43:03 2002
@@ -1,5 +1,5 @@
 
-# s390/Makefile
+# s390x/Makefile
 #
 # This file is included by the global makefile so that you can add your own
 # architecture-specific flags and dependencies. Remember to do have actions
@@ -33,22 +33,13 @@
 SUBDIRS := $(SUBDIRS) arch/s390x/mm arch/s390x/kernel arch/s390x/lib \
            drivers/s390
 CORE_FILES := arch/s390x/mm/mm.o arch/s390x/kernel/kernel.o $(CORE_FILES)
-DRIVERS := $(DRIVERS) drivers/s390/io.o
+DRIVERS := $(DRIVERS) drivers/s390/built-in.o
 LIBS := $(TOPDIR)/arch/s390x/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390x/lib/lib.a
 
 all: image listing
 
 listing: vmlinux
 	@$(MAKEBOOT) listing
-
-arch/s390x/kernel: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/s390x/kernel
-
-arch/s390x/mm: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/s390x/mm
-
-drivers/s390: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=drivers/s390
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
diff -Nru a/arch/s390x/kernel/Makefile b/arch/s390x/kernel/Makefile
--- a/arch/s390x/kernel/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/s390x/kernel/Makefile	Wed May 29 11:43:02 2002
@@ -1,17 +1,9 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-all: kernel.o head.o init_task.o
 
 O_TARGET	:= kernel.o
-
-EXTRA_AFLAGS := -traditional
+EXTRA_TARGETS	:= head.o init_task.o
 
 export-objs	:= debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o \
 		   exec32.o
@@ -31,9 +23,12 @@
 obj-$(CONFIG_S390_SUPPORT)	+= linux32.o signal32.o ioctl32.o wrapper32.o exec32.o
 obj-$(CONFIG_BINFMT_ELF32)	+= binfmt_elf32.o
 
+EXTRA_AFLAGS := -traditional
+
+include $(TOPDIR)/Rules.make
+
 #
 # This is just to get the dependencies...
 #
 binfmt_elf32.o:	$(TOPDIR)/fs/binfmt_elf.c
 
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/s390x/kernel/linux32.c b/arch/s390x/kernel/linux32.c
--- a/arch/s390x/kernel/linux32.c	Wed May 29 11:43:02 2002
+++ b/arch/s390x/kernel/linux32.c	Wed May 29 11:43:02 2002
@@ -897,97 +897,6 @@
 	return sys32_fcntl(fd, cmd, arg);
 }
 
-extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
-
-#ifdef CONFIG_QIFACE_COMPAT
-#ifdef CONFIG_QIFACE_V1
-struct user_dqblk32 {
-	__u32 dqb_bhardlimit;
-	__u32 dqb_bsoftlimit;
-	__u32 dqb_curblocks;
-	__u32 dqb_ihardlimit;
-	__u32 dqb_isoftlimit;
-	__u32 dqb_curinodes;
-	__kernel_time_t32 dqb_btime;
-	__kernel_time_t32 dqb_itime;
-};
-typedef struct v1c_mem_dqblk comp_dqblk_t;
-
-#define Q_COMP_GETQUOTA Q_V1_GETQUOTA
-#define Q_COMP_SETQUOTA Q_V1_SETQUOTA
-#define Q_COMP_SETQLIM Q_V1_SETQLIM
-#define Q_COMP_SETUSE Q_V1_SETUSE
-#else
-struct user_dqblk32 {
-	__u32 dqb_ihardlimit;
-	__u32 dqb_isoftlimit;
-	__u32 dqb_curinodes;
-	__u32 dqb_bhardlimit;
-	__u32 dqb_bsoftlimit;
-	__u64 dqb_curspace;
-	__kernel_time_t32 dqb_btime;
-	__kernel_time_t32 dqb_itime;
-};
-typedef struct v2c_mem_dqblk comp_dqblk_t;
-
-#define Q_COMP_GETQUOTA Q_V2_GETQUOTA
-#define Q_COMP_SETQUOTA Q_V2_SETQUOTA
-#define Q_COMP_SETQLIM Q_V2_SETQLIM
-#define Q_COMP_SETUSE Q_V2_SETUSE
-#endif
-
-asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
-{
-	int cmds = cmd >> SUBCMDSHIFT;
-	int err;
-	comp_dqblk_t d;
-	mm_segment_t old_fs;
-	char *spec;
-	
-	switch (cmds) {
-		case Q_COMP_GETQUOTA:
-			break;
-		case Q_COMP_SETQUOTA:
-		case Q_COMP_SETUSE:
-		case Q_COMP_SETQLIM:
-			if (copy_from_user(&d, (struct user_dqblk32 *)addr,
-					    sizeof (struct user_dqblk32)))
-				return -EFAULT;
-			d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime;
-			d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime;
-			break;
-	default:
-		return sys_quotactl(cmd, special, id, (__kernel_caddr_t)addr);
-	}
-	spec = getname (special);
-	err = PTR_ERR(spec);
-	if (IS_ERR(spec)) return err;
-	old_fs = get_fs();
-	set_fs (KERNEL_DS);
-	err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d);
-	set_fs (old_fs);
-	putname (spec);
-	if (err)
-		return err;
-	if (cmds == Q_COMP_GETQUOTA) {
-		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-		((struct user_dqblk32 *)&d)->dqb_itime = i;
-		((struct user_dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user ((struct user_dqblk32 *)addr, &d,
-				  sizeof (struct user_dqblk32)))
-			return -EFAULT;
-	}
-	return 0;
-}
-
-#else
-/* No conversion needed for new interface */
-asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
-{
-	return sys_quotactl(cmd, special, id, addr);
-}
-#endif
-
 static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
 {
 	int err;
diff -Nru a/arch/s390x/kernel/signal.c b/arch/s390x/kernel/signal.c
--- a/arch/s390x/kernel/signal.c	Wed May 29 11:43:01 2002
+++ b/arch/s390x/kernel/signal.c	Wed May 29 11:43:01 2002
@@ -49,41 +49,6 @@
 
 asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
-		int err;
-
-		/* If you change siginfo_t structure, please be sure
-		   this code is fixed accordingly.
-		   It should never copy any pad contained in the structure
-		   to avoid security leaks, but must copy the generic
-		   3 ints plus the relevant union member.  */
-		err = __put_user(from->si_signo, &to->si_signo);
-		err |= __put_user(from->si_errno, &to->si_errno);
-		err |= __put_user((short)from->si_code, &to->si_code);
-		/* First 32bits of unions are always present.  */
-		err |= __put_user(from->si_pid, &to->si_pid);
-		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
-		case __SI_CHLD >> 16:
-			err |= __put_user(from->si_utime, &to->si_utime);
-			err |= __put_user(from->si_stime, &to->si_stime);
-			err |= __put_user(from->si_status, &to->si_status);
-		default:
-			err |= __put_user(from->si_uid, &to->si_uid);
-			break;
-		/* case __SI_RT: This is not generated by the kernel as of now.  */
-		}
-		return err;
-	}
-}
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -409,9 +374,11 @@
  */	
 
 static void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
+	struct pt_regs * regs)
 {
+	struct k_sigaction *ka = &current->sig->action[sig-1];
+
 	/* Are we from a system call? */
 	if (regs->trap == __LC_SVC_OLD_PSW) {
 		/* If so, check system call restarting.. */
@@ -462,7 +429,6 @@
 int do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
 	siginfo_t info;
-	struct k_sigaction *ka;
 
 	/*
 	 * We want the common case to go fast, which
@@ -482,100 +448,10 @@
         }
 #endif 
 
-	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			set_current_state(TASK_STOPPED);
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sig->action[signr-1];
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP: {
-				struct signal_struct *sig;
-				set_current_state(TASK_STOPPED);
-				current->exit_code = signr;
-				sig = current->p_pptr->sig;
-				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-			}
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-                                if (do_coredump(signr, regs))
-                                        exit_code |= 0x80;
-                                /* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, ka, &info, oldset, regs);
+		handle_signal(signr, &info, oldset, regs);
 		return 1;
 	}
 
diff -Nru a/arch/s390x/kernel/signal32.c b/arch/s390x/kernel/signal32.c
--- a/arch/s390x/kernel/signal32.c	Wed May 29 11:43:03 2002
+++ b/arch/s390x/kernel/signal32.c	Wed May 29 11:43:03 2002
@@ -548,9 +548,11 @@
  */	
 
 static void
-handle_signal32(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+handle_signal32(unsigned long sig, siginfo_t *info, sigset_t *oldset,
+	struct pt_regs * regs)
 {
+	struct k_sigaction *ka = &current->sig->action[sig-1];
+
 	/* Are we from a system call? */
 	if (regs->trap == __LC_SVC_OLD_PSW) {
 		/* If so, check system call restarting.. */
@@ -601,7 +603,7 @@
 int do_signal32(struct pt_regs *regs, sigset_t *oldset)
 {
 	siginfo_t info;
-	struct k_sigaction *ka;
+	int signr;
 
 	/*
 	 * We want the common case to go fast, which
@@ -615,97 +617,10 @@
 	if (!oldset)
 		oldset = &current->blocked;
 
-	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			set_current_state(TASK_STOPPED);
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sig->action[signr-1];
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP:
-				set_current_state(TASK_STOPPED);
-				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-                                if (do_coredump(signr, regs))
-                                        exit_code |= 0x80;
-                                /* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal32(signr, ka, &info, oldset, regs);
+		handle_signal32(signr, &info, oldset, regs);
 		return 1;
 	}
 
diff -Nru a/arch/s390x/kernel/wrapper32.S b/arch/s390x/kernel/wrapper32.S
--- a/arch/s390x/kernel/wrapper32.S	Wed May 29 11:43:02 2002
+++ b/arch/s390x/kernel/wrapper32.S	Wed May 29 11:43:02 2002
@@ -586,7 +586,7 @@
 	llgtr	%r3,%r3			# const char *
 	lgfr	%r4,%r4			# int
 	llgtr	%r5,%r5			# caddr_t
-	jg	sys32_quotactl		# branch to system call
+	jg	sys_quotactl		# branch to system call
 
 	.globl  sys32_getpgid_wrapper 
 sys32_getpgid_wrapper:
diff -Nru a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
--- a/arch/sh/kernel/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/sh/kernel/Makefile	Wed May 29 11:43:03 2002
@@ -1,16 +1,9 @@
 #
 # Makefile for the Linux/SuperH kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
 
-all: kernel.o head.o init_task.o
-
-clean:
-
-O_TARGET := kernel.o
+O_TARGET	:= kernel.o
+EXTRA_TARGETS	:= head.o init_task.o
 
 export-objs	:= io.o io_generic.o io_hd64461.o setup_hd64461.o sh_ksyms.o
 
diff -Nru a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
--- a/arch/sh/kernel/signal.c	Wed May 29 11:43:03 2002
+++ b/arch/sh/kernel/signal.c	Wed May 29 11:43:03 2002
@@ -34,41 +34,6 @@
 
 asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
-		int err;
-
-		/* If you change siginfo_t structure, please be sure
-		   this code is fixed accordingly.
-		   It should never copy any pad contained in the structure
-		   to avoid security leaks, but must copy the generic
-		   3 ints plus the relevant union member.  */
-		err = __put_user(from->si_signo, &to->si_signo);
-		err |= __put_user(from->si_errno, &to->si_errno);
-		err |= __put_user((short)from->si_code, &to->si_code);
-		/* First 32bits of unions are always present.  */
-		err |= __put_user(from->si_pid, &to->si_pid);
-		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
-		case __SI_CHLD >> 16:
-			err |= __put_user(from->si_utime, &to->si_utime);
-			err |= __put_user(from->si_stime, &to->si_stime);
-			err |= __put_user(from->si_status, &to->si_status);
-		default:
-			err |= __put_user(from->si_uid, &to->si_uid);
-			break;
-		/* case __SI_RT: This is not generated by the kernel as of now.  */
-		}
-		return err;
-	}
-}
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -522,9 +487,11 @@
  */	
 
 static void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
+	struct pt_regs * regs)
 {
+	struct k_sigaction *ka = &current->sig->action[sig-1];
+
 	/* Are we from a system call? */
 	if (regs->syscall_nr >= 0) {
 		/* If so, check system call restarting.. */
@@ -575,7 +542,7 @@
 int do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
 	siginfo_t info;
-	struct k_sigaction *ka;
+	int signr;
 
 	/*
 	 * We want the common case to go fast, which
@@ -589,97 +556,10 @@
 	if (!oldset)
 		oldset = &current->blocked;
 
-	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sig->action[signr-1];
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP:
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				continue;
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, ka, &info, oldset, regs);
+		handle_signal(signr, &info, oldset, regs);
 		return 1;
 	}
 
diff -Nru a/arch/sh/stboards/Makefile b/arch/sh/stboards/Makefile
--- a/arch/sh/stboards/Makefile	Wed May 29 11:43:01 2002
+++ b/arch/sh/stboards/Makefile	Wed May 29 11:43:01 2002
@@ -1,15 +1,9 @@
 #
 # Makefile for STMicroelectronics board specific parts of the kernel
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
 
-all: stboards.o
 O_TARGET := stboards.o
-obj-y := irq.o setup.o mach.o led.o
 
-clean:
+obj-y := irq.o setup.o mach.o led.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
--- a/arch/sparc/boot/Makefile	Wed May 29 11:43:03 2002
+++ b/arch/sparc/boot/Makefile	Wed May 29 11:43:03 2002
@@ -30,7 +30,7 @@
 # build would work, but this fails because $(HEAD) cannot work
 # properly as it will cause head.o to be built with the implicit
 # rules not the ones in kernel/Makefile.  Someone please fix. --DaveM
-vmlinux.o: dummy
+vmlinux.o: FORCE
 	$(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) \
 		--start-group \
 		$(patsubst %,$(TOPDIR)/%,$(BTLIBS)) \
diff -Nru a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
--- a/arch/sparc/kernel/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/sparc/kernel/Makefile	Wed May 29 11:43:02 2002
@@ -1,17 +1,11 @@
 # $Id: Makefile,v 1.62 2000/12/15 00:41:17 davem Exp $
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
 SH = $(CONFIG_SHELL)
 
-all: kernel.o head.o init_task.o
-
-O_TARGET := kernel.o
+O_TARGET	:= kernel.o
+EXTRA_TARGETS	:= head.o init_task.o
 
 EXTRA_AFLAGS := -ansi
 
@@ -34,10 +28,9 @@
 obj-y += sys_sunos.o sunos_ioctl.o
 endif
 
-head.o: head.S
-	$(CC) $(AFLAGS) -ansi -c $*.S -o $*.o
+include $(TOPDIR)/Rules.make
 
-check_asm: dummy
+check_asm: FORCE
 	@if [ ! -r $(HPATH)/asm/asm_offsets.h ] ; then \
 	  touch $(HPATH)/asm/asm_offsets.h ; \
 	fi
@@ -126,6 +119,3 @@
 	else \
 	  mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; \
 	fi
-
-
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
--- a/arch/sparc64/kernel/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/sparc64/kernel/Makefile	Wed May 29 11:43:02 2002
@@ -6,9 +6,8 @@
 
 EXTRA_AFLAGS := -ansi
 
-all: kernel.o head.o init_task.o
-
-O_TARGET := kernel.o
+O_TARGET	:= kernel.o
+EXTRA_TARGETS	:= head.o init_task.o
 
 export-objs	:= sparc64_ksyms.o
 obj-y		:= process.o setup.o cpu.o idprom.o \
@@ -32,10 +31,6 @@
   endif
 endif
 
-head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \
-	etrap.S rtrap.S winfixup.S entry.S
-	$(CC) $(AFLAGS) -ansi -c $*.S -o $*.o
-
 #
 # This is just to get the dependencies...
 #
@@ -48,3 +43,6 @@
 endif
 
 include $(TOPDIR)/Rules.make
+
+head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \
+	etrap.S rtrap.S winfixup.S entry.S
diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	Wed May 29 11:43:03 2002
+++ b/arch/sparc64/kernel/sys_sparc32.c	Wed May 29 11:43:03 2002
@@ -889,97 +889,6 @@
 	return sys32_fcntl(fd, cmd, arg);
 }
 
-extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
-
-#ifdef CONFIG_QIFACE_COMPAT
-#ifdef CONFIG_QIFACE_V1
-struct user_dqblk32 {
-	__u32 dqb_bhardlimit;
-	__u32 dqb_bsoftlimit;
-	__u32 dqb_curblocks;
-	__u32 dqb_ihardlimit;
-	__u32 dqb_isoftlimit;
-	__u32 dqb_curinodes;
-	__kernel_time_t32 dqb_btime;
-	__kernel_time_t32 dqb_itime;
-};
-typedef struct v1c_mem_dqblk comp_dqblk_t;
-
-#define Q_COMP_GETQUOTA Q_V1_GETQUOTA
-#define Q_COMP_SETQUOTA Q_V1_SETQUOTA
-#define Q_COMP_SETQLIM Q_V1_SETQLIM
-#define Q_COMP_SETUSE Q_V1_SETUSE
-#else
-struct user_dqblk32 {
-	__u32 dqb_ihardlimit;
-	__u32 dqb_isoftlimit;
-	__u32 dqb_curinodes;
-	__u32 dqb_bhardlimit;
-	__u32 dqb_bsoftlimit;
-	__u64 dqb_curspace;
-	__kernel_time_t32 dqb_btime;
-	__kernel_time_t32 dqb_itime;
-};
-typedef struct v2c_mem_dqblk comp_dqblk_t;
-
-#define Q_COMP_GETQUOTA Q_V2_GETQUOTA
-#define Q_COMP_SETQUOTA Q_V2_SETQUOTA
-#define Q_COMP_SETQLIM Q_V2_SETQLIM
-#define Q_COMP_SETUSE Q_V2_SETUSE
-#endif
-
-asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
-{
-	int cmds = cmd >> SUBCMDSHIFT;
-	int err;
-	comp_dqblk_t d;
-	mm_segment_t old_fs;
-	char *spec;
-	
-	switch (cmds) {
-		case Q_COMP_GETQUOTA:
-			break;
-		case Q_COMP_SETQUOTA:
-		case Q_COMP_SETUSE:
-		case Q_COMP_SETQLIM:
-			if (copy_from_user(&d, (struct user_dqblk32 *)addr,
-					    sizeof (struct user_dqblk32)))
-				return -EFAULT;
-			d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime;
-			d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime;
-			break;
-	default:
-		return sys_quotactl(cmd, special, id, (__kernel_caddr_t)addr);
-	}
-	spec = getname (special);
-	err = PTR_ERR(spec);
-	if (IS_ERR(spec)) return err;
-	old_fs = get_fs();
-	set_fs (KERNEL_DS);
-	err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d);
-	set_fs (old_fs);
-	putname (spec);
-	if (err)
-		return err;
-	if (cmds == Q_COMP_GETQUOTA) {
-		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-		((struct user_dqblk32 *)&d)->dqb_itime = i;
-		((struct user_dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user ((struct user_dqblk32 *)addr, &d,
-				  sizeof (struct user_dqblk32)))
-			return -EFAULT;
-	}
-	return 0;
-}
-
-#else
-/* No conversion needed for new interface */
-asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
-{
-	return sys_quotactl(cmd, special, id, addr);
-}
-#endif
-
 static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
 {
 	int err;
diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
--- a/arch/sparc64/kernel/systbls.S	Wed May 29 11:43:02 2002
+++ b/arch/sparc64/kernel/systbls.S	Wed May 29 11:43:02 2002
@@ -52,7 +52,7 @@
 /*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 	.word sys32_fcntl64, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
 /*160*/	.word sys32_sched_setaffinity, sys32_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
-	.word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_setxattr
+	.word sys_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_setxattr
 /*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys32_getdents
 	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys32_sigpending, sys32_query_module
diff -Nru a/arch/x86_64/Makefile b/arch/x86_64/Makefile
--- a/arch/x86_64/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/x86_64/Makefile	Wed May 29 11:43:02 2002
@@ -70,20 +70,9 @@
 
 CORE_FILES += $(core-y)
 
-arch/x86_64/tools: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/x86_64/tools 
-
-arch/x86_64/kernel: dummy 
-	$(MAKE) linuxsubdirs SUBDIRS=arch/x86_64/kernel
-
-arch/x86_64/mm: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/x86_64/mm
-
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
 vmlinux: arch/x86_64/vmlinux.lds
-
-FORCE: ;
 
 .PHONY: zImage bzImage compressed zlilo bzlilo zdisk bzdisk install \
 		clean archclean archmrproper archdep checkoffset
diff -Nru a/arch/x86_64/ia32/Makefile b/arch/x86_64/ia32/Makefile
--- a/arch/x86_64/ia32/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/x86_64/ia32/Makefile	Wed May 29 11:43:02 2002
@@ -2,14 +2,11 @@
 # Makefile for the ia32 kernel emulation subsystem.
 #
 
-export-objs := ia32_ioctl.o	
+O_TARGET := ia32.o
 
-all: ia32.o
+export-objs := ia32_ioctl.o	
 
-O_TARGET := ia32.o
 obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o \
 	ia32_binfmt.o fpu32.o socket32.o ptrace32.o
-
-clean::
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
--- a/arch/x86_64/kernel/Makefile	Wed May 29 11:43:02 2002
+++ b/arch/x86_64/kernel/Makefile	Wed May 29 11:43:02 2002
@@ -2,12 +2,8 @@
 # Makefile for the linux kernel.
 #
 
-EXTRA_AFLAGS := -traditional
-
-all: kernel.o head.o head64.o init_task.o
-
-O_TARGET := kernel.o
-
+O_TARGET	:= kernel.o
+EXTRA_TARGETS 	:= head.o head64.o init_task.o
 
 export-objs     := mtrr.o msr.o cpuid.o x8664_ksyms.o
 
@@ -30,6 +26,8 @@
 #obj-$(CONFIG_ACPI)             += acpi.o
 #obj-$(CONFIG_ACPI_SLEEP)       += acpi_wakeup.o
 obj-$(CONFIG_EARLY_PRINTK)    += early_printk.o
+
+EXTRA_AFLAGS := -traditional
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
--- a/arch/x86_64/kernel/signal.c	Wed May 29 11:43:02 2002
+++ b/arch/x86_64/kernel/signal.c	Wed May 29 11:43:02 2002
@@ -39,41 +39,6 @@
 void ia32_setup_frame(int sig, struct k_sigaction *ka,
             sigset_t *set, struct pt_regs * regs); 
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-{
-	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
-		int err;
-
-		/* If you change siginfo_t structure, please be sure
-		   this code is fixed accordingly.
-		   It should never copy any pad contained in the structure
-		   to avoid security leaks, but must copy the generic
-		   3 ints plus the relevant union member.  */
-		err = __put_user(from->si_signo, &to->si_signo);
-		err |= __put_user(from->si_errno, &to->si_errno);
-		err |= __put_user((short)from->si_code, &to->si_code);
-		/* First 32bits of unions are always present.  */
-		err |= __put_user(from->si_pid, &to->si_pid);
-		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
-		case __SI_CHLD >> 16:
-			err |= __put_user(from->si_utime, &to->si_utime);
-			err |= __put_user(from->si_stime, &to->si_stime);
-			err |= __put_user(from->si_status, &to->si_status);
-		default:
-			err |= __put_user(from->si_uid, &to->si_uid);
-			break;
-		/* case __SI_RT: This is not generated by the kernel as of now.  */
-		}
-		return err;
-	}
-}
-
 asmlinkage long
 sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs regs)
 {
@@ -380,9 +345,11 @@
  */	
 
 static void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
+	struct pt_regs * regs)
 {
+	struct k_sigaction *ka = &current->sig->action[sig-1];
+
 #if DEBUG_SIG
 	printk("handle_signal pid:%d sig:%lu rip:%lx rsp:%lx regs=%p\n", current->pid, sig, 
 		regs->rip, regs->rsp, regs);
@@ -438,7 +405,7 @@
 int do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
 	siginfo_t info;
-	struct k_sigaction *ka;
+	int signr;
 
 	/*
 	 * We want the common case to go fast, which
@@ -453,101 +420,8 @@
 	if (!oldset)
 		oldset = &current->blocked;
 
-	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-
-		if (!signr) { 
-			break;
-		}
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current, SIGCHLD);
-			schedule();
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->parent->pid;
-				info.si_uid = current->parent->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sig->action[signr-1];
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)			      
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP: {
-				struct signal_struct *sig;
-				preempt_disable(); 
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				sig = current->parent->sig;
-				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				preempt_enable();
-				continue;
-			}
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-		}
-
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
 		/* Reenable any watchpoints before delivering the
 		 * signal to user space. The processor register will
 		 * have been cleared if the watchpoint triggered
@@ -556,7 +430,7 @@
 		__asm__("movq %0,%%db7"	: : "r" (current->thread.debugreg[7]));
 
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, ka, &info, oldset, regs);
+		handle_signal(signr, &info, oldset, regs);
 		return 1;
 	}
 
diff -Nru a/arch/x86_64/tools/Makefile b/arch/x86_64/tools/Makefile
--- a/arch/x86_64/tools/Makefile	Wed May 29 11:43:01 2002
+++ b/arch/x86_64/tools/Makefile	Wed May 29 11:43:01 2002
@@ -14,11 +14,9 @@
 
 .PHONY : offset.h all modules modules_install
 
-offset.h: offset.sed offset.c FORCE_RECOMPILE
+offset.h: offset.sed offset.c FORCE
 	$(CC) $(CFLAGS) -S -o offset.tmp offset.c
 	sed -n -f offset.sed < offset.tmp > offset.h   
-
-FORCE_RECOMPILE:
 
 clean:
 	rm -f offset.[hs] $(TARGET).new offset.tmp
diff -Nru a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/Makefile	Wed May 29 11:43:02 2002
@@ -9,43 +9,43 @@
 mod-subdirs :=	dio mtd sbus video macintosh usb input telephony sgi ide \
 		message scsi md ieee1394 pnp isdn atm \
 		fc4 i2c acpi bluetooth input/serio \
-		input/gameport parport hotplug
+		input/gameport parport hotplug \
+		base char block misc net media cdrom
 
-subdir-y :=	base char block net misc media cdrom
-subdir-m :=	$(subdir-y)
-
-subdir-$(CONFIG_PARPORT)	+= parport
-subdir-$(CONFIG_HOTPLUG_PCI)	+= hotplug
-subdir-$(CONFIG_DIO)		+= dio
-subdir-$(CONFIG_PCI)		+= pci
-subdir-$(CONFIG_PCMCIA)		+= pcmcia
-subdir-$(CONFIG_MTD)		+= mtd
-subdir-$(CONFIG_SBUS)		+= sbus
-subdir-$(CONFIG_ZORRO)		+= zorro
-subdir-$(CONFIG_NUBUS)		+= nubus
-subdir-$(CONFIG_TC)		+= tc
-subdir-$(CONFIG_VT)		+= video
-subdir-$(CONFIG_MAC)		+= macintosh
-subdir-$(CONFIG_ALL_PPC)	+= macintosh
-subdir-$(CONFIG_USB)		+= usb
-subdir-$(CONFIG_INPUT)		+= input
-subdir-$(CONFIG_SERIO)		+= input/serio
-subdir-$(CONFIG_GAMEPORT)	+= input/gameport
-subdir-$(CONFIG_PHONE)		+= telephony
-subdir-$(CONFIG_SGI)		+= sgi
-subdir-$(CONFIG_IDE)		+= ide
-subdir-$(CONFIG_SCSI)		+= scsi
-subdir-$(CONFIG_I2O)		+= message
-subdir-$(CONFIG_FUSION)		+= message
-subdir-$(CONFIG_MD)		+= md
-subdir-$(CONFIG_IEEE1394)	+= ieee1394
-subdir-$(CONFIG_PNP)		+= pnp
-subdir-$(CONFIG_ISDN)		+= isdn
-subdir-$(CONFIG_ATM)		+= atm
-subdir-$(CONFIG_FC4)		+= fc4
-subdir-$(CONFIG_I2C)		+= i2c
-subdir-$(CONFIG_ACPI)		+= acpi
-
-subdir-$(CONFIG_BLUEZ)		+= bluetooth
+obj-$(CONFIG_PCI)		+= pci/
+obj-$(CONFIG_ACPI)		+= acpi/
+obj-$(CONFIG_PARPORT)		+= parport/
+obj-y 				+= base/ char/ block/ misc/ net/ media/
+obj-$(CONFIG_NUBUS)		+= nubus/
+obj-$(CONFIG_ATM)		+= atm/
+obj-$(CONFIG_IDE)		+= ide/
+obj-$(CONFIG_FC4)		+= fc4/
+obj-$(CONFIG_SCSI)		+= scsi/
+obj-$(CONFIG_FUSION)		+= message/
+obj-$(CONFIG_IEEE1394)		+= ieee1394/
+obj-y				+= cdrom/
+obj-$(CONFIG_MTD)		+= mtd/
+obj-$(CONFIG_PCMCIA)		+= pcmcia/
+obj-$(CONFIG_DIO)		+= dio/
+obj-$(CONFIG_SBUS)		+= sbus/
+obj-$(CONFIG_ZORRO)		+= zorro/
+obj-$(CONFIG_ALL_PPC)		+= macintosh/
+obj-$(CONFIG_MAC)		+= macintosh/
+obj-$(CONFIG_PNP)		+= pnp/
+obj-$(CONFIG_SGI)		+= sgi/
+obj-$(CONFIG_VT)		+= video/
+obj-$(CONFIG_PARIDE) 		+= block/paride/
+obj-$(CONFIG_TC)		+= tc/
+obj-$(CONFIG_USB)		+= usb/
+obj-$(CONFIG_INPUT)		+= input/
+obj-$(CONFIG_GAMEPORT)		+= input/gameport/
+obj-$(CONFIG_SERIO)		+= input/serio/
+obj-$(CONFIG_I2O)		+= message/
+obj-$(CONFIG_I2C)		+= i2c/
+obj-$(CONFIG_PHONE)		+= telephony/
+obj-$(CONFIG_MD)		+= md/
+obj-$(CONFIG_BLUEZ)		+= bluetooth/
+obj-$(CONFIG_HOTPLUG_PCI)	+= hotplug/
+obj-$(CONFIG_ISDN)		+= isdn/
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/acorn/Makefile b/drivers/acorn/Makefile
--- a/drivers/acorn/Makefile	Wed May 29 11:43:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,15 +0,0 @@
-#
-# Makefile for the Acorn-specific Linux kernel device drivers.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (not a .c file).
-
-subdir-y	:= char
-subdir-m	:= $(subdir-y)
-
-# the BLOCK subdir is included from drivers/block now
-# the SCSI subdir is included from drivers/scsi now
-# the NET subdir is included from drivers/net now
-
-include $(TOPDIR)/Rules.make
diff -Nru a/drivers/acorn/block/Makefile b/drivers/acorn/block/Makefile
--- a/drivers/acorn/block/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/acorn/block/Makefile	Wed May 29 11:43:03 2002
@@ -2,14 +2,6 @@
 # Makefile for the Acorn block device drivers.
 #
 
-O_TARGET	:= acorn-block.o
-
-obj-y		:=
-obj-m		:=
-obj-n		:=
-obj-		:=
-
-export-objs	:=
 fd1772_mod-objs	:= fd1772.o fd1772dma.o
 mfmhd_mod-objs	:= mfmhd.o mfm.o
 
diff -Nru a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
--- a/drivers/acorn/block/fd1772.c	Wed May 29 11:43:02 2002
+++ b/drivers/acorn/block/fd1772.c	Wed May 29 11:43:02 2002
@@ -591,7 +591,7 @@
 {
 	printk("FDC1772: fd_error\n");
 	/*panic("fd1772: fd_error"); *//* DAG tmp */
-	if (QUEUE_EMPTY)
+	if (blk_queue_empty(QUEUE))
 		return;
 	CURRENT->errors++;
 	if (CURRENT->errors >= MAX_ERRORS) {
@@ -1114,16 +1114,6 @@
 static int fd_ref[4];
 static int fd_device[4];
 
-/*
- * Current device number. Taken either from the block header or from the
- * format request descriptor.
- */
-#define CURRENT_DEVICE (CURRENT->rq_dev)
-
-/* Current error count. */
-#define CURRENT_ERRORS (CURRENT->errors)
-
-
 /* dummy for blk.h */
 static void floppy_off(unsigned int nr)
 {
@@ -1145,7 +1135,7 @@
 {
 	unsigned int drive = (dev & 0x03);
 
-	if (MAJOR(dev) != MAJOR_NR) {
+	if (major(dev) != MAJOR_NR) {
 		printk("floppy_changed: not a floppy\n");
 		return 0;
 	}
@@ -1205,7 +1195,7 @@
 	ReqData = ReqBuffer + 512 * ReqCnt;
 
 #ifdef TRACKBUFFER
-	read_track = (ReqCmd == READ && CURRENT_ERRORS == 0);
+	read_track = (ReqCmd == READ && CURRENT->errors == 0);
 #endif
 
 	DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n", ReqSide,
@@ -1220,24 +1210,21 @@
 
 	DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->rq_dev=%04x CURRENT->sector=%ld\n",
 		(unsigned long) CURRENT, CURRENT ? CURRENT->rq_dev : 0,
-		!QUEUE_EMPTY ? CURRENT->sector : 0));
-
-	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE)
-		goto the_end;
+		!blk_queue_empty(QUEUE) ? CURRENT->sector : 0));
 
 repeat:
 
-	if (QUEUE_EMPTY)
+	if (blk_queue_empty(QUEUE))
 		goto the_end;
 
-	if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
+	if (major(CURRENT->rq_dev) != MAJOR_NR)
 		panic(DEVICE_NAME ": request list destroyed");
 
 	if (CURRENT->bh) {
 		if (!buffer_locked(CURRENT->bh))
 			panic(DEVICE_NAME ": block not locked");
 	}
-	device = MINOR(CURRENT_DEVICE);
+	device = minor(CURRENT->rq_dev);
 	drive = device & 3;
 	type = device >> 2;
 	floppy = &unit[drive];
@@ -1343,7 +1330,7 @@
 	int drive, device;
 
 	device = inode->i_rdev;
-	drive = MINOR(device);
+	drive = minor(device);
 	switch (cmd) {
 	case FDFMTBEG:
 		return 0;
@@ -1502,8 +1489,8 @@
 		DPRINT(("Weird, open called with filp=0\n"));
 		return -EIO;
 	}
-	drive = MINOR(inode->i_rdev) & 3;
-	if ((MINOR(inode->i_rdev) >> 2) > NUM_DISK_TYPES)
+	drive = minor(inode->i_rdev) & 3;
+	if ((minor(inode->i_rdev) >> 2) > NUM_DISK_TYPES)
 		return -ENXIO;
 
 	old_dev = fd_device[drive];
@@ -1543,7 +1530,7 @@
 
 static int floppy_release(struct inode *inode, struct file *filp)
 {
-	int drive = MINOR(inode->i_rdev) & 3;
+	int drive = minor(inode->i_rdev) & 3;
 
 	if (fd_ref[drive] < 0)
 		fd_ref[drive] = 0;
diff -Nru a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
--- a/drivers/acorn/block/mfmhd.c	Wed May 29 11:43:02 2002
+++ b/drivers/acorn/block/mfmhd.c	Wed May 29 11:43:02 2002
@@ -756,7 +756,7 @@
 		/* No - its the end of the line */
 		/* end_request's should have happened at the end of sector DMAs */
 		/* Turns Drive LEDs off - may slow it down? */
-		if (QUEUE_EMPTY)
+		if (blk_queue_empty(QUEUE))
 			issue_command(CMD_CKV, block, 2);
 
 		Busy = 0;
diff -Nru a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile
--- a/drivers/acorn/char/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/acorn/char/Makefile	Wed May 29 11:43:01 2002
@@ -1,22 +1,6 @@
 #
-# Makefile for the kernel character device drivers.
+# Makefile for the acorn character device drivers.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
-
-O_TARGET 	:= acorn-char.o
-
-# Object file lists.
-
-obj-y   	:=
-obj-m		:=
-obj-n		:=
-obj-		:=
 
 # All the objects that export symbols.
 export-objs	:= mouse_rpc.o
diff -Nru a/drivers/acpi/Makefile b/drivers/acpi/Makefile
--- a/drivers/acpi/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/acpi/Makefile	Wed May 29 11:43:02 2002
@@ -2,8 +2,6 @@
 # Makefile for the Linux ACPI interpreter
 # 
 
-O_TARGET := acpi.o
-
 export ACPI_CFLAGS
 
 ACPI_CFLAGS	:= -D_LINUX -I$(CURDIR)/include
diff -Nru a/drivers/acpi/acpi_system.c b/drivers/acpi/acpi_system.c
--- a/drivers/acpi/acpi_system.c	Wed May 29 11:43:03 2002
+++ b/drivers/acpi/acpi_system.c	Wed May 29 11:43:03 2002
@@ -709,11 +709,9 @@
 	if (!system->states[state])
 		return_VALUE(-ENODEV);
 
-	
 #ifdef CONFIG_SOFTWARE_SUSPEND
 	if (state == 4) {
-		/* We are working from process context, that's why we may call it directly. */ 
-		do_software_suspend();
+		software_suspend();
 		return_VALUE(count);
 	}
 #endif
diff -Nru a/drivers/atm/Makefile b/drivers/atm/Makefile
--- a/drivers/atm/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/atm/Makefile	Wed May 29 11:43:01 2002
@@ -2,8 +2,6 @@
 # Makefile for the Linux network (ATM) device drivers.
 #
 
-O_TARGET := atm.o
-
 export-objs := uPD98402.o suni.o idt77105.o
 
 obj-y := atmdev_init.o
@@ -102,5 +100,5 @@
                        fore200e_pca_fw.c fore200e_sba_fw.c)
 
 ifneq ($(FORE200E_FW_CHANGED),)
-$(FORE200E_FW_CHANGED): dummy
+$(FORE200E_FW_CHANGED): FORCE
 endif
diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile
--- a/drivers/base/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/base/Makefile	Wed May 29 11:43:02 2002
@@ -1,7 +1,8 @@
-O_TARGET	:= base.o
+# Makefile for the Linux device tree
 
-obj-y		:= core.o sys.o interface.o fs.o power.o
+obj-y		:= core.o sys.o interface.o fs.o power.o bus.o \
+			driver.o 
 
-export-objs	:= core.o fs.o power.o sys.o
+export-objs	:= core.o fs.o power.o sys.o bus.o driver.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/base/base.h b/drivers/base/base.h
--- a/drivers/base/base.h	Wed May 29 11:43:02 2002
+++ b/drivers/base/base.h	Wed May 29 11:43:02 2002
@@ -9,6 +9,11 @@
 extern struct device device_root;
 extern spinlock_t device_lock;
 
+extern int bus_add_device(struct device * dev);
+extern void bus_remove_device(struct device * dev);
+
+extern int device_create_dir(struct driver_dir_entry * dir, struct driver_dir_entry * parent);
 extern int device_make_dir(struct device * dev);
 extern void device_remove_dir(struct device * dev);
 
+extern int device_bus_link(struct device * dev);
diff -Nru a/drivers/base/bus.c b/drivers/base/bus.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/base/bus.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,125 @@
+/*
+ * bus.c - bus driver management
+ * 
+ * Copyright (c) 2002 Patrick Mochel
+ *		 2002 Open Source Development Lab
+ * 
+ * 
+ */
+
+#define DEBUG 0
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include "base.h"
+
+static LIST_HEAD(bus_driver_list);
+
+static struct driver_dir_entry bus_dir = {
+	name:	"bus",
+	mode:	(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO),
+};
+
+/**
+ * bus_add_device - add device to bus
+ * @dev:	device being added
+ *
+ * Add the device to its bus's list of devices.
+ * Create a symlink in the bus's 'devices' directory to the 
+ * device's physical location.
+ * Try and bind the device to a driver.
+ */
+int bus_add_device(struct device * dev)
+{
+	if (dev->bus) {
+		pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name);
+		get_bus(dev->bus);
+		write_lock(&dev->bus->lock);
+		list_add_tail(&dev->bus_list,&dev->bus->devices);
+		write_unlock(&dev->bus->lock);
+		device_bus_link(dev);
+	}
+	return 0;
+}
+
+/**
+ * bus_remove_device - remove device from bus
+ * @dev:	device to be removed
+ *
+ * Remove symlink from bus's directory.
+ * Delete device from bus's list.
+ */
+void bus_remove_device(struct device * dev)
+{
+	if (dev->bus) {
+		driverfs_remove_file(&dev->bus->device_dir,dev->bus_id);
+		write_lock(&dev->bus->lock);
+		list_del_init(&dev->bus_list);
+		write_unlock(&dev->bus->lock);
+		put_bus(dev->bus);
+	}
+}
+
+static int bus_make_dir(struct bus_type * bus)
+{
+	int error;
+	bus->dir.name = bus->name;
+
+	error = device_create_dir(&bus->dir,&bus_dir);
+	if (!error) {
+		bus->device_dir.name = "devices";
+		device_create_dir(&bus->device_dir,&bus->dir);
+
+		bus->driver_dir.name = "drivers";
+		device_create_dir(&bus->driver_dir,&bus->dir);
+	}
+	return error;
+}
+
+
+int bus_register(struct bus_type * bus)
+{
+	spin_lock(&device_lock);
+	rwlock_init(&bus->lock);
+	INIT_LIST_HEAD(&bus->devices);
+	INIT_LIST_HEAD(&bus->drivers);
+	list_add_tail(&bus->node,&bus_driver_list);
+	atomic_set(&bus->refcount,2);
+	spin_unlock(&device_lock);
+
+	pr_debug("bus type '%s' registered\n",bus->name);
+
+	/* give it some driverfs entities */
+	bus_make_dir(bus);
+	put_bus(bus);
+
+	return 0;
+}
+
+void put_bus(struct bus_type * bus)
+{
+	if (!atomic_dec_and_lock(&bus->refcount,&device_lock))
+		return;
+	list_del_init(&bus->node);
+	spin_unlock(&device_lock);
+
+	/* remove driverfs entries */
+	driverfs_remove_dir(&bus->driver_dir);
+	driverfs_remove_dir(&bus->device_dir);
+	driverfs_remove_dir(&bus->dir);
+}
+
+static int __init bus_init(void)
+{
+	/* make 'bus' driverfs directory */
+	return driverfs_create_dir(&bus_dir,NULL);
+}
+
+core_initcall(bus_init);
+
+EXPORT_SYMBOL(bus_add_device);
+EXPORT_SYMBOL(bus_remove_device);
+EXPORT_SYMBOL(bus_register);
+EXPORT_SYMBOL(put_bus);
diff -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	Wed May 29 11:43:01 2002
+++ b/drivers/base/core.c	Wed May 29 11:43:01 2002
@@ -70,6 +70,8 @@
 	if ((error = device_make_dir(dev)))
 		goto register_done;
 
+	bus_add_device(dev);
+
 	/* notify platform of device entry */
 	if (platform_notify)
 		platform_notify(dev);
@@ -96,21 +98,26 @@
 	DBG("DEV: Unregistering device. ID = '%s', name = '%s'\n",
 	    dev->bus_id,dev->name);
 
-	/* remove the driverfs directory */
-	device_remove_dir(dev);
-
 	/* Notify the platform of the removal, in case they
 	 * need to do anything...
 	 */
 	if (platform_notify_remove)
 		platform_notify_remove(dev);
 
+	bus_remove_device(dev);
+
 	/* Tell the driver to clean up after itself.
 	 * Note that we likely didn't allocate the device,
 	 * so this is the driver's chance to free that up...
 	 */
 	if (dev->driver && dev->driver->remove)
 		dev->driver->remove(dev,REMOVE_FREE_RESOURCES);
+
+	/* remove the driverfs directory */
+	device_remove_dir(dev);
+
+	if (dev->release)
+		dev->release(dev);
 
 	put_device(dev->parent);
 }
diff -Nru a/drivers/base/driver.c b/drivers/base/driver.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/base/driver.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,70 @@
+/*
+ * driver.c - centralized device driver management
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include "base.h"
+
+/**
+ * driver_make_dir - create a driverfs directory for a driver
+ * @drv:	driver in question
+ */
+static int driver_make_dir(struct device_driver * drv)
+{
+	drv->dir.name = drv->name;
+	return device_create_dir(&drv->dir,&drv->bus->driver_dir);
+}
+
+/**
+ * driver_register - register driver with bus
+ * @drv:	driver to register
+ * 
+ * Add to bus's list of devices
+ */
+int driver_register(struct device_driver * drv)
+{
+	if (!drv->bus)
+		return -EINVAL;
+
+	pr_debug("Registering driver '%s' with bus '%s'\n",drv->name,drv->bus->name);
+
+	get_bus(drv->bus);
+	atomic_set(&drv->refcount,2);
+	rwlock_init(&drv->lock);
+	write_lock(&drv->bus->lock);
+	list_add(&drv->bus_list,&drv->bus->drivers);
+	write_unlock(&drv->bus->lock);
+	driver_make_dir(drv);
+	put_driver(drv);
+	return 0;
+}
+
+/**
+ * put_driver - decrement driver's refcount and clean up if necessary
+ * @drv:	driver in question
+ */
+void put_driver(struct device_driver * drv)
+{
+	if (!atomic_dec_and_lock(&drv->refcount,&device_lock))
+		return;
+	spin_unlock(&device_lock);
+
+	if (drv->bus) {
+		pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name);
+
+		write_lock(&drv->bus->lock);
+		list_del_init(&drv->bus_list);
+		write_unlock(&drv->bus->lock);
+
+		driverfs_remove_dir(&drv->dir);
+		put_bus(drv->bus);
+	}
+	if (drv->release)
+		drv->release(drv);
+}
+
+EXPORT_SYMBOL(driver_register);
+EXPORT_SYMBOL(put_driver);
diff -Nru a/drivers/base/fs.c b/drivers/base/fs.c
--- a/drivers/base/fs.c	Wed May 29 11:43:03 2002
+++ b/drivers/base/fs.c	Wed May 29 11:43:03 2002
@@ -5,12 +5,15 @@
  *		 2002 Open Source Development Lab
  */
 
+#define DEBUG 0
+
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/stat.h>
+#include <linux/limits.h>
 
 extern struct driver_file_entry * device_default_files[];
 
@@ -68,6 +71,92 @@
 		driverfs_remove_dir(&dev->dir);
 }
 
+
+static int get_devpath_length(struct device * dev)
+{
+	int length = 1;
+	struct device * parent = dev;
+
+	/* walk up the ancestors until we hit the root.
+	 * Add 1 to strlen for leading '/' of each level.
+	 */
+	do {
+		length += strlen(parent->bus_id) + 1;
+		parent = parent->parent;
+	} while (parent);
+	return length;
+}
+
+static void fill_devpath(struct device * dev, char * path, int length)
+{
+	struct device * parent;
+	--length;
+	for (parent = dev; parent; parent = parent->parent) {
+		int cur = strlen(parent->bus_id);
+
+		/* back up enough to print this bus id with '/' */
+		length -= cur;
+		strncpy(path + length,parent->bus_id,cur);
+		*(path + --length) = '/';
+	}
+
+	pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
+}
+
+static int create_symlink(struct driver_dir_entry * parent, char * name, char * path)
+{
+	struct driver_file_entry * entry;
+
+	entry = kmalloc(sizeof(struct driver_file_entry),GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+	entry->name = name;
+	entry->mode = S_IRUGO;
+	return driverfs_create_symlink(parent,entry,path);
+}
+
+int device_bus_link(struct device * dev)
+{
+	char * path;
+	int length;
+	int error = 0;
+
+	if (!dev->bus)
+		return 0;
+
+	length = get_devpath_length(dev);
+
+	/* now add the path from the bus directory
+	 * It should be '../../..' (one to get to the bus's directory,
+	 * one to get to the 'bus' directory, and one to get to the root 
+	 * of the fs.)
+	 */
+	length += strlen("../../..");
+
+	if (length > PATH_MAX)
+		return -ENAMETOOLONG;
+
+	if (!(path = kmalloc(length,GFP_KERNEL)))
+		return -ENOMEM;
+	memset(path,0,length);
+
+	/* our relative position */
+	strcpy(path,"../../..");
+
+	fill_devpath(dev,path,length);
+	error = create_symlink(&dev->bus->device_dir,dev->bus_id,path);
+
+	kfree(path);
+	return error;
+}
+
+int device_create_dir(struct driver_dir_entry * dir, struct driver_dir_entry * parent)
+{
+	INIT_LIST_HEAD(&dir->files);
+	dir->mode  = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
+	return driverfs_create_dir(dir,parent);
+}
+
 /**
  * device_make_dir - create a driverfs directory
  * @name:	name of directory
@@ -87,23 +176,20 @@
 	int error;
 	int i;
 
-	INIT_LIST_HEAD(&dev->dir.files);
-	dev->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
-	dev->dir.name = dev->bus_id;
-
 	if (dev->parent)
 		parent = &dev->parent->dir;
+	dev->dir.name = dev->bus_id;
 
-	if ((error = driverfs_create_dir(&dev->dir,parent)))
+	if ((error = device_create_dir(&dev->dir,parent)))
 		return error;
 
 	for (i = 0; (entry = *(device_default_files + i)); i++) {
 		if ((error = device_create_file(dev,entry))) {
 			device_remove_dir(dev);
-			return error;
+			break;
 		}
 	}
-	return 0;
+	return error;
 }
 
 EXPORT_SYMBOL(device_create_file);
diff -Nru a/drivers/block/Makefile b/drivers/block/Makefile
--- a/drivers/block/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/block/Makefile	Wed May 29 11:43:03 2002
@@ -8,8 +8,6 @@
 # In the future, some of these should be built conditionally.
 #
 
-O_TARGET := block.o
-
 export-objs	:= elevator.o ll_rw_blk.o blkpg.o loop.o DAC960.o genhd.o block_ioctl.o
 
 obj-y	:= elevator.o ll_rw_blk.o blkpg.o genhd.o block_ioctl.o
@@ -32,7 +30,5 @@
 
 obj-$(CONFIG_BLK_DEV_UMEM)	+= umem.o
 obj-$(CONFIG_BLK_DEV_NBD)	+= nbd.o
-
-subdir-$(CONFIG_PARIDE) += paride
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/block/acsi.c b/drivers/block/acsi.c
--- a/drivers/block/acsi.c	Wed May 29 11:43:03 2002
+++ b/drivers/block/acsi.c	Wed May 29 11:43:03 2002
@@ -768,7 +768,7 @@
 static void bad_rw_intr( void )
 
 {
-	if (QUEUE_EMPTY)
+	if (blk_queue_empty(QUEUE))
 		return;
 
 	if (++CURRENT->errors >= MAX_ERRORS)
@@ -842,7 +842,8 @@
 
 	DEVICE_INTR = NULL;
 	printk( KERN_ERR "ACSI timeout\n" );
-	if (QUEUE_EMPTY) return;
+	if (blk_queue_empty(QUEUE))
+	    return;
 	if (++CURRENT->errors >= MAX_ERRORS) {
 #ifdef DEBUG
 		printk( KERN_ERR "ACSI: too many errors.\n" );
@@ -951,40 +952,20 @@
 	char 				*buffer;
 	unsigned long		pbuffer;
 	struct buffer_head	*bh;
-	
-	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) {
-		if (!DEVICE_INTR) {
-			ENABLE_IRQ();
-			stdma_release();
-		}
-		return;
-	}
-
-	if (DEVICE_INTR)
-		return;
 
   repeat:
 	CLEAR_TIMER();
-	/* Another check here: An interrupt or timer event could have
-	 * happened since the last check!
-	 */
-	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) {
-		if (!DEVICE_INTR) {
-			ENABLE_IRQ();
-			stdma_release();
-		}
-		return;
-	}
+
 	if (DEVICE_INTR)
 		return;
 
-	if (QUEUE_EMPTY) {
+	if (blk_queue_empty(QUEUE)) {
 		CLEAR_INTR;
 		ENABLE_IRQ();
 		stdma_release();
 		return;
 	}
-	
+
 	if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
 		panic(DEVICE_NAME ": request list destroyed");
 	if (CURRENT->bh) {
diff -Nru a/drivers/block/amiflop.c b/drivers/block/amiflop.c
--- a/drivers/block/amiflop.c	Wed May 29 11:43:03 2002
+++ b/drivers/block/amiflop.c	Wed May 29 11:43:03 2002
@@ -209,17 +209,6 @@
 static kdev_t fd_device[4] = { NODEV, NODEV, NODEV, NODEV };
 
 /*
- * Current device number. Taken either from the block header or from the
- * format request descriptor.
- */
-#define CURRENT_DEVICE (CURRENT->rq_dev)
-
-/* Current error count. */
-#define CURRENT_ERRORS (CURRENT->errors)
-
-
-
-/*
  * Here come the actual hardware access and helper functions.
  * They are not reentrant and single threaded because all drives
  * share the same hardware and the same trackbuffer.
@@ -1383,12 +1372,8 @@
 	char *data;
 	unsigned long flags;
 
-	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE){
-		return;
-	}
-
  repeat:
-	if (QUEUE_EMPTY) {
+	if (blk_queue_empty(QUEUE)) {
 		/* Nothing left to do */
 		return;
 	}
@@ -1396,7 +1381,7 @@
 	if (major(CURRENT->rq_dev) != MAJOR_NR)
 		panic(DEVICE_NAME ": request list destroyed");
 
-	device = minor(CURRENT_DEVICE);
+	device = minor(CURRENT->rq_dev);
 	if (device < 8) {
 		/* manual selection */
 		drive = device & 3;
diff -Nru a/drivers/block/ataflop.c b/drivers/block/ataflop.c
--- a/drivers/block/ataflop.c	Wed May 29 11:43:02 2002
+++ b/drivers/block/ataflop.c	Wed May 29 11:43:02 2002
@@ -625,8 +625,10 @@
 		wake_up( &format_wait );
 		return;
 	}
-		
-	if (QUEUE_EMPTY) return;
+
+	if (blk_queue_empty(QUEUE))
+		return;
+
 	CURRENT->errors++;
 	if (CURRENT->errors >= MAX_ERRORS) {
 		printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive );
@@ -1335,16 +1337,6 @@
 static int fd_ref[4] = { 0,0,0,0 };
 static int fd_device[4] = { 0,0,0,0 };
 
-/*
- * Current device number. Taken either from the block header or from the
- * format request descriptor.
- */
-#define CURRENT_DEVICE (CURRENT->rq_dev)
-
-/* Current error count. */
-#define CURRENT_ERRORS (CURRENT->errors)
-
-
 /* dummy for blk.h */
 static void floppy_off( unsigned int nr) {}
 
@@ -1437,7 +1429,7 @@
 	ReqData = ReqBuffer + 512 * ReqCnt;
 
 	if (UseTrackbuffer)
-		read_track = (ReqCmd == READ && CURRENT_ERRORS == 0);
+		read_track = (ReqCmd == READ && CURRENT->errors == 0);
 	else
 		read_track = 0;
 
@@ -1451,18 +1443,14 @@
 	int device, drive, type;
   
 	DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->dev=%04x CURRENT->sector=%ld\n",
-		(unsigned long)CURRENT, !QUEUE_EMPTY ? CURRENT->rq_dev : 0,
-		!QUEUE_EMPTY ? CURRENT->sector : 0 ));
+		(unsigned long)CURRENT, !blk_queue_empty(QUEUE) ? CURRENT->rq_dev : 0,
+		!blk_queue_empty(QUEUE) ? CURRENT->sector : 0 ));
 
 	IsFormatting = 0;
 
-	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE){
-		return;
-	}
-
 repeat:
-    
-	if (QUEUE_EMPTY)
+
+	if (blk_queue_empty(QUEUE))
 		goto the_end;
 
 	if (major(CURRENT->rq_dev) != MAJOR_NR)
@@ -1471,7 +1459,7 @@
 	if (CURRENT->bh && !buffer_locked(CURRENT->bh))
 		panic(DEVICE_NAME ": block not locked");
 
-	device = minor(CURRENT_DEVICE);
+	device = minor(CURRENT->rq_dev);
 	drive = device & 3;
 	type = device >> 2;
 	
diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c	Wed May 29 11:43:03 2002
+++ b/drivers/block/cciss.c	Wed May 29 11:43:03 2002
@@ -281,7 +281,7 @@
                 	i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
                         if (i == NR_CMDS)
                                 return NULL;
-                } while(test_and_set_bit(i & 31, h->cmd_pool_bits+(i/32)) != 0);
+                } while(test_and_set_bit(i & (BITS_PER_LONG - 1), h->cmd_pool_bits+(i/BITS_PER_LONG)) != 0);
 #ifdef CCISS_DEBUG
 		printk(KERN_DEBUG "cciss: using command buffer %d\n", i);
 #endif
@@ -327,7 +327,7 @@
 	} else 
 	{
 		i = c - h->cmd_pool;
-		clear_bit(i%32, h->cmd_pool_bits+(i/32));
+		clear_bit(i&(BITS_PER_LONG-1), h->cmd_pool_bits+(i/BITS_PER_LONG));
                 h->nr_frees++;
         }
 }
@@ -338,7 +338,7 @@
 static void cciss_geninit( int ctlr)
 {
 	drive_info_struct *drv;
-	int i,j;
+	int i;
 	
 	/* Loop through each real device */ 
 	hba[ctlr]->gendisk.nr_real = 0; 
@@ -1883,6 +1883,7 @@
 
 	goto queue;
 startio:
+	blk_stop_queue(q);
 	start_io(h);
 }
 
@@ -1943,8 +1944,8 @@
 	/*
 	 * See if we can queue up some more IO
 	 */
-	do_cciss_request(BLK_DEFAULT_QUEUE(MAJOR_NR + h->ctlr));
 	spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+	blk_start_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + h->ctlr));
 }
 /* 
  *  We cannot read the structure directly, for portablity we must use 
@@ -2448,8 +2449,7 @@
 		free_hba(i);
 		return(-1);
 	}
-	hba[i]->cmd_pool_bits = (__u32*)kmalloc(
-        	((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
+	hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL);
 	hba[i]->cmd_pool = (CommandList_struct *)pci_alloc_consistent(
 		hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct), 
 		&(hba[i]->cmd_pool_dhandle));
@@ -2484,7 +2484,7 @@
 	pci_set_drvdata(pdev, hba[i]);
 	/* command and error info recs zeroed out before 
 			they are used */
-        memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32));
+        memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long));
 
 #ifdef CCISS_DEBUG	
 	printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i);
diff -Nru a/drivers/block/cciss.h b/drivers/block/cciss.h
--- a/drivers/block/cciss.h	Wed May 29 11:43:01 2002
+++ b/drivers/block/cciss.h	Wed May 29 11:43:01 2002
@@ -76,7 +76,7 @@
 	dma_addr_t		cmd_pool_dhandle; 
 	ErrorInfo_struct 	*errinfo_pool;
 	dma_addr_t		errinfo_pool_dhandle; 
-        __u32   		*cmd_pool_bits;
+        unsigned long  		*cmd_pool_bits;
 	int			nr_allocs;
 	int			nr_frees; 
 
diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
--- a/drivers/block/cpqarray.c	Wed May 29 11:43:01 2002
+++ b/drivers/block/cpqarray.c	Wed May 29 11:43:01 2002
@@ -166,7 +166,7 @@
 
 static void ida_geninit(int ctlr)
 {
-	int i,j;
+	int i;
 	drv_info_t *drv;
 
 	for(i=0; i<NWD; i++) {
@@ -409,8 +409,7 @@
 		hba[i]->cmd_pool = (cmdlist_t *)pci_alloc_consistent(
 				hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t), 
 				&(hba[i]->cmd_pool_dhandle));
-		hba[i]->cmd_pool_bits = (__u32*)kmalloc(
-				((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
+		hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL);
 		
 	if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL)
 		{
@@ -441,7 +440,7 @@
 	
 		}
 		memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t));
-		memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32));
+		memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long));
 		printk(KERN_INFO "cpqarray: Finding drives on %s", 
 			hba[i]->devname);
 		getgeometry(i);
@@ -916,6 +915,7 @@
 	goto queue_next;
 
 startio:
+	blk_stop_queue(q);
 	start_io(h);
 }
 
@@ -1066,8 +1066,8 @@
 	/*
 	 * See if we can queue up some more IO
 	 */
-	do_ida_request(BLK_DEFAULT_QUEUE(MAJOR_NR + h->ctlr));
 	spin_unlock_irqrestore(IDA_LOCK(h->ctlr), flags);
+	blk_start_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + h->ctlr));
 }
 
 /*
@@ -1333,7 +1333,7 @@
 			i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
 			if (i == NR_CMDS)
 				return NULL;
-		} while(test_and_set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0);
+		} while(test_and_set_bit(i&(BITS_PER_LONG-1), h->cmd_pool_bits+(i/BITS_PER_LONG)) != 0);
 		c = h->cmd_pool + i;
 		cmd_dhandle = h->cmd_pool_dhandle + i*sizeof(cmdlist_t);
 		h->nr_allocs++;
@@ -1353,7 +1353,7 @@
 			c->busaddr);
 	} else {
 		i = c - h->cmd_pool;
-		clear_bit(i%32, h->cmd_pool_bits+(i/32));
+		clear_bit(i&(BITS_PER_LONG-1), h->cmd_pool_bits+(i/BITS_PER_LONG));
 		h->nr_frees++;
 	}
 }
diff -Nru a/drivers/block/cpqarray.h b/drivers/block/cpqarray.h
--- a/drivers/block/cpqarray.h	Wed May 29 11:43:03 2002
+++ b/drivers/block/cpqarray.h	Wed May 29 11:43:03 2002
@@ -104,7 +104,7 @@
 	cmdlist_t *cmpQ;
 	cmdlist_t *cmd_pool;
 	dma_addr_t cmd_pool_dhandle;
-	__u32	*cmd_pool_bits;
+	unsigned long *cmd_pool_bits;
 	spinlock_t lock;
 
 	unsigned int Qdepth;
diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c
--- a/drivers/block/floppy.c	Wed May 29 11:43:02 2002
+++ b/drivers/block/floppy.c	Wed May 29 11:43:02 2002
@@ -2918,14 +2918,8 @@
 	if (current_drive < N_DRIVE)
 		floppy_off(current_drive);
 
-	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE){
-		CLEAR_INTR;
-		unlock_fdc();
-		return;
-	}
-
-	while(1){
-		if (QUEUE_EMPTY) {
+	for (;;) {
+		if (blk_queue_empty(QUEUE)) {
 			CLEAR_INTR;
 			unlock_fdc();
 			return;
@@ -3900,7 +3894,7 @@
 	bio.bi_end_io = floppy_rb0_complete;
 
 	submit_bio(READ, &bio);
-	run_task_queue(&tq_disk);
+	generic_unplug_device(bdev_get_queue(bdev));
 	process_fd_request();
 	wait_for_completion(&complete);
 
@@ -4226,14 +4220,15 @@
 
 static int have_no_fdc= -ENODEV;
 
-static struct device device_floppy;
+static struct device device_floppy = {
+	name:		"floppy",
+	bus_id:		"03?0",
+};
 
 int __init floppy_init(void)
 {
 	int i,unit,drive;
 
-	strcpy(device_floppy.name, "floppy");
-	strcpy(device_floppy.bus_id, "03?0");
 	register_sys_device(&device_floppy);
 
 	raw_cmd = NULL;
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Wed May 29 11:43:01 2002
+++ b/drivers/block/ll_rw_blk.c	Wed May 29 11:43:01 2002
@@ -49,11 +49,8 @@
  */
 static kmem_cache_t *request_cachep;
 
-/*
- * The "disk" task queue is used to start the actual requests
- * after a plug
- */
-DECLARE_TASK_QUEUE(tq_disk);
+static struct list_head blk_plug_list;
+static spinlock_t blk_plug_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 /* blk_dev_struct is:
  *	request_queue
@@ -791,8 +788,11 @@
 	if (!elv_queue_empty(q))
 		return;
 
-	if (!test_and_set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags))
-		queue_task(&q->plug_tq, &tq_disk);
+	if (!test_and_set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) {
+		spin_lock(&blk_plug_lock);
+		list_add_tail(&q->plug_list, &blk_plug_list);
+		spin_unlock(&blk_plug_lock);
+	}
 }
 
 /*
@@ -803,7 +803,10 @@
 	/*
 	 * not plugged
 	 */
-	if (!test_and_clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags))
+	if (!__test_and_clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags))
+		return;
+
+	if (test_bit(QUEUE_FLAG_STOPPED, &q->queue_flags))
 		return;
 
 	/*
@@ -815,19 +818,19 @@
 
 /**
  * generic_unplug_device - fire a request queue
- * @q:    The &request_queue_t in question
+ * @data:    The &request_queue_t in question
  *
  * Description:
  *   Linux uses plugging to build bigger requests queues before letting
  *   the device have at them. If a queue is plugged, the I/O scheduler
  *   is still adding and merging requests on the queue. Once the queue
  *   gets unplugged (either by manually calling this function, or by
- *   running the tq_disk task queue), the request_fn defined for the
+ *   calling blk_run_queues()), the request_fn defined for the
  *   queue is invoked and transfers started.
  **/
 void generic_unplug_device(void *data)
 {
-	request_queue_t *q = (request_queue_t *) data;
+	request_queue_t *q = data;
 	unsigned long flags;
 
 	spin_lock_irqsave(q->queue_lock, flags);
@@ -835,6 +838,74 @@
 	spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
+/*
+ * clear stop flag and run queue
+ */
+void blk_start_queue(request_queue_t *q)
+{
+	if (test_and_clear_bit(QUEUE_FLAG_STOPPED, &q->queue_flags)) {
+		unsigned long flags;
+
+		spin_lock_irqsave(q->queue_lock, flags);
+		if (!elv_queue_empty(q))
+			q->request_fn(q);
+		spin_unlock_irqrestore(q->queue_lock, flags);
+	}
+}
+
+/*
+ * set stop bit, queue won't be run until blk_start_queue() is called
+ */
+void blk_stop_queue(request_queue_t *q)
+{
+	set_bit(QUEUE_FLAG_STOPPED, &q->queue_flags);
+}
+
+/*
+ * the equivalent of the previous tq_disk run
+ */
+void blk_run_queues(void)
+{
+	struct list_head *n, *tmp, local_plug_list;
+	unsigned long flags;
+
+	INIT_LIST_HEAD(&local_plug_list);
+
+	/*
+	 * this will happen fairly often
+	 */
+	spin_lock_irqsave(&blk_plug_lock, flags);
+	if (list_empty(&blk_plug_list)) {
+		spin_unlock_irqrestore(&blk_plug_lock, flags);
+		return;
+	}
+
+	list_splice(&blk_plug_list, &local_plug_list);
+	INIT_LIST_HEAD(&blk_plug_list);
+	spin_unlock_irqrestore(&blk_plug_lock, flags);
+
+	/*
+	 * local_plug_list is now a private copy we can traverse lockless
+	 */
+	list_for_each_safe(n, tmp, &local_plug_list) {
+		request_queue_t *q = list_entry(n, request_queue_t, plug_list);
+
+		if (!test_bit(QUEUE_FLAG_STOPPED, &q->queue_flags)) {
+			list_del(&q->plug_list);
+			generic_unplug_device(q);
+		}
+	}
+
+	/*
+	 * add any remaining queue back to plug list
+	 */
+	if (!list_empty(&local_plug_list)) {
+		spin_lock_irqsave(&blk_plug_lock, flags);
+		list_splice(&local_plug_list, &blk_plug_list);
+		spin_unlock_irqrestore(&blk_plug_lock, flags);
+	}
+}
+
 static int __blk_cleanup_queue(struct request_list *list)
 {
 	struct list_head *head = &list->free;
@@ -974,9 +1045,6 @@
 	q->front_merge_fn      	= ll_front_merge_fn;
 	q->merge_requests_fn	= ll_merge_requests_fn;
 	q->prep_rq_fn		= NULL;
-	q->plug_tq.sync		= 0;
-	q->plug_tq.routine	= &generic_unplug_device;
-	q->plug_tq.data		= q;
 	q->queue_flags		= (1 << QUEUE_FLAG_CLUSTER);
 	q->queue_lock		= lock;
 
@@ -987,6 +1055,9 @@
 
 	blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
 	blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
+
+	INIT_LIST_HEAD(&q->plug_list);
+
 	return 0;
 }
 
@@ -1867,6 +1938,8 @@
 	blk_max_low_pfn = max_low_pfn;
 	blk_max_pfn = max_pfn;
 
+	INIT_LIST_HEAD(&blk_plug_list);
+
 #if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD)
 	hd_init();
 #endif
@@ -1889,6 +1962,7 @@
 EXPORT_SYMBOL(generic_unplug_device);
 EXPORT_SYMBOL(blk_attempt_remerge);
 EXPORT_SYMBOL(blk_max_low_pfn);
+EXPORT_SYMBOL(blk_max_pfn);
 EXPORT_SYMBOL(blk_queue_max_sectors);
 EXPORT_SYMBOL(blk_queue_max_phys_segments);
 EXPORT_SYMBOL(blk_queue_max_hw_segments);
@@ -1902,6 +1976,8 @@
 EXPORT_SYMBOL(blk_queue_assign_lock);
 EXPORT_SYMBOL(blk_phys_contig_segment);
 EXPORT_SYMBOL(blk_hw_contig_segment);
+EXPORT_SYMBOL(blk_get_request);
+EXPORT_SYMBOL(blk_put_request);
 
 EXPORT_SYMBOL(blk_queue_prep_rq);
 
@@ -1910,3 +1986,7 @@
 EXPORT_SYMBOL(blk_queue_start_tag);
 EXPORT_SYMBOL(blk_queue_end_tag);
 EXPORT_SYMBOL(blk_queue_invalidate_tags);
+
+EXPORT_SYMBOL(blk_start_queue);
+EXPORT_SYMBOL(blk_stop_queue);
+EXPORT_SYMBOL(blk_run_queues);
diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c	Wed May 29 11:43:01 2002
+++ b/drivers/block/loop.c	Wed May 29 11:43:01 2002
@@ -168,7 +168,8 @@
 					
 }
 
-static int lo_send(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
+static int
+do_lo_send(struct loop_device *lo, struct bio_vec *bvec, int bsize, loff_t pos)
 {
 	struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
 	struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
@@ -178,12 +179,13 @@
 	unsigned long index;
 	unsigned size, offset;
 	int len;
+	int ret = 0;
 
 	down(&mapping->host->i_sem);
 	index = pos >> PAGE_CACHE_SHIFT;
 	offset = pos & (PAGE_CACHE_SIZE - 1);
-	len = bio->bi_size;
-	data = bio_data(bio);
+	data = kmap(bvec->bv_page) + bvec->bv_offset;
+	len = bvec->bv_len;
 	while (len > 0) {
 		int IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize;
 		int transfer_result;
@@ -221,14 +223,34 @@
 		page_cache_release(page);
 	}
 	up(&mapping->host->i_sem);
-	return 0;
+out:
+	kunmap(bvec->bv_page);
+	return ret;
 
 unlock:
 	unlock_page(page);
 	page_cache_release(page);
 fail:
 	up(&mapping->host->i_sem);
-	return -1;
+	ret = -1;
+	goto out;
+}
+
+static int
+lo_send(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
+{
+	unsigned vecnr;
+	int ret = 0;
+
+	for (vecnr = 0; vecnr < bio->bi_vcnt; vecnr++) {
+		struct bio_vec *bvec = &bio->bi_io_vec[vecnr];
+
+		ret = do_lo_send(lo, bvec, bsize, pos);
+		if (ret < 0)
+			break;
+		pos += bvec->bv_len;
+	}
+	return ret;
 }
 
 struct lo_read_data {
@@ -262,26 +284,46 @@
 	return size;
 }
 
-static int lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
+static int
+do_lo_receive(struct loop_device *lo,
+		struct bio_vec *bvec, int bsize, loff_t pos)
 {
 	struct lo_read_data cookie;
 	read_descriptor_t desc;
 	struct file *file;
 
 	cookie.lo = lo;
-	cookie.data = bio_data(bio);
+	cookie.data = kmap(bvec->bv_page) + bvec->bv_offset;
 	cookie.bsize = bsize;
 	desc.written = 0;
-	desc.count = bio->bi_size;
+	desc.count = bvec->bv_len;
 	desc.buf = (char*)&cookie;
 	desc.error = 0;
 	spin_lock_irq(&lo->lo_lock);
 	file = lo->lo_backing_file;
 	spin_unlock_irq(&lo->lo_lock);
 	do_generic_file_read(file, &pos, &desc, lo_read_actor);
+	kunmap(bvec->bv_page);
 	return desc.error;
 }
 
+static int
+lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
+{
+	unsigned vecnr;
+	int ret = 0;
+
+	for (vecnr = 0; vecnr < bio->bi_vcnt; vecnr++) {
+		struct bio_vec *bvec = &bio->bi_io_vec[vecnr];
+
+		ret = do_lo_receive(lo, bvec, bsize, pos);
+		if (ret < 0)
+			break;
+		pos += bvec->bv_len;
+	}
+	return ret;
+}
+
 static inline int loop_get_bs(struct loop_device *lo)
 {
 	return block_size(lo->lo_device);
@@ -535,7 +577,9 @@
 	daemonize();
 
 	sprintf(current->comm, "loop%d", lo->lo_number);
-	current->flags |= PF_IOTHREAD;
+	current->flags |= PF_IOTHREAD;	/* loop can be used in an encrypted device
+					   hence, it mustn't be stopped at all because it could
+					   be indirectly used during suspension */
 
 	spin_lock_irq(&current->sigmask_lock);
 	sigfillset(&current->blocked);
diff -Nru a/drivers/block/nbd.c b/drivers/block/nbd.c
--- a/drivers/block/nbd.c	Wed May 29 11:43:02 2002
+++ b/drivers/block/nbd.c	Wed May 29 11:43:02 2002
@@ -323,7 +323,7 @@
 	int dev = 0;
 	struct nbd_device *lo;
 
-	while (!QUEUE_EMPTY) {
+	while (!blk_queue_empty(QUEUE)) {
 		req = CURRENT;
 #ifdef PARANOIA
 		if (!req)
diff -Nru a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
--- a/drivers/block/paride/pd.c	Wed May 29 11:43:02 2002
+++ b/drivers/block/paride/pd.c	Wed May 29 11:43:02 2002
@@ -877,10 +877,9 @@
 	
 /* paranoia */
 
-	if (QUEUE_EMPTY ||
+	if (blk_queue_empty(QUEUE) ||
 	    (rq_data_dir(CURRENT) != pd_cmd) ||
 	    (minor(CURRENT->rq_dev) != pd_dev) ||
-	    (CURRENT->rq_status == RQ_INACTIVE) ||
 	    (CURRENT->sector != pd_block)) 
 		printk("%s: OUCH: request list changed unexpectedly\n",
 			PD.name);
diff -Nru a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
--- a/drivers/block/paride/pf.c	Wed May 29 11:43:01 2002
+++ b/drivers/block/paride/pf.c	Wed May 29 11:43:01 2002
@@ -881,10 +881,9 @@
 	
 /* paranoia */
 
-	if (QUEUE_EMPTY ||
+	if (blk_queue_empty(QUEUE) ||
 	    (rq_data_dir(CURRENT) != pf_cmd) ||
 	    (DEVICE_NR(CURRENT->rq_dev) != pf_unit) ||
-	    (CURRENT->rq_status == RQ_INACTIVE) ||
 	    (CURRENT->sector != pf_block)) 
 		printk("%s: OUCH: request list changed unexpectedly\n",
 			PF.name);
diff -Nru a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
--- a/drivers/block/ps2esdi.c	Wed May 29 11:43:01 2002
+++ b/drivers/block/ps2esdi.c	Wed May 29 11:43:01 2002
@@ -466,7 +466,7 @@
 #if 0
 	printk("%s:got request. device : %d minor : %d command : %d  sector : %ld count : %ld, buffer: %p\n",
 	       DEVICE_NAME,
-	       CURRENT_DEV, minor(CURRENT->rq_dev),
+	       DEVICE_NR(CURRENT->rq_dev), minor(CURRENT->rq_dev),
 	       CURRENT->cmd, CURRENT->sector,
 	       CURRENT->current_nr_sectors, CURRENT->buffer);
 #endif
@@ -482,14 +482,14 @@
 		printk("%s: DMA above 16MB not supported\n", DEVICE_NAME);
 		end_request(FAIL);
 	}			/* check for above 16Mb dmas */
-	else if ((CURRENT_DEV < ps2esdi_drives) &&
+	else if ((DEVICE_NR(CURRENT->rq_dev) < ps2esdi_drives) &&
 	    (CURRENT->sector + CURRENT->current_nr_sectors <=
 	     ps2esdi[minor(CURRENT->rq_dev)].nr_sects) &&
 	    	CURRENT->flags & REQ_CMD) {
 #if 0
 		printk("%s:got request. device : %d minor : %d command : %d  sector : %ld count : %ld\n",
 		       DEVICE_NAME,
-		       CURRENT_DEV, minor(CURRENT->rq_dev),
+		       DEVICE_NR(CURRENT->rq_dev), minor(CURRENT->rq_dev),
 		       CURRENT->cmd, CURRENT->sector,
 		       CURRENT->current_nr_sectors);
 #endif
@@ -499,10 +499,10 @@
 
 		switch (rq_data_dir(CURRENT)) {
 		case READ:
-			ps2esdi_readwrite(READ, CURRENT_DEV, block, count);
+			ps2esdi_readwrite(READ, DEVICE_NR(CURRENT->rq_dev), block, count);
 			break;
 		case WRITE:
-			ps2esdi_readwrite(WRITE, CURRENT_DEV, block, count);
+			ps2esdi_readwrite(WRITE, DEVICE_NR(CURRENT->rq_dev), block, count);
 			break;
 		default:
 			printk("%s: Unknown command\n", DEVICE_NAME);
diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c
--- a/drivers/block/rd.c	Wed May 29 11:43:03 2002
+++ b/drivers/block/rd.c	Wed May 29 11:43:03 2002
@@ -379,6 +379,7 @@
 		rd_bdev[unit]->bd_openers++;
 		rd_bdev[unit]->bd_block_size = rd_blocksize;
 		rd_bdev[unit]->bd_inode->i_mapping->a_ops = &ramdisk_aops;
+		rd_bdev[unit]->bd_queue = &blk_dev[MAJOR_NR].request_queue;
 	}
 
 	return 0;
diff -Nru a/drivers/block/smart1,2.h b/drivers/block/smart1,2.h
--- a/drivers/block/smart1,2.h	Wed May 29 11:43:03 2002
+++ b/drivers/block/smart1,2.h	Wed May 29 11:43:03 2002
@@ -252,7 +252,9 @@
 
 		outb(CHANNEL_CLEAR, h->ioaddr + SMART1_LOCAL_DOORBELL);
 
-#error Please convert me to Documentation/DMA-mapping.txt
+		/*
+		 * this is x86 (actually compaq x86) only, so it's ok
+		 */
 		if (cmd) ((cmdlist_t*)bus_to_virt(cmd))->req.hdr.rcode = status;
 	} else {
 		cmd = 0;
diff -Nru a/drivers/block/swim3.c b/drivers/block/swim3.c
--- a/drivers/block/swim3.c	Wed May 29 11:43:02 2002
+++ b/drivers/block/swim3.c	Wed May 29 11:43:02 2002
@@ -313,7 +313,7 @@
 		wake_up(&fs->wait);
 		return;
 	}
-	while (!QUEUE_EMPTY && fs->state == idle) {
+	while (!blk_queue_empty(QUEUE) && fs->state == idle) {
 		if (major(CURRENT->rq_dev) != MAJOR_NR)
 			panic(DEVICE_NAME ": request list destroyed");
 //		if (CURRENT->bh && !buffer_locked(CURRENT->bh))
diff -Nru a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
--- a/drivers/block/swim_iop.c	Wed May 29 11:43:01 2002
+++ b/drivers/block/swim_iop.c	Wed May 29 11:43:01 2002
@@ -552,7 +552,7 @@
 		wake_up(&fs->wait);
 		return;
 	}
-	while (!QUEUE_EMPTY && fs->state == idle) {
+	while (!blk_queue_empty(QUEUE) && fs->state == idle) {
 		if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
 			panic(DEVICE_NAME ": request list destroyed");
 		if (CURRENT->bh && !buffer_locked(CURRENT->bh))
diff -Nru a/drivers/block/xd.c b/drivers/block/xd.c
--- a/drivers/block/xd.c	Wed May 29 11:43:02 2002
+++ b/drivers/block/xd.c	Wed May 29 11:43:02 2002
@@ -286,7 +286,7 @@
 			return;
 		}
 
-		if (CURRENT_DEV < xd_drives
+		if (DEVICE_NR(CURRENT->rq_dev) < xd_drives
 		    && (CURRENT->flags & REQ_CMD)
 		    && CURRENT->sector + CURRENT->nr_sectors
 		         <= xd_struct[minor(CURRENT->rq_dev)].nr_sects) {
@@ -297,7 +297,8 @@
 				case READ:
 				case WRITE:
 					for (retry = 0; (retry < XD_RETRIES) && !code; retry++)
-						code = xd_readwrite(rq_data_dir(CURRENT),CURRENT_DEV,CURRENT->buffer,block,count);
+						code = xd_readwrite(rq_data_dir(CURRENT),DEVICE_NR(CURRENT->rq_dev),
+							CURRENT->buffer,block,count);
 					break;
 				default:
 					printk("do_xd_request: unknown request\n");
diff -Nru a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
--- a/drivers/bluetooth/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/bluetooth/Makefile	Wed May 29 11:43:02 2002
@@ -2,21 +2,14 @@
 # Makefile for Bluetooth HCI device drivers.
 #
 
-O_TARGET	:= bluetooth.o
-
-list-multi	:= hci_uart.o
-
 obj-$(CONFIG_BLUEZ_HCIUSB)	+= hci_usb.o
 obj-$(CONFIG_BLUEZ_HCIVHCI)	+= hci_vhci.o
-
 obj-$(CONFIG_BLUEZ_HCIUART)	+= hci_uart.o
-uart-y				:= hci_ldisc.o
-uart-$(CONFIG_BLUEZ_HCIUART_H4)	+= hci_h4.o
-
 obj-$(CONFIG_BLUEZ_HCIDTL1)	+= dtl1_cs.o
 obj-$(CONFIG_BLUEZ_HCIBLUECARD)	+= bluecard_cs.o
 
-include $(TOPDIR)/Rules.make
+hci_uart-y				:= hci_ldisc.o
+hci_uart-$(CONFIG_BLUEZ_HCIUART_H4)	+= hci_h4.o
+hci_uart-objs				:= $(hci_uart-y)
 
-hci_uart.o: $(uart-y)
-	$(LD) -r -o $@ $(uart-y)
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/cdrom/Makefile b/drivers/cdrom/Makefile
--- a/drivers/cdrom/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/cdrom/Makefile	Wed May 29 11:43:03 2002
@@ -3,9 +3,6 @@
 # 30 Jan 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net>
 # Rewritten to use lists instead of if-statements.
 
-O_TARGET	:= driver.o
-
-
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
diff -Nru a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
--- a/drivers/cdrom/aztcd.c	Wed May 29 11:43:03 2002
+++ b/drivers/cdrom/aztcd.c	Wed May 29 11:43:03 2002
@@ -226,9 +226,13 @@
 #define AZT_DEBUG_MULTISESSION
 #endif
 
-#define CURRENT_VALID \
-  (!QUEUE_EMPTY && major(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
-   && CURRENT -> sector != -1)
+static int current_valid(void)
+{
+        return !blk_queue_empty(QUEUE) &&
+	        major(CURRENT->rq_dev) == MAJOR_NR &&
+		CURRENT->cmd == READ &&
+		CURRENT->sector != -1;
+}
 
 #define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA)
 #define AZT_BUF_SIZ 16
@@ -1554,34 +1558,33 @@
 #ifdef AZT_TEST
 	printk("aztcd: executing azt_transfer Time:%li\n", jiffies);
 #endif
-	if (CURRENT_VALID) {
-		while (CURRENT->nr_sectors) {
-			int bn = CURRENT->sector / 4;
-			int i;
-			for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn;
-			     ++i);
-			if (i < AZT_BUF_SIZ) {
-				int offs =
-				    (i * 4 + (CURRENT->sector & 3)) * 512;
-				int nr_sectors = 4 - (CURRENT->sector & 3);
-				if (azt_buf_out != i) {
-					azt_buf_out = i;
-					if (azt_buf_bn[i] != bn) {
-						azt_buf_out = -1;
-						continue;
-					}
-				}
-				if (nr_sectors > CURRENT->nr_sectors)
-					nr_sectors = CURRENT->nr_sectors;
-				memcpy(CURRENT->buffer, azt_buf + offs,
-				       nr_sectors * 512);
-				CURRENT->nr_sectors -= nr_sectors;
-				CURRENT->sector += nr_sectors;
-				CURRENT->buffer += nr_sectors * 512;
-			} else {
-				azt_buf_out = -1;
-				break;
-			}
+	if (!current_valid())
+	        return;
+
+	while (CURRENT->nr_sectors) {
+		int bn = CURRENT->sector / 4;
+		int i;
+		for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn; ++i);
+		if (i < AZT_BUF_SIZ) {
+			int offs = (i * 4 + (CURRENT->sector & 3)) * 512;
+			int nr_sectors = 4 - (CURRENT->sector & 3);
+			if (azt_buf_out != i) {
+				azt_buf_out = i;
+				if (azt_buf_bn[i] != bn) {
+					azt_buf_out = -1;
+					continue;
+				}
+			}
+			if (nr_sectors > CURRENT->nr_sectors)
+			    nr_sectors = CURRENT->nr_sectors;
+			memcpy(CURRENT->buffer, azt_buf + offs,
+				nr_sectors * 512);
+			CURRENT->nr_sectors -= nr_sectors;
+			CURRENT->sector += nr_sectors;
+			CURRENT->buffer += nr_sectors * 512;
+		} else {
+			azt_buf_out = -1;
+			break;
 		}
 	}
 }
@@ -1598,7 +1601,7 @@
 		return;
 	}
 	azt_transfer_is_active = 1;
-	while (CURRENT_VALID) {
+	while (current_valid()) {
 		azt_transfer();
 		if (CURRENT->nr_sectors == 0) {
 			end_request(1);
@@ -1607,7 +1610,7 @@
 			if (azt_state == AZT_S_IDLE) {
 				if ((!aztTocUpToDate) || aztDiskChanged) {
 					if (aztUpdateToc() < 0) {
-						while (CURRENT_VALID)
+						while (current_valid())
 							end_request(0);
 						break;
 					}
@@ -1991,7 +1994,7 @@
 				AztTries = 0;
 				loop_ctl = 0;
 			}
-			if (CURRENT_VALID)
+			if (current_valid())
 				end_request(0);
 			AztTries = 5;
 		}
@@ -2065,7 +2068,7 @@
 					break;
 				}
 				azt_state = AZT_S_IDLE;
-				while (CURRENT_VALID)
+				while (current_valid())
 					end_request(0);
 				return;
 			}
@@ -2120,12 +2123,12 @@
 					break;
 				}
 				azt_state = AZT_S_IDLE;
-				while (CURRENT_VALID)
+				while (current_valid())
 					end_request(0);
 				return;
 			}
 
-			if (CURRENT_VALID) {
+			if (current_valid()) {
 				struct azt_Play_msf msf;
 				int i;
 				azt_next_bn = CURRENT->sector / 4;
@@ -2218,7 +2221,7 @@
 						AztTries = 0;
 						break;
 					}
-					if (CURRENT_VALID)
+					if (current_valid())
 						end_request(0);
 					AztTries = 5;
 				}
@@ -2246,8 +2249,7 @@
 				}
 #endif
 				AztTries = 5;
-				if (!CURRENT_VALID
-				    && azt_buf_in == azt_buf_out) {
+				if (!current_valid() && azt_buf_in == azt_buf_out) {
 					azt_state = AZT_S_STOP;
 					loop_ctl = 1;
 					break;
@@ -2319,7 +2321,7 @@
 					}
 				}
 				if (!azt_transfer_is_active) {
-					while (CURRENT_VALID) {
+					while (current_valid()) {
 						azt_transfer();
 						if (CURRENT->nr_sectors ==
 						    0)
@@ -2329,7 +2331,7 @@
 					}
 				}
 
-				if (CURRENT_VALID
+				if (current_valid()
 				    && (CURRENT->sector / 4 < azt_next_bn
 					|| CURRENT->sector / 4 >
 					azt_next_bn + AZT_BUF_SIZ)) {
@@ -2403,10 +2405,10 @@
 
 #ifdef AZT_TEST3
 			printk("CURRENT_VALID %d azt_mode %d\n",
-			       CURRENT_VALID, azt_mode);
+			       current_valid(), azt_mode);
 #endif
 
-			if (CURRENT_VALID) {
+			if (current_valid()) {
 				if (st != -1) {
 					if (azt_mode == 1) {
 						azt_state = AZT_S_READ;
diff -Nru a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
--- a/drivers/cdrom/cdu31a.c	Wed May 29 11:43:02 2002
+++ b/drivers/cdrom/cdu31a.c	Wed May 29 11:43:02 2002
@@ -1563,11 +1563,6 @@
 		interruptible_sleep_on(&sony_wait);
 		if (signal_pending(current)) {
 			restore_flags(flags);
-			if (!QUEUE_EMPTY
-			    && CURRENT->rq_status != RQ_INACTIVE) {
-				end_request(0);
-			}
-			restore_flags(flags);
 #if DEBUG
 			printk("Leaving do_cdu31a_request at %d\n",
 			       __LINE__);
diff -Nru a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
--- a/drivers/cdrom/gscd.c	Wed May 29 11:43:01 2002
+++ b/drivers/cdrom/gscd.c	Wed May 29 11:43:01 2002
@@ -288,7 +288,7 @@
 	block = CURRENT->sector;
 	nsect = CURRENT->nr_sectors;
 
-	if (QUEUE_EMPTY || CURRENT->sector == -1)
+	if (CURRENT->sector == -1)
 		goto out;
 
 	if (CURRENT->cmd != READ) {
diff -Nru a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
--- a/drivers/cdrom/mcd.c	Wed May 29 11:43:01 2002
+++ b/drivers/cdrom/mcd.c	Wed May 29 11:43:01 2002
@@ -119,9 +119,13 @@
 #define QUICK_LOOP_DELAY udelay(45)	/* use udelay */
 #define QUICK_LOOP_COUNT 20
 
-#define CURRENT_VALID \
-(!QUEUE_EMPTY && major(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
-&& CURRENT -> sector != -1)
+static int current_valid(void)
+{
+        return !blk_queue_empty(QUEUE) &&
+	        major(CURRENT->rq_dev) == MAJOR_NR &&
+		CURRENT->cmd == READ &&
+		CURRENT->sector != -1;
+}
 
 #define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
 #define MCD_BUF_SIZ 16
@@ -556,33 +560,33 @@
 
 static void mcd_transfer(void)
 {
-	if (CURRENT_VALID) {
-		while (CURRENT->nr_sectors) {
-			int bn = CURRENT->sector / 4;
-			int i;
-			for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn;
-			     ++i);
-			if (i < MCD_BUF_SIZ) {
-				int offs =(i * 4 + (CURRENT->sector & 3)) * 512;
-				int nr_sectors = 4 - (CURRENT->sector & 3);
-				if (mcd_buf_out != i) {
-					mcd_buf_out = i;
-					if (mcd_buf_bn[i] != bn) {
-						mcd_buf_out = -1;
-						continue;
-					}
+	if (!current_valid())
+		return;
+
+	while (CURRENT->nr_sectors) {
+		int bn = CURRENT->sector / 4;
+		int i;
+		for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn; ++i)
+			;
+		if (i < MCD_BUF_SIZ) {
+			int offs =(i * 4 + (CURRENT->sector & 3)) * 512;
+			int nr_sectors = 4 - (CURRENT->sector & 3);
+			if (mcd_buf_out != i) {
+				mcd_buf_out = i;
+				if (mcd_buf_bn[i] != bn) {
+					mcd_buf_out = -1;
+					continue;
 				}
-				if (nr_sectors > CURRENT->nr_sectors)
-					nr_sectors = CURRENT->nr_sectors;
-				memcpy(CURRENT->buffer, mcd_buf + offs,
-				       nr_sectors * 512);
-				CURRENT->nr_sectors -= nr_sectors;
-				CURRENT->sector += nr_sectors;
-				CURRENT->buffer += nr_sectors * 512;
-			} else {
-				mcd_buf_out = -1;
-				break;
 			}
+			if (nr_sectors > CURRENT->nr_sectors)
+				nr_sectors = CURRENT->nr_sectors;
+			memcpy(CURRENT->buffer, mcd_buf + offs, nr_sectors * 512);
+			CURRENT->nr_sectors -= nr_sectors;
+			CURRENT->sector += nr_sectors;
+			CURRENT->buffer += nr_sectors * 512;
+		} else {
+		        mcd_buf_out = -1;
+			break;
 		}
 	}
 }
@@ -614,7 +618,7 @@
 	       CURRENT->nr_sectors));
 
 		mcd_transfer_is_active = 1;
-	while (CURRENT_VALID) {
+	while (current_valid()) {
 		mcd_transfer();
 		if (CURRENT->nr_sectors == 0) {
 			end_request(1);
@@ -623,7 +627,7 @@
 			if (mcd_state == MCD_S_IDLE) {
 				if (!tocUpToDate) {
 					if (updateToc() < 0) {
-						while (CURRENT_VALID)
+						while (current_valid())
 							end_request(0);
 						break;
 					}
@@ -688,7 +692,7 @@
 					McdTries = 0;
 					goto ret;
 				}
-				if (CURRENT_VALID)
+				if (current_valid())
 					end_request(0);
 				McdTries = MCD_RETRY_ATTEMPTS;
 			}
@@ -745,7 +749,7 @@
 				       "mcd: door open\n" :
 				       "mcd: disk removed\n");
 				mcd_state = MCD_S_IDLE;
-				while (CURRENT_VALID)
+				while (current_valid())
 					end_request(0);
 				goto out;
 			}
@@ -779,12 +783,12 @@
 				       "mcd: door open\n" :
 				       "mcd: disk removed\n");
 				mcd_state = MCD_S_IDLE;
-				while (CURRENT_VALID)
+				while (current_valid())
 					end_request(0);
 				goto out;
 			}
 
-			if (CURRENT_VALID) {
+			if (current_valid()) {
 				struct mcd_Play_msf msf;
 				mcd_next_bn = CURRENT->sector / 4;
 				hsg2msf(mcd_next_bn, &msf.start);
@@ -820,7 +824,7 @@
 					McdTries = 0;
 					break;
 				}
-				if (CURRENT_VALID)
+				if (current_valid())
 					end_request(0);
 				McdTries = 5;
 			}
@@ -833,7 +837,7 @@
 
 		default:
 			McdTries = 5;
-			if (!CURRENT_VALID && mcd_buf_in == mcd_buf_out) {
+			if (!current_valid() && mcd_buf_in == mcd_buf_out) {
 				mcd_state = MCD_S_STOP;
 				goto immediately;
 			}
@@ -845,7 +849,7 @@
 				mcd_buf_out = mcd_buf_in;
 			mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
 			if (!mcd_transfer_is_active) {
-				while (CURRENT_VALID) {
+				while (current_valid()) {
 					mcd_transfer();
 					if (CURRENT->nr_sectors == 0)
 						end_request(1);
@@ -854,7 +858,7 @@
 				}
 			}
 
-			if (CURRENT_VALID
+			if (current_valid()
 			    && (CURRENT->sector / 4 < mcd_next_bn ||
 				CURRENT->sector / 4 > mcd_next_bn + 16)) {
 				mcd_state = MCD_S_STOP;
@@ -933,8 +937,9 @@
 		st = -1;
 
 do_not_work_around_mitsumi_bug_93_2:
-		test3(printk("CURRENT_VALID %d mcd_mode %d\n", CURRENT_VALID, mcd_mode));
-		if (CURRENT_VALID) {
+		test3(printk("CURRENT_VALID %d mcd_mode %d\n", current_valid(),
+			    mcd_mode));
+		if (current_valid()) {
 			if (st != -1) {
 				if (mcd_mode == 1)
 					goto read_immediately;
diff -Nru a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
--- a/drivers/cdrom/optcd.c	Wed May 29 11:43:02 2002
+++ b/drivers/cdrom/optcd.c	Wed May 29 11:43:02 2002
@@ -973,11 +973,13 @@
 
 /* Request handling */
 
-
-#define CURRENT_VALID \
-	(!QUEUE_EMPTY && major(CURRENT -> rq_dev) == MAJOR_NR \
-	 && CURRENT -> cmd == READ && CURRENT -> sector != -1)
-
+static int current_valid(void)
+{
+        return !blk_queue_empty(QUEUE) &&
+	        major(CURRENT->rq_dev) == MAJOR_NR &&
+		CURRENT->cmd == READ &&
+		CURRENT->sector != -1;
+}
 
 /* Buffers for block size conversion. */
 #define NOBUF		-1
@@ -1006,7 +1008,7 @@
 	printk(KERN_DEBUG "optcd: executing transfer\n");
 #endif
 
-	if (!CURRENT_VALID)
+	if (!current_valid())
 		return;
 	while (CURRENT -> nr_sectors) {
 		int bn = CURRENT -> sector / 4;
@@ -1092,7 +1094,7 @@
 				" Giving up\n", next_bn);
 			if (transfer_is_active)
 				loop_again = 0;
-			if (CURRENT_VALID)
+			if (current_valid())
 				end_request(0);
 			tries = 5;
 		}
@@ -1126,7 +1128,7 @@
 				break;
 			if (send_cmd(COMDRVST)) {
 				state = S_IDLE;
-				while (CURRENT_VALID)
+				while (current_valid())
 					end_request(0);
 				return;
 			}
@@ -1153,11 +1155,11 @@
 					? "door open"
 					: "disk removed");
 				state = S_IDLE;
-				while (CURRENT_VALID)
+				while (current_valid())
 					end_request(0);
 				return;
 			}
-			if (!CURRENT_VALID) {
+			if (!current_valid()) {
 				state = S_STOP;
 				loop_again = 1;
 				break;
@@ -1208,7 +1210,7 @@
 						tries = 0;
 						break;
 					}
-					if (CURRENT_VALID)
+					if (current_valid())
 						end_request(0);
 					tries = 5;
 				}
@@ -1219,7 +1221,7 @@
 				break;
 			default:	/* DTEN low */
 				tries = 5;
-				if (!CURRENT_VALID && buf_in == buf_out) {
+				if (!current_valid() && buf_in == buf_out) {
 					state = S_STOP;
 					loop_again = 1;
 					break;
@@ -1272,7 +1274,7 @@
 						N_BUFS ? 0 : buf_in + 1;
 				}
 				if (!transfer_is_active) {
-					while (CURRENT_VALID) {
+					while (current_valid()) {
 						transfer();
 						if (CURRENT -> nr_sectors == 0)
 							end_request(1);
@@ -1281,7 +1283,7 @@
 					}
 				}
 
-				if (CURRENT_VALID
+				if (current_valid()
 				    && (CURRENT -> sector / 4 < next_bn ||
 				    CURRENT -> sector / 4 >
 				     next_bn + N_BUFS)) {
@@ -1305,7 +1307,7 @@
 			flush_data();
 			if (send_cmd(COMDRVST)) {
 				state = S_IDLE;
-				while (CURRENT_VALID)
+				while (current_valid())
 					end_request(0);
 				return;
 			}
@@ -1320,7 +1322,7 @@
 				toc_uptodate = 0;
 				opt_invalidate_buffers();
 			}
-			if (CURRENT_VALID) {
+			if (current_valid()) {
 				if (status >= 0) {
 					state = S_READ;
 					loop_again = 1;
@@ -1346,7 +1348,7 @@
 		state = S_STOP;
 		if (exec_cmd(COMSTOP) < 0) {
 			state = S_IDLE;
-			while (CURRENT_VALID)
+			while (current_valid())
 				end_request(0);
 			return;
 		}
@@ -1368,7 +1370,7 @@
 	}
 
 	transfer_is_active = 1;
-	while (CURRENT_VALID) {
+	while (current_valid()) {
 		transfer();	/* First try to transfer block from buffers */
 		if (CURRENT -> nr_sectors == 0) {
 			end_request(1);
@@ -1377,7 +1379,7 @@
 			if (state == S_IDLE) {
 				/* %% Should this block the request queue?? */
 				if (update_toc() < 0) {
-					while (CURRENT_VALID)
+					while (current_valid())
 						end_request(0);
 					break;
 				}
diff -Nru a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
--- a/drivers/cdrom/sbpcd.c	Wed May 29 11:43:02 2002
+++ b/drivers/cdrom/sbpcd.c	Wed May 29 11:43:02 2002
@@ -4902,7 +4902,7 @@
 #ifdef DEBUG_GTL
 	xnr=++xx_nr;
 
-	if(QUEUE_EMPTY)
+	if(blk_queue_empty(QUEUE))
 	{
 		printk( "do_sbpcd_request[%di](NULL), Pid:%d, Time:%li\n",
 			xnr, current->pid, jiffies);
diff -Nru a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
--- a/drivers/cdrom/sjcd.c	Wed May 29 11:43:03 2002
+++ b/drivers/cdrom/sjcd.c	Wed May 29 11:43:03 2002
@@ -1074,16 +1074,20 @@
  * When Linux gets variable block sizes this will probably go away.
  */
 
-#define CURRENT_IS_VALID                                      \
-    ( !QUEUE_EMPTY && major( CURRENT->rq_dev ) == MAJOR_NR && \
-      CURRENT->cmd == READ && CURRENT->sector != -1 )
+static int current_valid(void)
+{
+        return !blk_queue_empty(QUEUE) &&
+	        major(CURRENT->rq_dev) == MAJOR_NR &&
+		CURRENT->cmd == READ &&
+		CURRENT->sector != -1;
+}
 
 static void sjcd_transfer(void)
 {
 #if defined( SJCD_TRACE )
 	printk("SJCD: transfer:\n");
 #endif
-	if (CURRENT_IS_VALID) {
+	if (current_valid()) {
 		while (CURRENT->nr_sectors) {
 			int i, bn = CURRENT->sector / 4;
 			for (i = 0;
@@ -1239,7 +1243,7 @@
 					}
 				}
 
-				if (CURRENT_IS_VALID) {
+				if (current_valid()) {
 					struct sjcd_play_msf msf;
 
 					sjcd_next_bn = CURRENT->sector / 4;
@@ -1307,7 +1311,7 @@
 					    ("SJCD: read block %d failed, maybe audio disk? Giving up\n",
 					     sjcd_next_bn);
 #endif
-					if (CURRENT_IS_VALID)
+					if (current_valid())
 						end_request(0);
 #if defined( SJCD_TRACE )
 					printk
@@ -1332,7 +1336,7 @@
 				 * Otherwise cdrom hangs up. Check to see if we have something to copy
 				 * to.
 				 */
-				if (!CURRENT_IS_VALID
+				if (!current_valid()
 				    && sjcd_buf_in == sjcd_buf_out) {
 #if defined( SJCD_TRACE )
 					printk
@@ -1373,7 +1377,7 @@
 					 * OK, request seems to be precessed. Continue transferring...
 					 */
 					if (!sjcd_transfer_is_active) {
-						while (CURRENT_IS_VALID) {
+						while (current_valid()) {
 							/*
 							 * Continue transferring.
 							 */
@@ -1387,7 +1391,7 @@
 								break;
 						}
 					}
-					if (CURRENT_IS_VALID &&
+					if (current_valid() &&
 					    (CURRENT->sector / 4 <
 					     sjcd_next_bn
 					     || CURRENT->sector / 4 >
@@ -1450,7 +1454,7 @@
 					sjcd_toc_uptodate = 0;
 					sjcd_invalidate_buffers();
 				}
-				if (CURRENT_IS_VALID) {
+				if (current_valid()) {
 					if (sjcd_status_valid)
 						sjcd_transfer_state =
 						    SJCD_S_READ;
@@ -1476,7 +1480,7 @@
 
 	if (--sjcd_transfer_timeout == 0) {
 		printk("SJCD: timeout in state %d\n", sjcd_transfer_state);
-		while (CURRENT_IS_VALID)
+		while (current_valid())
 			end_request(0);
 		sjcd_send_cmd(SCMD_STOP);
 		sjcd_transfer_state = SJCD_S_IDLE;
@@ -1497,7 +1501,7 @@
 	       CURRENT->sector, CURRENT->nr_sectors);
 #endif
 	sjcd_transfer_is_active = 1;
-	while (CURRENT_IS_VALID) {
+	while (current_valid()) {
 		sjcd_transfer();
 		if (CURRENT->nr_sectors == 0)
 			end_request(1);
@@ -1508,7 +1512,7 @@
 					if (sjcd_update_toc() < 0) {
 						printk
 						    ("SJCD: transfer: discard\n");
-						while (CURRENT_IS_VALID)
+						while (current_valid())
 							end_request(0);
 						break;
 					}
diff -Nru a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
--- a/drivers/cdrom/sonycd535.c	Wed May 29 11:43:02 2002
+++ b/drivers/cdrom/sonycd535.c	Wed May 29 11:43:02 2002
@@ -1486,6 +1486,7 @@
 	int  got_result = 0;
 	int  tmp_irq;
 	int  i;
+	devfs_handle_t sony_devfs_handle;
 
 	/* Setting the base I/O address to 0 will disable it. */
 	if ((sony535_cd_base_io == 0xffff)||(sony535_cd_base_io == 0))
@@ -1509,11 +1510,6 @@
 	printk(KERN_INFO CDU535_MESSAGE_NAME ": probing base address %03X\n",
 			sony535_cd_base_io);
 #endif
-	if (check_region(sony535_cd_base_io,4)) {
-		printk(CDU535_MESSAGE_NAME ": my base address is not free!\n");
-		return -EIO;
-	}
-
 	/* look for the CD-ROM, follows the procedure in the DOS driver */
 	inb(select_unit_reg);
 	/* wait for 40 18 Hz ticks (reverse-engineered from DOS driver) */
@@ -1586,13 +1582,14 @@
 					printk("IRQ%d, ", tmp_irq);
 				printk("using %d byte buffer\n", sony_buffer_size);
 
-				devfs_register (NULL, CDU535_HANDLE,
-						DEVFS_FL_DEFAULT,
-						MAJOR_NR, 0,
-						S_IFBLK | S_IRUGO | S_IWUGO,
-						&cdu_fops, NULL);
+				sony_devfs_handle = devfs_register (NULL, CDU535_HANDLE,
+								DEVFS_FL_DEFAULT,
+								MAJOR_NR, 0,
+								S_IFBLK | S_IRUGO | S_IWUGO,
+								&cdu_fops, NULL);
 				if (devfs_register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) {
 					printk("Unable to get major %d for %s\n",
+					devfs_unregister(sony_devfs_handle);
 							MAJOR_NR, CDU535_MESSAGE_NAME);
 					return -EIO;
 				}
@@ -1604,6 +1601,8 @@
 					kmalloc(sizeof *sony_toc, GFP_KERNEL);
 				if (sony_toc == NULL) {
 					blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+					devfs_unregister_blkdev(MAJOR_NR, CDU535_HANDLE);
+					devfs_unregister(sony_devfs_handle);
 					return -ENOMEM;
 				}
 				last_sony_subcode = (struct s535_sony_subcode *)
@@ -1611,6 +1610,8 @@
 				if (last_sony_subcode == NULL) {
 					blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 					kfree(sony_toc);
+					devfs_unregister_blkdev(MAJOR_NR, CDU535_HANDLE);
+					devfs_unregister(sony_devfs_handle);
 					return -ENOMEM;
 				}
 				sony_buffer = (Byte **)
@@ -1619,6 +1620,8 @@
 					blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 					kfree(sony_toc);
 					kfree(last_sony_subcode);
+					devfs_unregister_blkdev(MAJOR_NR, CDU535_HANDLE);
+					devfs_unregister(sony_devfs_handle);
 					return -ENOMEM;
 				}
 				for (i = 0; i < sony_buffer_sectors; i++) {
@@ -1631,6 +1634,8 @@
 						kfree(sony_buffer);
 						kfree(sony_toc);
 						kfree(last_sony_subcode);
+						devfs_unregister_blkdev(MAJOR_NR, CDU535_HANDLE);
+						devfs_unregister(sony_devfs_handle);
 						return -ENOMEM;
 					}
 				}
@@ -1643,7 +1648,25 @@
 		printk("Did not find a " CDU535_MESSAGE_NAME " drive\n");
 		return -EIO;
 	}
-	request_region(sony535_cd_base_io, 4, CDU535_HANDLE);
+	if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE))
+		{
+		printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n",
+			sony535_cd_base_io);
+		for (i = 0; i < sony_buffer_sectors; i++)
+			if (sony_buffer[i]) 
+				kfree(sony_buffer[i]);
+		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+		kfree(sony_buffer);
+		kfree(sony_toc);
+		kfree(last_sony_subcode);
+		devfs_unregister_blkdev(MAJOR_NR, CDU535_HANDLE);
+		devfs_unregister(sony_devfs_handle);
+		if (sony535_irq_used)
+			free_irq(sony535_irq_used, NULL);
+		}
+	
+		return -EIO;
+		}
 	register_disk(NULL, mk_kdev(MAJOR_NR,0), 1, &cdu_fops, 0);
 	return 0;
 }
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/char/Makefile	Wed May 29 11:43:02 2002
@@ -7,8 +7,6 @@
 #
 FONTMAPFILE = cp437.uni
 
-O_TARGET := char.o
-
 obj-y	 += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o
 
 # All of the (potential) objects that export symbols.
diff -Nru a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
--- a/drivers/char/drm/radeon_cp.c	Wed May 29 11:43:02 2002
+++ b/drivers/char/drm/radeon_cp.c	Wed May 29 11:43:02 2002
@@ -459,6 +459,7 @@
 	RADEON_WAIT_UNTIL_IDLE();
 
 	ADVANCE_RING();
+	COMMIT_RING();
 
 	return radeon_do_wait_for_idle( dev_priv );
 }
@@ -483,6 +484,7 @@
 	RADEON_WAIT_UNTIL_IDLE();
 
 	ADVANCE_RING();
+	COMMIT_RING();
 }
 
 /* Reset the Command Processor.  This will not flush any pending
diff -Nru a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
--- a/drivers/char/drm/radeon_drv.h	Wed May 29 11:43:03 2002
+++ b/drivers/char/drm/radeon_drv.h	Wed May 29 11:43:03 2002
@@ -714,6 +714,7 @@
 			   n, __FUNCTION__ );				\
 	}								\
 	if ( dev_priv->ring.space <= (n) * sizeof(u32) ) {		\
+                COMMIT_RING();						\
 		radeon_wait_ring( dev_priv, (n) * sizeof(u32) );	\
 	}								\
 	_nr = n; dev_priv->ring.space -= (n) * sizeof(u32);		\
@@ -727,7 +728,6 @@
 		DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n",	\
 			  write, dev_priv->ring.tail );			\
 	}								\
-	radeon_flush_write_combine();					\
 	if (((dev_priv->ring.tail + _nr) & mask) != write) {		\
 		DRM_ERROR( 						\
 			"ADVANCE_RING(): mismatch: nr: %x write: %x\n",	\
@@ -735,7 +735,10 @@
 			write);						\
 	} else								\
 		dev_priv->ring.tail = write;				\
-	RADEON_WRITE( RADEON_CP_RB_WPTR, write );			\
+} while (0)
+
+#define COMMIT_RING() do {					    \
+	RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail );		    \
 } while (0)
 
 #define OUT_RING( x ) do {						\
@@ -751,6 +754,30 @@
 	OUT_RING( CP_PACKET0( reg, 0 ) );				\
 	OUT_RING( val );						\
 } while (0)
+
+
+#define OUT_RING_USER_TABLE( tab, sz ) do {			\
+	int _size = (sz);					\
+	int *_tab = (tab);					\
+								\
+	if (write + _size > mask) {				\
+		int i = (mask+1) - write;			\
+		if (__copy_from_user( (int *)(ring+write),	\
+				      _tab, i*4 ))		\
+			return -EFAULT;				\
+		write = 0;					\
+		_size -= i;					\
+		_tab += i;					\
+	}							\
+								\
+	if (_size && __copy_from_user( (int *)(ring+write),	\
+			               _tab, _size*4 ))		\
+		return -EFAULT;					\
+								\
+	write += _size;						\
+	write &= mask;						\
+} while (0)
+
 
 #define RADEON_PERFORMANCE_BOXES	0
 
diff -Nru a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
--- a/drivers/char/drm/radeon_state.c	Wed May 29 11:43:02 2002
+++ b/drivers/char/drm/radeon_state.c	Wed May 29 11:43:02 2002
@@ -1058,6 +1058,7 @@
 
 	radeon_cp_dispatch_clear( dev, &clear, depth_boxes );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1118,6 +1119,7 @@
 		
 	radeon_cp_dispatch_flip( dev );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1140,6 +1142,7 @@
 	radeon_cp_dispatch_swap( dev );
 	dev_priv->sarea_priv->ctx_owner = 0;
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1228,6 +1231,7 @@
 		radeon_cp_discard_buffer( dev, buf );
 	}
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1328,6 +1332,7 @@
 		radeon_cp_discard_buffer( dev, buf );
 	}
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1339,6 +1344,7 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_texture_t tex;
 	drm_radeon_tex_image_t image;
+	int ret;
 
 	LOCK_TEST_WITH_RETURN( dev );
 
@@ -1358,7 +1364,10 @@
 	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 	VB_AGE_TEST_WITH_RETURN( dev_priv );
 
-	return radeon_cp_dispatch_texture( dev, &tex, &image );
+	ret = radeon_cp_dispatch_texture( dev, &tex, &image );
+
+	COMMIT_RING();
+	return ret;
 }
 
 int radeon_cp_stipple( struct inode *inode, struct file *filp,
@@ -1383,6 +1392,7 @@
 
 	radeon_cp_dispatch_stipple( dev, mask );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1460,6 +1470,7 @@
 	}
 
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1564,6 +1575,7 @@
 		radeon_cp_discard_buffer( dev, buf );
 	}
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1575,19 +1587,16 @@
 {
 	int sz = packet[(int)header.packet.packet_id].len;
 	int reg = packet[(int)header.packet.packet_id].start;
-	int i, tmp, *data = (int *)cmdbuf->buf;
+	int *data = (int *)cmdbuf->buf;
 	RING_LOCALS;
    
 	if (sz * sizeof(int) > cmdbuf->bufsz) 
 		return -EINVAL;
 
-	BEGIN_RING( (sz+1) );
+
+	BEGIN_RING(sz+1);
 	OUT_RING( CP_PACKET0( reg, (sz-1) ) );
-	for ( i = 0 ; i < sz ; i++ ) {
-		if (__get_user( tmp, &data[i] ))
-			return -EFAULT;
-		OUT_RING( tmp );
-	}
+	OUT_RING_USER_TABLE( data, sz );
 	ADVANCE_RING();
 
 	cmdbuf->buf += sz * sizeof(int);
@@ -1601,7 +1610,7 @@
 	drm_radeon_cmd_buffer_t *cmdbuf )
 {
 	int sz = header.scalars.count;
-	int i, tmp, *data = (int *)cmdbuf->buf;
+	int *data = (int *)cmdbuf->buf;
 	int start = header.scalars.offset;
 	int stride = header.scalars.stride;
 	RING_LOCALS;
@@ -1610,11 +1619,7 @@
 	OUT_RING( CP_PACKET0( RADEON_SE_TCL_SCALAR_INDX_REG, 0 ) );
 	OUT_RING( start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
 	OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_SCALAR_DATA_REG, sz-1 ) );
-	for ( i = 0 ; i < sz ; i++ ) {
-		if (__get_user( tmp, &data[i] ))
-			return -EFAULT;
-		OUT_RING( tmp );
-	}	
+	OUT_RING_USER_TABLE( data, sz );
 	ADVANCE_RING();
 	cmdbuf->buf += sz * sizeof(int);
 	cmdbuf->bufsz -= sz * sizeof(int);
@@ -1627,7 +1632,7 @@
 	drm_radeon_cmd_buffer_t *cmdbuf )
 {
 	int sz = header.vectors.count;
-	int i, tmp, *data = (int *)cmdbuf->buf;
+	int *data = (int *)cmdbuf->buf;
 	int start = header.vectors.offset;
 	int stride = header.vectors.stride;
 	RING_LOCALS;
@@ -1636,11 +1641,7 @@
 	OUT_RING( CP_PACKET0( RADEON_SE_TCL_VECTOR_INDX_REG, 0 ) );
 	OUT_RING( start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
 	OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_VECTOR_DATA_REG, (sz-1) ) );
-	for ( i = 0 ; i < sz ; i++ ) {
-		if (__get_user( tmp, &data[i] ))
-			return -EFAULT;
-		OUT_RING( tmp );
-	}	
+	OUT_RING_USER_TABLE( data, sz );
 	ADVANCE_RING();
 
 	cmdbuf->buf += sz * sizeof(int);
@@ -1655,9 +1656,9 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	int cmdsz, tmp;
 	int *cmd = (int *)cmdbuf->buf;
-	int j;
 	RING_LOCALS;
 
+
 	DRM_DEBUG("%s\n", __FUNCTION__);
 
 	if (__get_user( tmp, &cmd[0]))
@@ -1669,14 +1670,8 @@
 	    cmdsz * 4 > cmdbuf->bufsz)
 		return -EINVAL;
 
-
 	BEGIN_RING( cmdsz );
-	for (j = 0 ; j < cmdsz ; j++) {
-		if (__get_user( tmp, &cmd[j] ))
-			return -EFAULT;
-/*  		printk( "pk3 %d: %x\n", j, tmp); */
-		OUT_RING( tmp );
-	}
+	OUT_RING_USER_TABLE( cmd, cmdsz );
 	ADVANCE_RING();
 
 	cmdbuf->buf += cmdsz * 4;
@@ -1693,7 +1688,7 @@
 	int cmdsz, tmp;
 	int *cmd = (int *)cmdbuf->buf;
 	drm_clip_rect_t *boxes = cmdbuf->boxes;
-	int i = 0, j;
+	int i = 0;
 	RING_LOCALS;
 
 	DRM_DEBUG("%s\n", __FUNCTION__);
@@ -1715,12 +1710,7 @@
 		}
 		
 		BEGIN_RING( cmdsz );
-		for (j = 0 ; j < cmdsz ; j++) {
-			if (__get_user( tmp, &cmd[j] ))
-				return -EFAULT;
-/*  			printk( "pk3_clip %d: %x\n", j, tmp); */
-			OUT_RING( tmp );
-		}
+		OUT_RING_USER_TABLE( cmd, cmdsz );
 		ADVANCE_RING();
 
 	} while ( ++i < cmdbuf->nbox );
@@ -1768,7 +1758,8 @@
 	if (verify_area( VERIFY_READ, cmdbuf.buf, cmdbuf.bufsz ))
 		return -EFAULT;
 
-	if (verify_area( VERIFY_READ, cmdbuf.boxes, 
+	if (cmdbuf.nbox &&
+	    verify_area( VERIFY_READ, cmdbuf.boxes, 
 			 cmdbuf.nbox * sizeof(drm_clip_rect_t)))
 		return -EFAULT;
 
@@ -1844,6 +1835,7 @@
 	}
 
 
+	COMMIT_RING();
 	return 0;
 }
 
diff -Nru a/drivers/char/ip2main.c b/drivers/char/ip2main.c
--- a/drivers/char/ip2main.c	Wed May 29 11:43:03 2002
+++ b/drivers/char/ip2main.c	Wed May 29 11:43:03 2002
@@ -1002,12 +1002,10 @@
 	printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1,
 	       ip2config.addr[boardnum], ip2config.irq[boardnum] );
 
-	if (0 != ( rc = check_region( ip2config.addr[boardnum], 8))) {
-		printk(KERN_ERR "IP2: bad addr=0x%x rc = %d\n",
-				ip2config.addr[boardnum], rc );
+	if (!request_region( ip2config.addr[boardnum], 8, pcName )) {
+		printk(KERN_ERR "IP2: bad addr=0x%x\n", ip2config.addr[boardnum]);
 		goto err_initialize;
 	}
-	request_region( ip2config.addr[boardnum], 8, pcName );
 
 	if ( iiDownloadAll ( pB, (loadHdrStrPtr)Fip_firmware, 1, Fip_firmware_size )
 	    != II_DOWN_GOOD ) {
diff -Nru a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
--- a/drivers/char/rio/rio_linux.c	Wed May 29 11:43:03 2002
+++ b/drivers/char/rio/rio_linux.c	Wed May 29 11:43:03 2002
@@ -702,7 +702,7 @@
   func_enter();
 
   /* The "dev" argument isn't used. */
-  rc = -riocontrol (p, 0, cmd, (void *)arg, capable(CAP_SYS_ADMIN));
+  rc = riocontrol (p, 0, cmd, (void *)arg, capable(CAP_SYS_ADMIN));
 
   func_exit ();
   return rc;
diff -Nru a/drivers/hotplug/Makefile b/drivers/hotplug/Makefile
--- a/drivers/hotplug/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/hotplug/Makefile	Wed May 29 11:43:02 2002
@@ -2,8 +2,6 @@
 # Makefile for the Linux kernel pci hotplug controller drivers.
 #
 
-O_TARGET	:= vmlinux-obj.o
-
 export-objs	:= pci_hotplug_core.o pci_hotplug_util.o
 
 obj-$(CONFIG_HOTPLUG_PCI)		+= pci_hotplug.o
diff -Nru a/drivers/i2c/Makefile b/drivers/i2c/Makefile
--- a/drivers/i2c/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/i2c/Makefile	Wed May 29 11:43:01 2002
@@ -2,8 +2,6 @@
 # Makefile for the kernel i2c bus driver.
 #
 
-O_TARGET := i2c.o
-
 export-objs	:= i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \
 		   i2c-algo-ite.o i2c-proc.o
 
diff -Nru a/drivers/ide/Config.help b/drivers/ide/Config.help
--- a/drivers/ide/Config.help	Wed May 29 11:43:03 2002
+++ b/drivers/ide/Config.help	Wed May 29 11:43:03 2002
@@ -295,28 +295,13 @@
   It is normally safe to answer Y; however, the default is N.
 
 CONFIG_BLK_DEV_AEC62XX
-  This driver adds up to 4 more EIDE devices sharing a single
-  interrupt. This add-on card is a bootable PCI UDMA controller. In
-  order to get this card to initialize correctly in some cases, you
-  should say Y here, and preferably also to "Use DMA by default when
-  available".
-
-  The ATP850U/UF is an UltraDMA 33 chipset base.
-  The ATP860 is an UltraDMA 66 chipset base.
-  The ATP860M(acintosh) version is an UltraDMA 66 chipset base.
-  The ATP865 is an ATA100/133 chipset.
-
-  Please read the comments at the top of <file:drivers/ide/aec62xx.c>.
-  If you say Y here, then say Y to "Use DMA by default when available"
-  as well.
-
-CONFIG_AEC62XX_TUNING
-  Please read the comments at the top of <file:drivers/ide/aec62xx.c>.
-  If unsure, say N.
+  This driver adds explicit support for Acard AEC62xx (Artop ATP8xx)
+  IDE controllers. This allows the kernel to change PIO, DMA and UDMA
+  speeds and to configure the chip to optimum performance.
 
 CONFIG_AEC6280_BURST
-  Use burst mode for DMA transfers. Higher speed, but causes more load
-  on the bus.
+  Use burst mode for DMA transfers. This helps to achieve higher
+  transfer rates, but causes more load on the PCI bus.
 
   If unsure, say N.
 
diff -Nru a/drivers/ide/Config.in b/drivers/ide/Config.in
--- a/drivers/ide/Config.in	Wed May 29 11:43:03 2002
+++ b/drivers/ide/Config.in	Wed May 29 11:43:03 2002
@@ -40,9 +40,8 @@
          int '      Default queue depth' CONFIG_BLK_DEV_IDE_TCQ_DEPTH 32
       fi
       dep_bool '    Good-Bad DMA Model-Firmware (EXPERIMENTAL)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_EXPERIMENTAL
-      dep_bool '    AEC62XX chip set support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
-      dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
-      dep_mbool '      AEC6280 Burst mode' CONFIG_AEC6280_BURST $CONFIG_BLK_DEV_AEC62XX
+      dep_bool '    Acard (Artop) chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_mbool '      ATP865 burst mode' CONFIG_AEC6280_BURST $CONFIG_BLK_DEV_AEC62XX
       dep_bool '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
       dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 $CONFIG_EXPERIMENTAL
       dep_bool '    AMD and nVidia chipset support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
@@ -122,7 +121,7 @@
       if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
 	 bool '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
       fi
-      bool '    QDI QD65xx support' CONFIG_BLK_DEV_QD65XX
+      dep_tristate '    QDI QD65xx support' CONFIG_BLK_DEV_QD65XX $CONFIG_BLK_DEV_IDE
       bool '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672
    fi
    if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" -o \
diff -Nru a/drivers/ide/Makefile b/drivers/ide/Makefile
--- a/drivers/ide/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/ide/Makefile	Wed May 29 11:43:03 2002
@@ -8,15 +8,9 @@
 # In the future, some of these should be built conditionally.
 #
 
-O_TARGET := idedriver.o
-
-export-objs	:= ide-taskfile.o ide.o ide-features.o ide-probe.o quirks.o pcidma.o tcq.o \
+export-objs	:= ide-taskfile.o main.o ide.o probe.o quirks.o pcidma.o tcq.o \
 		   atapi.o ataraid.o
 
-obj-y		:=
-obj-m		:=
-ide-obj-y	:=
-
 obj-$(CONFIG_BLK_DEV_HD)	+= hd.o
 obj-$(CONFIG_BLK_DEV_IDE)       += ide-mod.o
 obj-$(CONFIG_BLK_DEV_IDECS)     += ide-cs.o
@@ -27,6 +21,7 @@
 obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
 
 obj-$(CONFIG_BLK_DEV_IT8172)    += it8172.o
+obj-$(CONFIG_BLK_DEV_QD65XX)    += qd65xx.o
 
 ide-obj-$(CONFIG_BLK_DEV_AEC62XX)	+= aec62xx.o
 ide-obj-$(CONFIG_BLK_DEV_ALI14XX)	+= ali14xx.o
@@ -58,7 +53,6 @@
 ide-obj-$(CONFIG_BLK_DEV_PDC202XX)	+= pdc202xx.o
 ide-obj-$(CONFIG_BLK_DEV_PDC4030)	+= pdc4030.o
 ide-obj-$(CONFIG_BLK_DEV_PIIX)		+= piix.o
-ide-obj-$(CONFIG_BLK_DEV_QD65XX)	+= qd65xx.o
 ide-obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
 ide-obj-$(CONFIG_BLK_DEV_RZ1000)	+= rz1000.o
 ide-obj-$(CONFIG_BLK_DEV_SIS5513)	+= sis5513.o
@@ -74,6 +68,7 @@
 obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
 obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
 
-ide-mod-objs	:= ide-taskfile.o ide.o ide-probe.o ide-geometry.o ide-features.o ata-timing.o atapi.o $(ide-obj-y)
+ide-mod-objs	:= ide-taskfile.o main.o ide.o probe.o \
+		   ioctl.o atapi.o ata-timing.o $(ide-obj-y)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
--- a/drivers/ide/aec62xx.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/aec62xx.c	Wed May 29 11:43:02 2002
@@ -1,559 +1,271 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
+/*
+ *
+ * $Id: aec62xx.c,v 1.0 2002/05/24 14:37:19 vojtech Exp $
  *
- * Version 0.11	March 27, 2002
+ *  Copyright (c) 2002 Vojtech Pavlik
  *
- * Copyright (C) 1999-2000	Andre Hedrick (andre@linux-ide.org)
+ *  Based on the work of:
+ *	Andre Hedrick
+ */
+
+/*
+ * AEC 6210UF (ATP850UF), AEC6260 (ATP860) and AEC6280 (ATP865) IDE driver for Linux.
  *
+ * UDMA66 and higher modes are autoenabled only in case the BIOS has detected a
+ * 80 wire cable. To ignore the BIOS data and assume the cable is present, use
+ * 'ide0=ata66' or 'ide1=ata66' on the kernel command line.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/config.h>
-#include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
-
 #include <asm/io.h>
-#include <asm/irq.h>
 
 #include "ata-timing.h"
 #include "pcihost.h"
 
-#undef DISPLAY_AEC62XX_TIMINGS
+#define AEC_DRIVE_TIMING	0x40
+#define AEC_UDMA_NEW		0x44
+#define AEC_MISC		0x49
+#define AEC_IDE_ENABLE		0x4a
+#define AEC_UDMA_OLD		0x54
 
-#ifndef HIGH_4
-#define HIGH_4(H)		((H)=(H>>4))
-#endif
-#ifndef LOW_4
-#define LOW_4(L)		((L)=(L-((L>>4)<<4)))
-#endif
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-#ifndef MAKE_WORD
-#define MAKE_WORD(W,HB,LB)	((W)=((HB<<8)+LB))
-#endif
-
-
-#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int aec62xx_get_info(char *, char **, off_t, int);
-extern int (*aec62xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-static struct pci_dev *bmide_dev;
+static unsigned char aec_cyc2udma[17] = { 0, 0, 7, 6, 5, 4, 4, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1 };
 
-static const char *aec6280_get_speed(u8 speed)
-{
-	switch(speed) {
-		case 7: return "6";
-		case 6: return "5";
-		case 5: return "4";
-		case 4: return "3";
-		case 3: return "2";
-		case 2: return "1";
-		case 1: return "0";
-		case 0: return "?";
-	}
-	return "?";
-}
+/*
+ * aec_set_speed_old() writes timing values to
+ * the chipset registers for ATP850UF
+ */
 
-static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
+static void aec_set_speed_old(struct pci_dev *dev, unsigned char dn, struct ata_timing *timing)
 {
-	char *p = buffer;
+	unsigned char t;
 
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8 c0 = 0, c1 = 0;
-	u8 art = 0, uart = 0;
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			p += sprintf(p, "\n                                AEC6210 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-			p += sprintf(p, "\n                                AEC6260 No Bios Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			p += sprintf(p, "\n                                AEC6260 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP865:
-			p += sprintf(p, "\n                                AEC6280 Chipset without ROM.\n");
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP865R:
-			p += sprintf(p, "\n                                AEC6280 Chipset with ROM.\n");
-			break;
-		default:
-			p += sprintf(p, "\n                                AEC62?? Chipset.\n");
-			break;
-	}
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	(void) pci_read_config_byte(bmide_dev, 0x4a, &art);
-	p += sprintf(p, "                %sabled                         %sabled\n",
-		(art&0x02)?" en":"dis",(art&0x04)?" en":"dis");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-		(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			(void) pci_read_config_byte(bmide_dev, 0x54, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)         %s(%s)           %s(%s)\n",
-				(c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
-				(art&0x02)?"2":(art&0x01)?"1":"0",
-				(c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
-				(art&0x08)?"2":(art&0x04)?"1":"0",
-				(c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
-				(art&0x20)?"2":(art&0x10)?"1":"0",
-				(c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
-				(art&0x80)?"2":(art&0x40)?"1":"0");
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "             0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
-			p += sprintf(p, "            0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x46, &art);
-			p += sprintf(p, "              0x%02x\n", art);
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "Recovery:       0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "             0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x45, &art);
-			p += sprintf(p, "            0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x47, &art);
-			p += sprintf(p, "              0x%02x\n", art);
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
-				(c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
-				((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
-				(c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
-				((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?");
-			(void) pci_read_config_byte(bmide_dev, 0x45, &art);
-			p += sprintf(p, "         %s(%s)           %s(%s)\n",
-				(c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
-				((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
-				(c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
-				((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?");
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x49, &uart);
-			p += sprintf(p, "reg49h = 0x%02x ", uart);
-			(void) pci_read_config_byte(bmide_dev, 0x4a, &uart);
-			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP865:
-		case PCI_DEVICE_ID_ARTOP_ATP865R:
-			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
-				(c0&0x20)?((art&0x0f)?"UDMA":" DMA"):" PIO",
-				aec6280_get_speed(art&0x0f),
-				(c0&0x40)?((art&0xf0)?"UDMA":" DMA"):" PIO",
-				aec6280_get_speed(art>>4));
-			(void) pci_read_config_byte(bmide_dev, 0x45, &art);
-			p += sprintf(p, "         %s(%s)          %s(%s)\n",
-				(c0&0x20)?((art&0x0f)?"UDMA":" DMA"):" PIO",
-				aec6280_get_speed(art&0x0f),
-				(c0&0x40)?((art&0xf0)?"UDMA":" DMA"):" PIO",
-				aec6280_get_speed(art>>4));
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x49, &uart);
-			p += sprintf(p, "reg49h = 0x%02x ", uart);
-			(void) pci_read_config_byte(bmide_dev, 0x4a, &uart);
-			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
-			break;
-		default:
-			break;
-	}
+	pci_write_config_byte(dev, AEC_DRIVE_TIMING + (dn << 1),     FIT(timing->active, 0, 15));
+	pci_write_config_byte(dev, AEC_DRIVE_TIMING + (dn << 1) + 1, FIT(timing->recover, 0, 15));
 
-	return p-buffer;/* => must be less than 4k! */
+	pci_read_config_byte(dev, AEC_UDMA_OLD, &t);
+	t &= ~(3 << (dn << 1));
+	if (timing->udma)
+		t |= (5 - FIT(timing->udma, 2, 4)) << (dn << 1);
+	pci_write_config_byte(dev, AEC_UDMA_OLD, t);
 }
-#endif	/* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte aec62xx_proc = 0;
-
-struct chipset_bus_clock_list_entry {
-	byte		xfer_speed;
-
-	byte		chipset_settings_34;
-	byte		ultra_settings_34;
-
-	byte		chipset_settings_33;
-	byte		ultra_settings_33;
-};
-
-struct chipset_bus_clock_list_entry aec62xx_base [] = {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	{	XFER_UDMA_6,	0x41,	0x06,	0x31,	0x07	},
-	{	XFER_UDMA_5,	0x41,	0x05,	0x31,	0x06	},
-	{	XFER_UDMA_4,	0x41,	0x04,	0x31,	0x05	},
-	{	XFER_UDMA_3,	0x41,	0x03,	0x31,	0x04	},
-	{	XFER_UDMA_2,	0x41,	0x02,	0x31,	0x03	},
-	{	XFER_UDMA_1,	0x41,	0x01,	0x31,	0x02	},
-	{	XFER_UDMA_0,	0x41,	0x01,	0x31,	0x01	},
-
-	{	XFER_MW_DMA_2,	0x41,	0x00,	0x31,	0x00	},
-	{	XFER_MW_DMA_1,	0x42,	0x00,	0x31,	0x00	},
-	{	XFER_MW_DMA_0,	0x7a,	0x00,	0x0a,	0x00	},
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	{	XFER_PIO_4,	0x41,	0x00,	0x31,	0x00	},
-	{	XFER_PIO_3,	0x43,	0x00,	0x33,	0x00	},
-	{	XFER_PIO_2,	0x78,	0x00,	0x08,	0x00	},
-	{	XFER_PIO_1,	0x7a,	0x00,	0x0a,	0x00	},
-	{	XFER_PIO_0,	0x70,	0x00,	0x00,	0x00	},
-	{	0,		0x00,	0x00,	0x00,	0x00	}
-};
 
 /*
- * TO DO: active tuning and correction of cards without a bios.
+ * aec_set_speed_new() writes timing values to the chipset registers for all
+ * other Artop chips
  */
 
-static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+static void aec_set_speed_new(struct pci_dev *dev, unsigned char dn, struct ata_timing *timing)
 {
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return ((byte) ((system_bus_speed <= 33333) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34));
-		}
-	return 0x00;
-}
+	unsigned char t;
 
-static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return ((byte) ((system_bus_speed <= 33333) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34));
-		}
-	return 0x00;
-}
+	pci_write_config_byte(dev, AEC_DRIVE_TIMING + dn,
+		(FIT(timing->active, 0, 15) << 4) | FIT(timing->recover, 0, 15));
 
-static int aec62xx_ratemask(struct ata_device *drive)
-{
-	struct pci_dev *dev = drive->channel->pci_dev;
-	u32 bmide = pci_resource_start(dev, 4);
-	int map = 0;
-
-	if (!eighty_ninty_three(drive))
-		return XFER_UDMA;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP865R:
-		case PCI_DEVICE_ID_ARTOP_ATP865:
-			if (IN_BYTE(bmide+2) & 0x10)
-				map |= XFER_UDMA_133;
-			else
-				map |= XFER_UDMA_100;
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-			map |= XFER_UDMA_66;
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			map |= XFER_UDMA;
-	}
-	return map;
+	pci_read_config_byte(dev, AEC_UDMA_NEW + (dn >> 1), &t);
+	t &= ~(0xf << ((dn & 1) << 2));
+	if (timing->udma)
+		t |= aec_cyc2udma[FIT(timing->udma, 2, 16)] << ((dn & 1) << 2);
+	pci_write_config_byte(dev, AEC_UDMA_NEW + (dn >> 1), t);
 }
 
-static int aec6210_tune_chipset(struct ata_device *drive, byte speed)
+/*
+ * aec_set_drive() computes timing values configures the drive and
+ * the chipset to a desired transfer mode. It also can be called
+ * by upper layers.
+ */
+
+static int aec_set_drive(struct ata_device *drive, unsigned char speed)
 {
-	struct pci_dev *dev = drive->channel->pci_dev;
-	unsigned short d_conf	= 0x0000;
-	byte ultra		= 0x00;
-	byte ultra_conf		= 0x00;
-	byte tmp0		= 0x00;
-	byte tmp1		= 0x00;
-	byte tmp2		= 0x00;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
-	tmp0 = pci_bus_clock_list(speed, aec62xx_base);
-	SPLIT_BYTE(tmp0,tmp1,tmp2);
-	MAKE_WORD(d_conf,tmp1,tmp2);
-	pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
-
-	tmp1 = 0x00;
-	tmp2 = 0x00;
-	pci_read_config_byte(dev, 0x54, &ultra);
-	tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
-	ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base);
-	tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
-	pci_write_config_byte(dev, 0x54, tmp2);
+	struct ata_timing t;
+	int T, UT;
+	int aec_old;
 
-	__restore_flags(flags);	/* local CPU only */
+	aec_old = (drive->channel->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF);
 
-	return ide_config_drive_speed(drive, speed);
-}
+	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
+		if (ide_config_drive_speed(drive, speed))
+			printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
+				drive->dn >> 1, drive->dn & 1);
 
-static int aec6260_tune_chipset(struct ata_device *drive, byte speed)
-{
-	struct pci_dev *dev = drive->channel->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	u8 ultra_pci = drive->channel->unit ? 0x45 : 0x44;
-	byte drive_conf		= 0x00;
-	byte ultra_conf		= 0x00;
-	byte ultra		= 0x00;
-	byte tmp1		= 0x00;
-	byte tmp2		= 0x00;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
-	drive_conf = pci_bus_clock_list(speed, aec62xx_base);
-	pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
-
-	pci_read_config_byte(dev, ultra_pci, &ultra);
-	tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
-	ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base);
-	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
-	pci_write_config_byte(dev, ultra_pci, tmp2);
-	__restore_flags(flags);	/* local CPU only */
+	T = 1000000000 / system_bus_speed;
+	UT = T / (aec_old ? 1 : 4);
 
-	if (!drive->init_speed)
-		drive->init_speed = speed;
+	ata_timing_compute(drive, speed, &t, T, UT);
+
+	if (aec_old)
+		aec_set_speed_old(drive->channel->pci_dev, drive->dn, &t);
+	else
+		aec_set_speed_new(drive->channel->pci_dev, drive->dn, &t);
 
 	drive->current_speed = speed;
-	return ide_config_drive_speed(drive, speed);
+
+	return 0;
 }
 
+/*
+ * aec62xx_tune_drive() is a callback from upper layers for
+ * PIO-only tuning.
+ */
 
-static int aec62xx_tune_chipset(struct ata_device *drive, byte speed)
+static void aec62xx_tune_drive(struct ata_device *drive, unsigned char pio)
 {
-	switch (drive->channel->pci_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP865:
-		case PCI_DEVICE_ID_ARTOP_ATP865R:
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			return aec6260_tune_chipset(drive, speed);
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			return aec6210_tune_chipset(drive, speed);
-		default:
-			return -1;
+	if (pio == 255) {
+		aec_set_drive(drive, ata_timing_mode(drive, XFER_PIO | XFER_EPIO));
+		return;
 	}
+
+	aec_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5));
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma(struct ata_device *drive, u8 udma)
+static int aec62xx_dmaproc(struct ata_device *drive)
 {
+	short speed;
 	int map;
-	u8 mode;
 
-	if (drive->type != ATA_DISK)
-		return 0;
+	map = XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA | XFER_SWDMA | XFER_UDMA;
 
-	if (udma)
-		map = aec62xx_ratemask(drive);
-	else
-		map = XFER_SWDMA | XFER_MWDMA;
-
-	mode = ata_timing_mode(drive, map);
-
-	if (mode < XFER_SW_DMA_0)
-		return 0;
-
-	return !aec62xx_tune_chipset(drive, mode);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-static void aec62xx_tune_drive(struct ata_device *drive, byte pio)
-{
-	byte speed;
-
-	if (pio == 255)
-		speed = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
-	else
-		speed = XFER_PIO_0 + min_t(byte, pio, 4);
+	if (drive->channel->udma_four)
+		switch (drive->channel->pci_dev->device) {
+			case PCI_DEVICE_ID_ARTOP_ATP865R:
+			case PCI_DEVICE_ID_ARTOP_ATP865:
+				map |= XFER_UDMA_100 | XFER_UDMA_133;
+			case PCI_DEVICE_ID_ARTOP_ATP860R:
+			case PCI_DEVICE_ID_ARTOP_ATP860:
+				map |= XFER_UDMA_66;
+		}
 
-	(void) aec62xx_tune_chipset(drive, speed);
-}
+	speed = ata_timing_mode(drive, map);
+	aec_set_drive(drive, speed);
+	udma_enable(drive, drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO, 0);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_drive_xfer_rate(struct ata_device *drive)
-{
-	struct hd_driveid *id = drive->id;
-	int on = 1;
-	int verbose = 1;
-
-	if (id && (id->capability & 1) && drive->channel->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (udma_black_list(drive)) {
-			on = 0;
-			goto fast_ata_pio;
-		}
-		on = 0;
-		verbose = 0;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				on = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (!on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				on = config_chipset_for_dma(drive, 0);
-				if (!on)
-					goto no_dma_set;
-			}
-		} else if (udma_white_list(drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			on = config_chipset_for_dma(drive, 0);
-			if (!on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		on = 0;
-		verbose = 0;
-no_dma_set:
-		aec62xx_tune_drive(drive, 5);
-	}
-	udma_enable(drive, on, verbose);
 	return 0;
 }
-
-int aec62xx_dmaproc(struct ata_device *drive)
-{
-	return config_drive_xfer_rate(drive);
-}
 #endif
 
+/*
+ * The initialization callback. Here we determine the IDE chip type
+ * and initialize its drive independent registers.
+ */
+
 static unsigned int __init aec62xx_init_chipset(struct pci_dev *dev)
 {
-	u8 reg49h = 0;
-	u8 reg4ah = 0;
+	unsigned char t;
+
+/*
+ * Initialize if needed.
+ */
+
+	switch (dev->device) {
 
-	switch(dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP865:
 		case PCI_DEVICE_ID_ARTOP_ATP865R:
-			/* Clear reset and test bits.  */
-			pci_read_config_byte(dev, 0x49, &reg49h);
-			pci_write_config_byte(dev, 0x49, reg49h & ~0x30);
-			/* Enable chip interrupt output.  */
-			pci_read_config_byte(dev, 0x4a, &reg4ah);
-			pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01);
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+
+			/* Clear reset and test bits. */
+			pci_read_config_byte(dev, AEC_MISC, &t);
+			pci_write_config_byte(dev, AEC_MISC, t & ~0x30);
+
+			/* Enable chip interrupt output. */
+			pci_read_config_byte(dev, AEC_IDE_ENABLE, &t);
+			pci_write_config_byte(dev, AEC_IDE_ENABLE, t & ~0x01);
+
 #ifdef CONFIG_AEC6280_BURST
-			/* Must be greater than 0x80 for burst mode.  */
+			/* Must be greater than 0x80 for burst mode. */
 			pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x90);
-			/* Enable burst mode.  */
-			pci_read_config_byte(dev, 0x4a, &reg4ah);
-			pci_write_config_byte(dev, 0x4a, reg4ah | 0x80);
+
+			/* Enable burst mode. */
+			pci_read_config_byte(dev, AEC_IDE_ENABLE, &t);
+			pci_write_config_byte(dev, AEC_IDE_ENABLE, t | 0x80);
+
 #endif
-			break;
-		default:
-			break;
 	}
 
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", dev->name, dev->resource[PCI_ROM_RESOURCE].start);
-	}
+/*
+ * Print the boot message.
+ */
 
-#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!aec62xx_proc) {
-		aec62xx_proc = 1;
-		bmide_dev = dev;
-		aec62xx_display_info = &aec62xx_get_info;
-	}
-#endif
+	pci_read_config_byte(dev, PCI_REVISION_ID, &t);
+	printk(KERN_INFO "AEC_IDE: %s (rev %02x) controller on pci%s\n",
+		dev->name, t, dev->slot_name);
 
-	return dev->irq;
+	return 0;
 }
 
 static unsigned int __init aec62xx_ata66_check(struct ata_channel *ch)
 {
-	u8 mask	= ch->unit ? 0x02 : 0x01;
-	u8 ata66 = 0;
+	unsigned char t;
 
-	pci_read_config_byte(ch->pci_dev, 0x49, &ata66);
+	if (ch->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
+		return 0;
 
-	return ((ata66 & mask) ? 0 : 1);
+	pci_read_config_byte(ch->pci_dev, AEC_MISC, &t);
+	return ((t & (1 << ch->unit)) ? 0 : 1);
 }
 
-static void __init aec62xx_init_channel(struct ata_channel *hwif)
+static void __init aec62xx_init_channel(struct ata_channel *ch)
 {
-	hwif->tuneproc = aec62xx_tune_drive;
-	hwif->speedproc = aec62xx_tune_chipset;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
+	int i;
+
+	ch->tuneproc = &aec62xx_tune_drive;
+	ch->speedproc = &aec_set_drive;
+	ch->autodma = 0;
+
+	ch->io_32bit = 1;
+	ch->unmask = 1;
+
+	for (i = 0; i < 2; i++) {
+		ch->drives[i].autotune = 1;
+		ch->drives[i].dn = ch->unit * 2 + i;
+	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->XXX_udma = aec62xx_dmaproc;
-		hwif->highmem = 1;
-# ifdef CONFIG_IDEDMA_AUTO
+	if (ch->dma_base) {
+		ch->highmem = 1;
+		ch->XXX_udma = aec62xx_dmaproc;
+#ifdef CONFIG_IDEDMA_AUTO
 		if (!noautodma)
-			hwif->autodma = 1;
-# endif
+			ch->autodma = 1;
+#endif
 	}
 #endif
 }
 
-static void __init aec62xx_init_dma(struct ata_channel *hwif, unsigned long dmabase)
+/*
+ * We allow the BM-DMA driver only work on enabled interfaces.
+ */
+static void __init aec62xx_init_dma(struct ata_channel *ch, unsigned long dmabase)
 {
-	u8 reg54h = 0;
+	unsigned char t;
 
-	/* FIXME: we need some locking here */
-	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
-	pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->unit ? 0xF0 : 0x0F));
-	ata_init_dma(hwif, dmabase);
+	pci_read_config_byte(ch->pci_dev, AEC_IDE_ENABLE, &t);
+	if (t & (1 << ((ch->unit << 1) + 2)))
+		ata_init_dma(ch, dmabase);
 }
 
 /* module data table */
@@ -574,7 +286,7 @@
 		init_chipset: aec62xx_init_chipset,
 		ata66_check: aec62xx_ata66_check,
 		init_channel: aec62xx_init_channel,
-		enablebits: { {0x00,0x00,0x00},	{0x00,0x00,0x00} },
+		enablebits: { {0x4a,0x02,0x02},	{0x4a,0x04,0x04} },
 		bootable: NEVER_BOARD,
 		flags: ATA_F_IRQ | ATA_F_NOADMA | ATA_F_DMA
 	},
@@ -594,7 +306,7 @@
 		init_chipset: aec62xx_init_chipset,
 		ata66_check: aec62xx_ata66_check,
 		init_channel: aec62xx_init_channel,
-		enablebits: { {0x00,0x00,0x00},	{0x00,0x00,0x00} },
+		enablebits: { {0x4a,0x02,0x02},	{0x4a,0x04,0x04} },
 		bootable: NEVER_BOARD,
 		flags: ATA_F_IRQ | ATA_F_DMA
 	},
@@ -604,7 +316,7 @@
 		init_chipset: aec62xx_init_chipset,
 		ata66_check: aec62xx_ata66_check,
 		init_channel: aec62xx_init_channel,
-		enablebits: { {0x00,0x00,0x00},	{0x00,0x00,0x00} },
+		enablebits: { {0x4a,0x02,0x02},	{0x4a,0x04,0x04} },
 		bootable: OFF_BOARD,
 		flags: ATA_F_IRQ | ATA_F_DMA
 	}
@@ -614,9 +326,8 @@
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
-		ata_register_chipset(&chipsets[i]);
-	}
+	for (i = 0; i < ARRAY_SIZE(chipsets); i++)
+		ata_register_chipset(chipsets + i);
 
 	return 0;
 }
diff -Nru a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
--- a/drivers/ide/alim15x3.c	Wed May 29 11:43:03 2002
+++ b/drivers/ide/alim15x3.c	Wed May 29 11:43:03 2002
@@ -377,8 +377,6 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	if (!drive->init_speed)
-		drive->init_speed = speed;
 	drive->current_speed = speed;
 
 	return ide_config_drive_speed(drive, speed);
@@ -685,20 +683,35 @@
 
 
 /* module data table */
-static struct ata_pci_device chipset __initdata = {
-	vendor: PCI_VENDOR_ID_AL,
-        device: PCI_DEVICE_ID_AL_M5229,
-	init_chipset: ali15x3_init_chipset,
-	ata66_check: ali15x3_ata66_check,
-	init_channel: ali15x3_init_channel,
-	init_dma: ali15x3_init_dma,
-	enablebits: { {0x00,0x00,0x00}, {0x00,0x00,0x00} },
-	bootable: ON_BOARD
+static struct ata_pci_device chipsets[] __initdata = {
+	{
+		vendor: PCI_VENDOR_ID_AL,
+	        device: PCI_DEVICE_ID_AL_M5219,
+		/* FIXME: Perhaps we should use the same init routines
+		 * as below here. */
+		enablebits: { {0x00,0x00,0x00}, {0x00,0x00,0x00} },
+		bootable: ON_BOARD,
+		flags: ATA_F_SIMPLEX
+	},
+	{
+		vendor: PCI_VENDOR_ID_AL,
+	        device: PCI_DEVICE_ID_AL_M5229,
+		init_chipset: ali15x3_init_chipset,
+		ata66_check: ali15x3_ata66_check,
+		init_channel: ali15x3_init_channel,
+		init_dma: ali15x3_init_dma,
+		enablebits: { {0x00,0x00,0x00}, {0x00,0x00,0x00} },
+		bootable: ON_BOARD
+	}
 };
 
 int __init init_ali15x3(void)
 {
-	ata_register_chipset(&chipset);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+		ata_register_chipset(&chipsets[i]);
+	}
 
         return 0;
 }
diff -Nru a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
--- a/drivers/ide/amd74xx.c	Wed May 29 11:43:03 2002
+++ b/drivers/ide/amd74xx.c	Wed May 29 11:43:03 2002
@@ -251,8 +251,6 @@
 
 	amd_set_speed(drive->channel->pci_dev, drive->dn, &t);
 
-	if (!drive->init_speed)	
-		drive->init_speed = speed;
 	drive->current_speed = speed;
 
 	return 0;
@@ -443,7 +441,8 @@
 		init_channel: amd74xx_init_channel,
 		init_dma: amd74xx_init_dma,
 		enablebits: {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
-		bootable: ON_BOARD
+		bootable: ON_BOARD,
+		flags: ATA_F_SIMPLEX
 	},
 	{
 		vendor:	PCI_VENDOR_ID_AMD,
diff -Nru a/drivers/ide/ata-timing.h b/drivers/ide/ata-timing.h
--- a/drivers/ide/ata-timing.h	Wed May 29 11:43:03 2002
+++ b/drivers/ide/ata-timing.h	Wed May 29 11:43:03 2002
@@ -82,4 +82,5 @@
 extern struct ata_timing* ata_timing_data(short speed);
 extern int ata_timing_compute(struct ata_device *drive,
 		short speed, struct ata_timing *t, int T, int UT);
+
 #endif
diff -Nru a/drivers/ide/atapi.c b/drivers/ide/atapi.c
--- a/drivers/ide/atapi.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/atapi.c	Wed May 29 11:43:02 2002
@@ -38,6 +38,21 @@
 #include <asm/uaccess.h>
 
 /*
+ * Initializes a packet command. Used by tape and floppy driver.
+ */
+void atapi_init_pc(struct atapi_packet_command *pc)
+{
+	memset(pc->c, 0, 12);
+	pc->retries = 0;
+	pc->flags = 0;
+	pc->request_transfer = 0;
+	pc->buffer = pc->pc_buffer;
+	pc->buffer_size = IDEFLOPPY_PC_BUFFER_SIZE;
+	pc->b_data = NULL;
+	pc->bio = NULL;
+}
+
+/*
  * Too bad. The drive wants to send us data which we are not ready to accept.
  * Just throw it away.
  */
@@ -54,22 +69,57 @@
 }
 
 /*
- * Initializes a packet command. Used by tape and floppy driver.
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes, so if
+ * an odd n is specified, be sure that there's at least one extra byte
+ * allocated for the buffer.
  */
-void atapi_init_pc(struct atapi_packet_command *pc)
+void atapi_read(struct ata_device *drive, u8 *buf, unsigned int n)
 {
-	memset(pc->c, 0, 12);
-	pc->retries = 0;
-	pc->flags = 0;
-	pc->request_transfer = 0;
-	pc->buffer = pc->pc_buffer;
-	pc->buffer_size = IDEFLOPPY_PC_BUFFER_SIZE;
-	pc->b_data = NULL;
-	pc->bio = NULL;
+	if (drive->channel->atapi_read) {
+		drive->channel->atapi_read(drive, buf, n);
+		return;
+	}
+
+	++n;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		insw_swapw(IDE_DATA_REG, buf, n / 2);
+		return;
+	}
+#endif
+	ata_read(drive, buf, n / 4);
+	if ((n & 0x03) >= 2)
+		insw(IDE_DATA_REG, buf + (n & ~0x03), 1);
+}
+
+void atapi_write(struct ata_device *drive, u8 *buf, unsigned int n)
+{
+	if (drive->channel->atapi_write) {
+		drive->channel->atapi_write(drive, buf, n);
+		return;
+	}
+
+	++n;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		outsw_swapw(IDE_DATA_REG, buf, n / 2);
+		return;
+	}
+#endif
+	ata_write(drive, buf, n / 4);
+	if ((n & 0x03) >= 2)
+		outsw(IDE_DATA_REG, buf + (n & ~0x03), 1);
 }
 
 EXPORT_SYMBOL(atapi_discard_data);
 EXPORT_SYMBOL(atapi_write_zeros);
 EXPORT_SYMBOL(atapi_init_pc);
+
+EXPORT_SYMBOL(atapi_read);
+EXPORT_SYMBOL(atapi_write);
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/ide/buddha.c b/drivers/ide/buddha.c
--- a/drivers/ide/buddha.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/buddha.c	Wed May 29 11:43:02 2002
@@ -202,9 +202,9 @@
 						xsurf_offsets, 0,
 						(ide_ioreg_t)(buddha_board+xsurf_irqports[i]),
 						xsurf_ack_intr, IRQ_AMIGA_PORTS);
-			}	
-			
-			index = ide_register_hw(&hw, NULL);
+			}
+
+			index = ide_register_hw(&hw);
 			if (index != -1) {
 				printk("ide%d: ", index);
 				switch(type) {
diff -Nru a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
--- a/drivers/ide/cmd64x.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/cmd64x.c	Wed May 29 11:43:02 2002
@@ -537,8 +537,6 @@
 	(void) pci_write_config_byte(dev, pciU, regU);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	if (!drive->init_speed)
-		drive->init_speed = speed;
 	drive->current_speed = speed;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -657,8 +655,6 @@
 	pci_write_config_word(dev, dma_pci, multi);
 	pci_write_config_word(dev, udma_pci, ultra);
 
-	if (!drive->init_speed)
-		drive->init_speed = speed;
 	drive->current_speed = speed;
 
 	return ide_config_drive_speed(drive, speed);
@@ -1099,6 +1095,7 @@
 		init_chipset: cmd64x_init_chipset,
 		init_channel: cmd64x_init_channel,
 		bootable: ON_BOARD,
+		flags: ATA_F_SIMPLEX,
 	},
 	{
 		vendor: PCI_VENDOR_ID_CMD,
diff -Nru a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
--- a/drivers/ide/cs5530.c	Wed May 29 11:43:03 2002
+++ b/drivers/ide/cs5530.c	Wed May 29 11:43:03 2002
@@ -76,8 +76,6 @@
 
 byte cs5530_proc = 0;
 
-extern char *ide_xfer_verbose (byte xfer_rate);
-
 /*
  * Set a new transfer mode at the drive
  */
@@ -85,7 +83,7 @@
 {
 	int error = 0;
 
-	printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
+	printk("%s: cs5530_set_xfer_mode(%02x)\n", drive->name, mode);
 	error = ide_config_drive_speed(drive, mode);
 
 	return error;
@@ -376,7 +374,7 @@
 	init_chipset: pci_init_cs5530,
 	init_channel: ide_init_cs5530,
 	bootable: ON_BOARD,
-	flags: ATA_F_DMA
+	flags: ATA_F_DMA | ATA_F_FDMA
 };
 
 int __init init_cs5530(void)
diff -Nru a/drivers/ide/falconide.c b/drivers/ide/falconide.c
--- a/drivers/ide/falconide.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/falconide.c	Wed May 29 11:43:02 2002
@@ -60,7 +60,7 @@
 
 	ide_setup_ports(&hw, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets,
 			0, 0, NULL, IRQ_MFP_IDE);
-	index = ide_register_hw(&hw, NULL);
+	index = ide_register_hw(&hw);
 
 	if (index != -1)
 	    printk("ide%d: Falcon IDE interface\n", index);
diff -Nru a/drivers/ide/gayle.c b/drivers/ide/gayle.c
--- a/drivers/ide/gayle.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/gayle.c	Wed May 29 11:43:02 2002
@@ -150,7 +150,7 @@
 	ide_setup_ports(&hw, base, gayle_offsets,
 			ctrlport, irqport, ack_intr, IRQ_AMIGA_PORTS);
 
-	index = ide_register_hw(&hw, NULL);
+	index = ide_register_hw(&hw);
 	if (index != -1) {
 	    switch (i) {
 		case 0:
diff -Nru a/drivers/ide/hd.c b/drivers/ide/hd.c
--- a/drivers/ide/hd.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/hd.c	Wed May 29 11:43:02 2002
@@ -167,7 +167,7 @@
 	unsigned long flags;
 	char devc;
 
-	devc = !QUEUE_EMPTY ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
+	devc = !blk_queue_empty(QUEUE) ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
 	save_flags (flags);
 	sti();
 #ifdef VERBOSE_ERRORS
@@ -196,7 +196,7 @@
 		if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
 			printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
 				inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
-			if (!QUEUE_EMPTY)
+			if (!blk_queue_empty(QUEUE))
 				printk(", sector=%ld", CURRENT->sector);
 		}
 		printk("\n");
@@ -373,7 +373,7 @@
 {
 	int dev;
 
-	if (QUEUE_EMPTY)
+	if (blk_queue_empty(QUEUE))
 		return;
 	dev = DEVICE_NR(CURRENT->rq_dev);
 	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
@@ -436,7 +436,7 @@
 #if (HD_DELAY > 0)
 	last_req = read_timer();
 #endif
-	if (!QUEUE_EMPTY)
+	if (!blk_queue_empty(QUEUE))
 		hd_request();
 	return;
 }
@@ -497,8 +497,10 @@
 	unsigned int dev;
 
 	DEVICE_INTR = NULL;
-	if (QUEUE_EMPTY)
+
+	if (blk_queue_empty(QUEUE))
 		return;
+
 	disable_irq(HD_IRQ);
 	sti();
 	reset = 1;
diff -Nru a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c
--- a/drivers/ide/hpt34x.c	Wed May 29 11:43:01 2002
+++ b/drivers/ide/hpt34x.c	Wed May 29 11:43:01 2002
@@ -94,8 +94,6 @@
 
 byte hpt34x_proc = 0;
 
-extern char *ide_xfer_verbose(byte xfer_rate);
-
 static void hpt34x_clear_chipset(struct ata_device *drive)
 {
 	unsigned int reg1	= 0, tmp1 = 0;
@@ -132,15 +130,13 @@
 	pci_write_config_dword(drive->channel->pci_dev, 0x48, tmp2);
 
 #if HPT343_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
+	printk("%s: %02x drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
 		" (0x%02x 0x%02x) 0x%04x\n",
-		drive->name, ide_xfer_verbose(speed),
+		drive->name, speed,
 		drive->dn, reg1, tmp1, reg2, tmp2,
 		hi_speed, lo_speed, err);
-#endif /* HPT343_DEBUG_DRIVE_INFO */
+#endif
 
-	if (!drive->init_speed)
-		drive->init_speed = speed;
 	drive->current_speed = speed;
 	return ide_config_drive_speed(drive, speed);
 }
diff -Nru a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
--- a/drivers/ide/hpt366.c	Wed May 29 11:43:01 2002
+++ b/drivers/ide/hpt366.c	Wed May 29 11:43:01 2002
@@ -486,11 +486,10 @@
 static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
 static int n_hpt_devs;
 
-static u8 hpt366_proc = 0;
-
 static unsigned int hpt_min_rev(struct pci_dev *dev, int rev);
 
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+static u8 hpt366_proc = 0;
 static int hpt366_get_info(char *, char **, off_t, int);
 extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
 
@@ -788,9 +787,6 @@
 	if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0))
 		return -1;
 
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
 	if (hpt_min_rev(dev, 7)) {
 		hpt374_tune_chipset(drive, speed);
 	} else if (hpt_min_rev(dev, 5)) {
@@ -863,9 +859,6 @@
 	struct pci_dev *dev = drive->channel->pci_dev;
 	int map;
 	byte mode;
-
-	/* FIXME: remove this --bkz */
-	config_chipset_for_pio(drive);
 
 	if (drive->type != ATA_DISK)
 		return 0;
diff -Nru a/drivers/ide/icside.c b/drivers/ide/icside.c
--- a/drivers/ide/icside.c	Wed May 29 11:43:01 2002
+++ b/drivers/ide/icside.c	Wed May 29 11:43:01 2002
@@ -27,8 +27,6 @@
 #include <asm/io.h>
 #include <asm/page.h>
 
-extern char *ide_xfer_verbose (byte xfer_rate);
-
 /*
  * Maximum number of interfaces per card
  */
@@ -364,16 +362,13 @@
 
 	drive->drive_data = cycle_time;
 
-	if (!drive->init_speed)
-		drive->init_speed = xfer_mode;
-
 	if (cycle_time && ide_config_drive_speed(drive, xfer_mode) == 0)
 		on = 1;
 	else
 		drive->drive_data = 480;
 
-	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
-		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
+	printk("%s: %02x selected (peak %dMB/s)\n", drive->name,
+		xfer_mode, 2000 / drive->drive_data);
 
 	drive->current_speed = xfer_mode;
 
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/ide-cd.c	Wed May 29 11:43:02 2002
@@ -314,6 +314,7 @@
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
+#include <linux/atapi.h>
 #include "ide-cd.h"
 
 /****************************************************************************
@@ -870,9 +871,10 @@
 		/* Throw some data at the drive so it doesn't hang
 		   and quit this request. */
 		while (len > 0) {
-			int dum = 0;
-			atapi_write(drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			u8 dummy[4];
+
+			atapi_write(drive, dummy, sizeof(dummy));
+			len -= sizeof(dummy);
 		}
 	} else  if (ireason == 1) {
 		/* Some drives (ASUS) seem to tell us that status
@@ -1292,10 +1294,10 @@
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
-			int dum = 0;
+			u8 dummy[4];
 
-			atapi_write(drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			atapi_write(drive, dummy, sizeof(dummy));
+			len -= sizeof(dummy);
 		}
 
 		/* Keep count of how much data we've moved. */
@@ -1311,9 +1313,10 @@
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
-			int dum = 0;
-			atapi_read(drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			u8 dummy[4];
+
+			atapi_read(drive, dummy, sizeof(dummy));
+			len -= sizeof(dummy);
 		}
 
 		/* Keep count of how much data we've moved. */
@@ -1455,9 +1458,9 @@
 		/* Throw some data at the drive so it doesn't hang
 		   and quit this request. */
 		while (len > 0) {
-			int dum = 0;
-			atapi_write(drive, &dum, sizeof(dum));
-			len -= sizeof(dum);
+			u8 dummy[4];
+			atapi_write(drive, dummy, sizeof(dummy));
+			len -= sizeof(dummy);
 		}
 	} else {
 		/* Drive wants a command packet, or invalid ireason... */
@@ -2988,7 +2991,7 @@
 	channel = drive->channel;
 	unit = drive - channel->drives;
 
-	ide_revalidate_disk(mk_kdev(channel->major, unit << PARTN_BITS));
+	ata_revalidate(mk_kdev(channel->major, unit << PARTN_BITS));
 }
 
 MODULE_PARM(ignore, "s");
diff -Nru a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
--- a/drivers/ide/ide-cs.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/ide-cs.c	Wed May 29 11:43:02 2002
@@ -233,7 +233,8 @@
         ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
         hw.irq = irq;
         hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
-        return ide_register_hw(&hw, NULL);
+
+        return ide_register_hw(&hw);
 }
 
 void ide_config(dev_link_t *link)
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Wed May 29 11:43:01 2002
+++ b/drivers/ide/ide-disk.c	Wed May 29 11:43:01 2002
@@ -361,8 +361,8 @@
 
 		/*
 		 * Ignore the return code from door_lock, since the open() has
-		 * already succeeded, and the door_lock is irrelevant at this
-		 * point.
+		 * already succeeded once, and the door_lock is irrelevant at this
+		 * time.
 		 */
 
 		if (drive->doorlocking && ide_raw_taskfile(drive, &args))
@@ -1196,7 +1196,7 @@
 	channel = drive->channel;
 	unit = drive - channel->drives;
 
-	ide_revalidate_disk(mk_kdev(channel->major, unit << PARTN_BITS));
+	ata_revalidate(mk_kdev(channel->major, unit << PARTN_BITS));
 }
 
 static void __exit idedisk_exit(void)
diff -Nru a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c
--- a/drivers/ide/ide-features.c	Wed May 29 11:43:03 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,363 +0,0 @@
-/*
- * linux/drivers/block/ide-features.c	Version 0.04	June 9, 2000
- *
- *  Copyright (C) 1999-2000	Linus Torvalds & authors (see below)
- *
- *  Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- *
- *  Extracts if ide.c to address the evolving transfer rate code for
- *  the SETFEATURES_XFER callouts.  Various parts of any given function
- *  are credited to previous ATA-IDE maintainers.
- *
- *  Auto-CRC downgrade for Ultra DMA(ing)
- *
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-#include <linux/config.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/blkpg.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-
-/*
- * A Verbose noise maker for debugging on the attempted transfer rates.
- */
-char *ide_xfer_verbose (byte xfer_rate)
-{
-	static struct ide_xfer_par {
-		byte rate;
-		char *name;
-	} xfer_verbose[] = {
-		{ XFER_UDMA_7,		"UDMA 7" },
-		{ XFER_UDMA_6,		"UDMA 6" },
-		{ XFER_UDMA_5,		"UDMA 5" },
-		{ XFER_UDMA_4,		"UDMA 4" },
-		{ XFER_UDMA_3,		"UDMA 3" },
-		{ XFER_UDMA_2,		"UDMA 2" },
-		{ XFER_UDMA_1,		"UDMA 1" },
-		{ XFER_UDMA_0,		"UDMA 0" },
-		{ XFER_MW_DMA_2,	"MW DMA 2" },
-		{ XFER_MW_DMA_1,	"MW DMA 1" },
-		{ XFER_MW_DMA_0,	"MW DMA 0" },
-		{ XFER_SW_DMA_2,	"SW DMA 2" },
-		{ XFER_SW_DMA_1,	"SW DMA 1" },
-		{ XFER_SW_DMA_0,	"SW DMA 0" },
-		{ XFER_PIO_4,		"PIO 4" },
-		{ XFER_PIO_3,		"PIO 3" },
-		{ XFER_PIO_2,		"PIO 2" },
-		{ XFER_PIO_1,		"PIO 1" },
-		{ XFER_PIO_0,		"PIO 0" },
-		{ XFER_PIO_SLOW,	"PIO SLOW" },
-	};
-
-	int i = 0;
-
-	for (; i < ARRAY_SIZE(xfer_verbose); i++)
-		if (xfer_verbose[i].rate == xfer_rate)
-			return xfer_verbose[i].name;
-	return "XFER ERROR";
-}
-
-/*
- * hd_driveid data come as little endian,
- * they need to be converted on big endian machines
- */
-void ide_fix_driveid(struct hd_driveid *id)
-{
-#ifndef __LITTLE_ENDIAN
-# ifdef __BIG_ENDIAN
-	int i;
-	unsigned short *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (unsigned short *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-		stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (unsigned short *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-		stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (unsigned short *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-		stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-	for (i = 0; i < 4; i++)
-		id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
-	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 22; i++)
-		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power      = __le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 14; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 31; i++)
-		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-	for (i = 0; i < 48; i++)
-		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word  = __le16_to_cpu(id->integrity_word);
-# else
-#  error "Please fix <asm/byteorder.h>"
-# endif
-#endif
-}
-
-int ide_driveid_update(struct ata_device *drive)
-{
-	/*
-	 * Re-read drive->id for possible DMA mode
-	 * change (copied from ide-probe.c)
-	 */
-	struct hd_driveid *id;
-	unsigned long timeout, flags;
-
-	SELECT_MASK(drive->channel, drive, 1);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
-	ide_delay_50ms();
-	OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG);
-	timeout = jiffies + WAIT_WORSTCASE;
-	do {
-		if (0 < (signed long)(jiffies - timeout)) {
-			SELECT_MASK(drive->channel, drive, 0);
-			return 0;	/* drive timed-out */
-		}
-		ide_delay_50ms();	/* give drive a breather */
-	} while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
-	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
-	if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
-		SELECT_MASK(drive->channel, drive, 0);
-		printk("%s: CHECK for good STATUS\n", drive->name);
-		return 0;
-	}
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only; some systems need this */
-	SELECT_MASK(drive->channel, drive, 0);
-	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
-	if (!id) {
-		__restore_flags(flags);	/* local CPU only */
-		return 0;
-	}
-	ata_read(drive, id, SECTOR_WORDS);
-	GET_STAT();		/* clear drive IRQ */
-	ide__sti();		/* local CPU only */
-	__restore_flags(flags);	/* local CPU only */
-	ide_fix_driveid(id);
-	if (id) {
-		drive->id->dma_ultra = id->dma_ultra;
-		drive->id->dma_mword = id->dma_mword;
-		drive->id->dma_1word = id->dma_1word;
-		/* anything more ? */
-		kfree(id);
-	}
-
-	return 1;
-}
-
-/*
- *  All hosts that use the 80c ribbon must use this!
- */
-byte eighty_ninty_three(struct ata_device *drive)
-{
-	return ((byte) ((drive->channel->udma_four) &&
-#ifndef CONFIG_IDEDMA_IVB
-			(drive->id->hw_config & 0x4000) &&
-#endif
-			(drive->id->hw_config & 0x6000)) ? 1 : 0);
-}
-
-/*
- * Similar to ide_wait_stat(), except it never calls ide_error internally.
- * This is a kludge to handle the new ide_config_drive_speed() function,
- * and should not otherwise be used anywhere.  Eventually, the tuneproc's
- * should be updated to return ide_startstop_t, in which case we can get
- * rid of this abomination again.  :)   -ml
- *
- * It is gone..........
- *
- * const char *msg == consider adding for verbose errors.
- */
-int ide_config_drive_speed(struct ata_device *drive, byte speed)
-{
-	struct ata_channel *hwif = drive->channel;
-	int i;
-	int error = 1;
-	u8 stat;
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(__CRIS__)
-	u8 unit = (drive->select.b.unit & 0x01);
-	outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
-#endif
-
-	/*
-	 * Don't use ide_wait_cmd here - it will
-	 * attempt to set_geometry and recalibrate,
-	 * but for some reason these don't work at
-	 * this point (lost interrupt).
-	 */
-        /*
-         * Select the drive, and issue the SETFEATURES command
-         */
-	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
-	udelay(1);
-	SELECT_DRIVE(drive->channel, drive);
-	SELECT_MASK(drive->channel, drive, 0);
-	udelay(1);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
-	OUT_BYTE(speed, IDE_NSECTOR_REG);
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
-	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
-	udelay(1);
-	/*
-	 * Wait for drive to become non-BUSY
-	 */
-	if ((stat = GET_STAT()) & BUSY_STAT) {
-		unsigned long flags, timeout;
-		__save_flags(flags);	/* local CPU only */
-		ide__sti();		/* local CPU only -- for jiffies */
-		timeout = jiffies + WAIT_CMD;
-		while ((stat = GET_STAT()) & BUSY_STAT) {
-			if (0 < (signed long)(jiffies - timeout))
-				break;
-		}
-		__restore_flags(flags); /* local CPU only */
-	}
-
-	/*
-	 * Allow status to settle, then read it again.
-	 * A few rare drives vastly violate the 400ns spec here,
-	 * so we'll wait up to 10usec for a "good" status
-	 * rather than expensively fail things immediately.
-	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
-	 */
-	for (i = 0; i < 10; i++) {
-		udelay(1);
-		if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
-			error = 0;
-			break;
-		}
-	}
-
-	SELECT_MASK(drive->channel, drive, 0);
-
-	enable_irq(hwif->irq);
-
-	if (error) {
-		ide_dump_status(drive, NULL, "set_drive_speed_status", stat);
-		return error;
-	}
-
-	drive->id->dma_ultra &= ~0xFF00;
-	drive->id->dma_mword &= ~0x0F00;
-	drive->id->dma_1word &= ~0x0F00;
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(__CRIS__)
-	if (speed > XFER_PIO_4) {
-		outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
-	} else {
-		outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
-	}
-#endif
-
-	switch(speed) {
-		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
-		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
-		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
-		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
-		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
-		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
-		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
-		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
-		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
-		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
-		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
-		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
-		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
-		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
-		default: break;
-	}
-	return error;
-}
-
-EXPORT_SYMBOL(ide_fix_driveid);
-EXPORT_SYMBOL(ide_driveid_update);
-EXPORT_SYMBOL(eighty_ninty_three);
-EXPORT_SYMBOL(ide_config_drive_speed);
diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
--- a/drivers/ide/ide-floppy.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/ide-floppy.c	Wed May 29 11:43:02 2002
@@ -2036,7 +2036,7 @@
 	channel = drive->channel;
 	unit = drive - channel->drives;
 
-	ide_revalidate_disk(mk_kdev(channel->major, unit << PARTN_BITS));
+	ata_revalidate(mk_kdev(channel->major, unit << PARTN_BITS));
 }
 
 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
diff -Nru a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c
--- a/drivers/ide/ide-geometry.c	Wed May 29 11:43:01 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,145 +0,0 @@
-/*
- * Sun Feb 24 23:13:03 CET 2002: Patch by Andries Brouwer to remove the
- * confused CMOS probe applied. This is solving more problems than it may
- * (unexpectedly) introduce.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/ide.h>
-#include <linux/mc146818rtc.h>
-#include <asm/io.h>
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-
-extern struct ata_device * get_info_ptr(kdev_t);
-
-/*
- * If heads is nonzero: find a translation with this many heads and S=63.
- * Otherwise: find out how OnTrack Disk Manager would translate the disk.
- */
-static void
-ontrack(struct ata_device *drive, int heads, unsigned int *c, int *h, int *s)
-{
-	static const u8 dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
-	const u8 *headp = dm_head_vals;
-	unsigned long total;
-
-	/*
-	 * The specs say: take geometry as obtained from Identify, compute
-	 * total capacity C*H*S from that, and truncate to 1024*255*63. Now
-	 * take S=63, H the first in the sequence 4, 8, 16, 32, 64, 128, 255
-	 * such that 63*H*1024 >= total.  [Please tell aeb@cwi.nl in case this
-	 * computes a geometry different from what OnTrack uses.]
-	 */
-
-	total = ata_capacity(drive);
-
-	*s = 63;
-
-	if (heads) {
-		*h = heads;
-		*c = total / (63 * heads);
-		return;
-	}
-
-	while (63 * headp[0] * 1024 < total && headp[1] != 0)
-		 headp++;
-	*h = headp[0];
-	*c = total / (63 * headp[0]);
-}
-
-/*
- * This routine is called from the partition-table code in pt/msdos.c.
- * It has two tasks:
- * (i) to handle Ontrack DiskManager by offsetting everything by 63 sectors,
- *  or to handle EZdrive by remapping sector 0 to sector 1.
- * (ii) to invent a translated geometry.
- * Part (i) is suppressed if the user specifies the "noremap" option
- * on the command line.
- * Part (ii) is suppressed if the user specifies an explicit geometry.
- *
- * The ptheads parameter is either 0 or tells about the number of
- * heads shown by the end of the first nonempty partition.
- * If this is either 16, 32, 64, 128, 240 or 255 we'll believe it.
- *
- * The xparm parameter has the following meaning:
- *	 0 = convert to CHS with fewer than 1024 cyls
- *	     using the same method as Ontrack DiskManager.
- *	 1 = same as "0", plus offset everything by 63 sectors.
- *	-1 = similar to "0", plus redirect sector 0 to sector 1.
- *	 2 = convert to a CHS geometry with "ptheads" heads.
- *
- * Returns 0 if the translation was not possible, if the device was not
- * an IDE disk drive, or if a geometry was "forced" on the commandline.
- * Returns 1 if the geometry translation was successful.
- */
-int ide_xlate_1024(kdev_t i_rdev, int xparm, int ptheads, const char *msg)
-{
-	struct ata_device *drive;
-	const char *msg1 = "";
-	int heads = 0;
-	int c, h, s;
-	int transl = 1;		/* try translation */
-	int ret = 0;
-
-	drive = get_info_ptr(i_rdev);
-	if (!drive)
-		return 0;
-
-	/* remap? */
-	if (drive->remap_0_to_1 != 2) {
-		if (xparm == 1) {		/* DM */
-			drive->sect0 = 63;
-			msg1 = " [remap +63]";
-			ret = 1;
-		} else if (xparm == -1) {	/* EZ-Drive */
-			if (drive->remap_0_to_1 == 0) {
-				drive->remap_0_to_1 = 1;
-				msg1 = " [remap 0->1]";
-				ret = 1;
-			}
-		}
-	}
-
-	/* There used to be code here that assigned drive->id->CHS
-	   to drive->CHS and that to drive->bios_CHS. However,
-	   some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB.
-	   In such cases that code was wrong.  Moreover,
-	   there seems to be no reason to do any of these things. */
-
-	/* translate? */
-	if (drive->forced_geom)
-		transl = 0;
-
-	/* does ptheads look reasonable? */
-	if (ptheads == 32 || ptheads == 64 || ptheads == 128 ||
-	    ptheads == 240 || ptheads == 255)
-		heads = ptheads;
-
-	if (xparm == 2) {
-		if (!heads ||
-		   (drive->bios_head >= heads && drive->bios_sect == 63))
-			transl = 0;
-	}
-	if (xparm == -1) {
-		if (drive->bios_head > 16)
-			transl = 0;     /* we already have a translation */
-	}
-
-	if (transl) {
-		ontrack(drive, heads, &c, &h, &s);
-		drive->bios_cyl = c;
-		drive->bios_head = h;
-		drive->bios_sect = s;
-		ret = 1;
-	}
-
-	drive->part[0].nr_sects = ata_capacity(drive);
-
-	if (ret)
-		printk("%s%s [%d/%d/%d]", msg, msg1,
-		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
-	return ret;
-}
-#endif
diff -Nru a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
--- a/drivers/ide/ide-pci.c	Wed May 29 11:43:03 2002
+++ b/drivers/ide/ide-pci.c	Wed May 29 11:43:03 2002
@@ -27,10 +27,6 @@
 
 #include "pcihost.h"
 
-/* Missing PCI device IDs: */
-#define PCI_VENDOR_ID_HINT 0x3388
-#define PCI_DEVICE_ID_HINT 0x8013
-
 /*
  * This is the list of registered PCI chipset driver data structures.
  */
@@ -66,85 +62,68 @@
 }
 
 /*
- * This allows off board ide-pci cards the enable a BIOS, verify interrupt
- * settings of split-mirror pci-config space, place chipset into init-mode,
- * and/or preserve an interrupt if the card is not native ide support.
- */
-static unsigned int __init trust_pci_irq(struct ata_pci_device *d, struct pci_dev *dev)
-{
-	if (d->flags & ATA_F_IRQ)
-		return dev->irq;
-
-	return 0;
-}
-
-/*
  * Match a PCI IDE port against an entry in ide_hwifs[],
  * based on io_base port if possible.
  */
 static struct ata_channel __init *lookup_channel(unsigned long io_base, int bootable, const char *name)
 {
 	int h;
-	struct ata_channel *hwif;
+	struct ata_channel *ch;
 
 	/*
-	 * Look for a hwif with matching io_base specified using
-	 * parameters to ide_setup().
+	 * Look for a channel with matching io_base default value.  If chipset is
+	 * "ide_unknown", then claim that channel slot.  Otherwise, some other
+	 * chipset has already claimed it..  :(
 	 */
 	for (h = 0; h < MAX_HWIFS; ++h) {
-		hwif = &ide_hwifs[h];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (hwif->chipset == ide_generic)
-				return hwif; /* a perfect match */
-		}
-	}
-	/*
-	 * Look for a hwif with matching io_base default value.
-	 * If chipset is "ide_unknown", then claim that hwif slot.
-	 * Otherwise, some other chipset has already claimed it..  :(
-	 */
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		hwif = &ide_hwifs[h];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (hwif->chipset == ide_unknown)
-				return hwif; /* match */
-			printk("%s: port 0x%04lx already claimed by %s\n", name, io_base, hwif->name);
+		ch = &ide_hwifs[h];
+		if (ch->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (ch->chipset == ide_generic)
+				return ch; /* a perfect match */
+			if (ch->chipset == ide_unknown)
+				return ch; /* match */
+			printk(KERN_INFO "%s: port 0x%04lx already claimed by %s\n",
+					name, io_base, ch->name);
 			return NULL;	/* already claimed */
 		}
 	}
+
 	/*
-	 * Okay, there is no hwif matching our io_base,
-	 * so we'll just claim an unassigned slot.
+	 * Okay, there is no ch matching our io_base, so we'll just claim an
+	 * unassigned slot.
+	 *
 	 * Give preference to claiming other slots before claiming ide0/ide1,
-	 * just in case there's another interface yet-to-be-scanned
-	 * which uses ports 1f0/170 (the ide0/ide1 defaults).
+	 * just in case there's another interface yet-to-be-scanned which uses
+	 * ports 1f0/170 (the ide0/ide1 defaults).
 	 *
-	 * Unless there is a bootable card that does not use the standard
-	 * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
+	 * Unless there is a bootable card that does not use the standard ports
+	 * 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
 	 */
+
 	if (bootable == ON_BOARD) {
 		for (h = 0; h < MAX_HWIFS; ++h) {
-			hwif = &ide_hwifs[h];
-			if (hwif->chipset == ide_unknown)
-				return hwif;	/* pick an unused entry */
+			ch = &ide_hwifs[h];
+			if (ch->chipset == ide_unknown)
+				return ch;	/* pick an unused entry */
 		}
 	} else {
 		for (h = 2; h < MAX_HWIFS; ++h) {
-			hwif = ide_hwifs + h;
-			if (hwif->chipset == ide_unknown)
-				return hwif;	/* pick an unused entry */
+			ch = &ide_hwifs[h];
+			if (ch->chipset == ide_unknown)
+				return ch;	/* pick an unused entry */
 		}
 	}
 	for (h = 0; h < 2; ++h) {
-		hwif = ide_hwifs + h;
-		if (hwif->chipset == ide_unknown)
-			return hwif;	/* pick an unused entry */
+		ch = &ide_hwifs[h];
+		if (ch->chipset == ide_unknown)
+			return ch;	/* pick an unused entry */
 	}
-	printk("%s: too many IDE interfaces, no room in table\n", name);
+	printk(KERN_INFO "%s: too many ATA interfaces.\n", name);
+
 	return NULL;
 }
 
-static int __init setup_pci_baseregs (struct pci_dev *dev, const char *name)
+static int __init setup_pci_baseregs(struct pci_dev *dev, const char *name)
 {
 	u8 reg;
 	u8 progif = 0;
@@ -179,110 +158,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-
-/*
- * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
- */
-static unsigned long __init get_dma_base(struct ata_channel *hwif, int extra, const char *name)
-{
-	unsigned long	dma_base = 0;
-	struct pci_dev	*dev = hwif->pci_dev;
-
-	dma_base = pci_resource_start(dev, 4);
-	if (!dma_base)
-		return 0;
-
-	/* PDC20246, PDC20262, HPT343, & HPT366 */
-	if (extra) {
-		request_region(dma_base + 16, extra, name);
-		hwif->dma_extra = extra;
-	}
-
-	/* If we are on the second channel, the dma base address will be one
-	 * entry away from the primary interface.
-	 */
-	if (hwif->unit == ATA_SECONDARY)
-		dma_base += 8;
-
-	if ((dev->vendor == PCI_VENDOR_ID_AL && dev->device == PCI_DEVICE_ID_AL_M5219) ||
-			(dev->vendor == PCI_VENDOR_ID_AMD && dev->device == PCI_DEVICE_ID_AMD_VIPER_7409) ||
-			(dev->vendor == PCI_VENDOR_ID_CMD && dev->device == PCI_DEVICE_ID_CMD_643) ||
-			(dev->vendor == PCI_VENDOR_ID_SERVERWORKS && dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)) {
-		outb(inb(dma_base + 2) & 0x60, dma_base+2);
-		if (inb(dma_base + 2) & 0x80)
-			printk(KERN_INFO "%s: simplex device: DMA forced\n", name);
-	} else {
-
-		/* If the device claims "simplex" DMA, this means only one of
-		 * the two interfaces can be trusted with DMA at any point in
-		 * time.  So we should enable DMA only on one of the two
-		 * interfaces.
-		 */
-
-		if ((inb(dma_base + 2) & 0x80)) {
-			if ((!hwif->drives[0].present && !hwif->drives[1].present) ||
-				hwif->unit == ATA_SECONDARY) {
-				printk("%s: simplex device:  DMA disabled\n", name);
-				dma_base = 0;
-			}
-		}
-	}
-
-	return dma_base;
-}
-
-/*
- * Setup DMA transfers on a channel.
- */
-static void __init setup_channel_dma(struct ata_channel *ch,
-		struct pci_dev *dev,
-		struct ata_pci_device *d,
-		int port,
-		u8 class_rev,
-		int pciirq,
-		int autodma,
-		unsigned short *pcicmd)
-{
-	unsigned long dma_base;
-
-	if (d->flags & ATA_F_NOADMA)
-		autodma = 0;
-
-	if (autodma)
-		ch->autodma = 1;
-
-	if (!((d->flags & ATA_F_DMA) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))))
-		return;
-
-	dma_base = get_dma_base(ch, ((port == ATA_PRIMARY) && d->extra) ? d->extra : 0, dev->name);
-	if (!dma_base) {
-		printk("%s: %s Bus-Master DMA was disabled by BIOS\n",
-				ch->name, dev->name);
-
-		return;
-	}
-	if (!(*pcicmd & PCI_COMMAND_MASTER)) {
-
-		/*
-		 * Set up BM-DMA capability (PnP BIOS should have done this already)
-		 */
-		if (!(d->vendor == PCI_VENDOR_ID_CYRIX && d->device == PCI_DEVICE_ID_CYRIX_5530_IDE))
-			ch->autodma = 0;	/* default DMA off if we had to configure it here */
-		pci_write_config_word(dev, PCI_COMMAND, *pcicmd | PCI_COMMAND_MASTER);
-		if (pci_read_config_word(dev, PCI_COMMAND, pcicmd) || !(*pcicmd & PCI_COMMAND_MASTER)) {
-			printk("%s: %s error updating PCICMD\n",
-					ch->name, dev->name);
-			dma_base = 0;
-		}
-	}
-	if (d->init_dma)
-		d->init_dma(ch, dma_base);
-	else
-		ata_init_dma(ch, dma_base);
-}
-#endif
-
 /*
  * Setup a particular port on an ATA host controller.
  *
@@ -297,6 +172,7 @@
 		unsigned short *pcicmd)
 {
 	unsigned long base = 0;
+	unsigned long dma_base;
 	unsigned long ctl = 0;
 	ide_pci_enablebit_t *e = &(d->enablebits[port]);
 	struct ata_channel *ch;
@@ -355,7 +231,7 @@
 		base = port ? 0x170 : 0x1f0;
 
 	if ((ch = lookup_channel(base, d->bootable, dev->name)) == NULL)
-		return -ENOMEM;	/* no room in ide_hwifs[] */
+		return -ENOMEM;	/* no room */
 
 	if (ch->io_ports[IDE_DATA_OFFSET] != base) {
 		ide_init_hwif_ports(&ch->hw, base, (ctl | 2), NULL);
@@ -391,7 +267,79 @@
 	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	setup_channel_dma(ch, dev, d, port, class_rev, pciirq, autodma, pcicmd);
+	/*
+	 * Setup DMA transfers on the channel.
+	 */
+	if (d->flags & ATA_F_NOADMA)
+		autodma = 0;
+
+	if (autodma)
+		ch->autodma = 1;
+
+	if (!((d->flags & ATA_F_DMA) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))))
+		goto no_dma;
+	/*
+	 * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
+	 */
+	dma_base = pci_resource_start(dev, 4);
+	if (dma_base) {
+		/* PDC20246, PDC20262, HPT343, & HPT366 */
+		if ((ch->unit == ATA_PRIMARY) && d->extra) {
+			request_region(dma_base + 16, d->extra, dev->name);
+			ch->dma_extra = d->extra;
+		}
+
+		/* If we are on the second channel, the dma base address will
+		 * be one entry away from the primary interface.
+		 */
+		if (ch->unit == ATA_SECONDARY)
+			dma_base += 8;
+
+		if (d->flags & ATA_F_SIMPLEX) {
+			outb(inb(dma_base + 2) & 0x60, dma_base + 2);
+			if (inb(dma_base + 2) & 0x80)
+				printk(KERN_INFO "%s: simplex device: DMA forced\n", dev->name);
+		} else {
+			/* If the device claims "simplex" DMA, this means only
+			 * one of the two interfaces can be trusted with DMA at
+			 * any point in time.  So we should enable DMA only on
+			 * one of the two interfaces.
+			 */
+			if ((inb(dma_base + 2) & 0x80)) {
+				if ((!ch->drives[0].present && !ch->drives[1].present) ||
+						ch->unit == ATA_SECONDARY) {
+					printk(KERN_INFO "%s: simplex device:  DMA disabled\n", dev->name);
+					dma_base = 0;
+				}
+			}
+		}
+	} else {
+		printk(KERN_INFO "%s: %s Bus-Master DMA was disabled by BIOS\n",
+				ch->name, dev->name);
+
+		goto no_dma;
+	}
+	if (!(*pcicmd & PCI_COMMAND_MASTER)) {
+		/*
+		 * Set up BM-DMA capability (PnP BIOS should have done this
+		 * already).  Default to DMA off on the drive, if we had to
+		 * configure it here.  This should most propably be enabled no
+		 * all chipsets which can be expected to be used on systems
+		 * without a BIOS equivalent.
+		 */
+		if (!(d->flags | ATA_F_FDMA))
+			ch->autodma = 0;
+		pci_write_config_word(dev, PCI_COMMAND, *pcicmd | PCI_COMMAND_MASTER);
+		if (pci_read_config_word(dev, PCI_COMMAND, pcicmd) || !(*pcicmd & PCI_COMMAND_MASTER)) {
+			printk("%s: %s error updating PCICMD\n",
+					ch->name, dev->name);
+			dma_base = 0;
+		}
+	}
+	if (d->init_dma)
+		d->init_dma(ch, dma_base);
+	else
+		ata_init_dma(ch, dma_base);
 #endif
 
 no_dma:
@@ -432,7 +380,7 @@
 
 check_if_enabled:
 	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
-		printk("%s: error accessing PCI regs\n", dev->name);
+		printk(KERN_ERR "%s: error accessing PCI regs\n", dev->name);
 		return;
 	}
 	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
@@ -499,8 +447,12 @@
 		 */
 		if (d->init_chipset)
 			pciirq = d->init_chipset(dev);
-		else
-			pciirq = trust_pci_irq(d, dev);
+		else {
+			if (d->flags & ATA_F_IRQ)
+				pciirq = dev->irq;
+			else
+				pciirq =  0;
+		}
 	} else if (tried_config) {
 		printk(KERN_INFO "ATA: will probe IRQs later\n");
 		pciirq = 0;
@@ -524,6 +476,10 @@
 	setup_host_channel(dev, d, ATA_SECONDARY, class_rev, pciirq, autodma, &pcicmd);
 }
 
+/*
+ * Fix crossover IRQ line setups between primary and secondary channel.  Quite
+ * a common bug apparently.
+ */
 static void __init pdc20270_device_order_fixup (struct pci_dev *dev, struct ata_pci_device *d)
 {
 	struct pci_dev *dev2 = NULL;
@@ -756,7 +712,7 @@
 	},
 	{
 		vendor: PCI_VENDOR_ID_HINT,
-		device: PCI_DEVICE_ID_HINT,
+		device: PCI_DEVICE_ID_HINT_VXPROII_IDE,
 		bootable: ON_BOARD
 	},
 	{
diff -Nru a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
--- a/drivers/ide/ide-pmac.c	Wed May 29 11:43:03 2002
+++ b/drivers/ide/ide-pmac.c	Wed May 29 11:43:03 2002
@@ -1247,9 +1247,6 @@
 		return 0;
 	}
 
-	if (!drive->init_speed)
-		drive->init_speed = feature;
-
 	/* which drive is it ? */
 	if (drive->select.b.unit & 0x01)
 		timings = &pmac_ide[idx].timings[1];
@@ -1285,9 +1282,6 @@
 		printk(KERN_WARNING "%s: Failed !\n", drive->name);
 		return 0;
 	}
-
-	if (!drive->init_speed)
-		drive->init_speed = feature;
 
 	/* which drive is it ? */
 	if (drive->select.b.unit & 0x01)
diff -Nru a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
--- a/drivers/ide/ide-pnp.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/ide-pnp.c	Wed May 29 11:43:02 2002
@@ -1,5 +1,4 @@
-/*
- * linux/drivers/ide/ide-pnp.c
+/**** vi:set ts=8 sts=8 sw=8:************************************************
  *
  * This file provides autodetection for ISA PnP IDE interfaces.
  * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
@@ -33,21 +32,6 @@
 
 #define DEV_NAME(dev) (dev->bus->name ? dev->bus->name : "ISA PnP")
 
-#define GENERIC_HD_DATA		0
-#define GENERIC_HD_ERROR	1
-#define GENERIC_HD_NSECTOR	2
-#define GENERIC_HD_SECTOR	3
-#define GENERIC_HD_LCYL		4
-#define GENERIC_HD_HCYL		5
-#define GENERIC_HD_SELECT	6
-#define GENERIC_HD_STATUS	7
-
-static int generic_ide_offsets[IDE_NR_PORTS] __initdata = {
-	GENERIC_HD_DATA, GENERIC_HD_ERROR, GENERIC_HD_NSECTOR, 
-	GENERIC_HD_SECTOR, GENERIC_HD_LCYL, GENERIC_HD_HCYL,
-	GENERIC_HD_SELECT, GENERIC_HD_STATUS, -1, -1
-};
-
 /* ISA PnP device table entry */
 struct pnp_dev_t {
 	unsigned short card_vendor, card_device, vendor, device;
@@ -58,8 +42,8 @@
 static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
 {
 	hw_regs_t hw;
-	struct ata_channel *hwif;
 	int index;
+	int i;
 
 	if (!enable)
 		return 0;
@@ -67,15 +51,24 @@
 	if (!(DEV_IO(dev, 0) && DEV_IO(dev, 1) && DEV_IRQ(dev, 0)))
 		return 1;
 
-	ide_setup_ports(&hw, (ide_ioreg_t) DEV_IO(dev, 0),
-			generic_ide_offsets, (ide_ioreg_t) DEV_IO(dev, 1),
-			0, NULL, DEV_IRQ(dev, 0));
+	/* Initialize register access base values. */
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
+		hw.io_ports[i] = DEV_IO(dev, 0) + i;
+	hw.io_ports[IDE_CONTROL_OFFSET] = DEV_IO(dev, 1);
+
+	hw.irq = DEV_IRQ(dev, 0);
+	hw.dma = NO_DMA;
+	hw.ack_intr = NULL;
 
-	index = ide_register_hw(&hw, &hwif);
+	index = ide_register_hw(&hw);
 
 	if (index != -1) {
-		hwif->pci_dev = dev;
+		struct ata_channel *ch;
+
+		ch = &ide_hwifs[index];
+		ch->pci_dev = dev;
 		printk(KERN_INFO "ide%d: %s IDE interface\n", index, DEV_NAME(dev));
+
 		return 0;
 	}
 
@@ -83,11 +76,13 @@
 }
 
 /* Add your devices here :)) */
-struct pnp_dev_t idepnp_devices[] __initdata = {
-  	/* Generic ESDI/IDE/ATA compatible hard disk controller */
-	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+static struct pnp_dev_t pnp_devices[] __initdata = {
+	/* Generic ESDI/IDE/ATA compatible hard disk controller */
+	{
+		ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600),
-		pnpide_generic_init },
+		pnpide_generic_init
+	},
 	{	0 }
 };
 
@@ -125,14 +120,14 @@
 		return;
 	}
 #endif
-	for (dev_type = idepnp_devices; dev_type->vendor; dev_type++) {
+	for (dev_type = pnp_devices; dev_type->vendor; dev_type++) {
 		while ((dev = isapnp_find_dev(NULL, dev_type->vendor,
 			dev_type->device, dev))) {
 
 			if (dev->active)
 				continue;
 
-       			if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
+			if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
 				printk(KERN_ERR "ide: %s prepare failed\n", DEV_NAME(dev));
 				continue;
 			}
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Wed May 29 11:43:01 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,904 +0,0 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
- *
- *  Mostly written by Mark Lord <mlord@pobox.com>
- *                and Gadi Oxman <gadio@netvision.net.il>
- *                and Andre Hedrick <andre@linux-ide.org>
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- * This is the IDE probe module, as evolved from hd.c and ide.c.
- *
- * Version 1.00		move drive probing code from ide.c to ide-probe.c
- * Version 1.01		fix compilation problem for m68k
- * Version 1.02		increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot
- *			 by Andrea Arcangeli
- * Version 1.03		fix for (hwif->chipset == ide_4drives)
- * Version 1.04		fixed buggy treatments of known flash memory cards
- *
- * Version 1.05		fix for (hwif->chipset == ide_pdc4030)
- *			added ide6/7/8/9
- *			allowed for secondary flash card to be detectable
- *			 with new flag : drive->ata_flash : 1;
- * Version 1.06		stream line request queue and prep for cascade project.
- * Version 1.07		max_sect <= 255; slower disks would get behind and
- *			then fall over when they get to 256.	Paul G.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/spinlock.h>
-#include <linux/pci.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-static inline void do_identify(struct ata_device *drive, u8 cmd)
-{
-	int bswap = 1;
-	struct hd_driveid *id;
-
-	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);	/* called with interrupts disabled! */
-	if (!id) {
-		printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
-		goto err_kmalloc;
-	}
-
-	/* Read 512 bytes of id info.
-	 *
-	 * Please note that it is well known that some *very* old drives are
-	 * able to provide only 256 of them, since this was the amount read by
-	 * DOS.
-	 *
-	 * However let's try to get away with this...
-	 */
-
-#if 1
-	ata_read(drive, id, SECTOR_WORDS);
-#else
-        {
-                unsigned long   *ptr = (unsigned long *)id ;
-                unsigned long   lcount = 256/2 ;
-                // printk("IDE_DATA_REG = %#lx",IDE_DATA_REG);
-                while( lcount-- )
-                        *ptr++ = inl(IDE_DATA_REG);
-        }
-#endif
-	ide__sti();	/* local CPU only */
-	ide_fix_driveid(id);
-
-	if (id->word156 == 0x4d42) {
-		printk("%s: drive->id->word156 == 0x%04x \n", drive->name, drive->id->word156);
-	}
-
-	if (!drive->forced_lun)
-		drive->last_lun = id->last_lun & 0x7;
-#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
-	/*
-	 * EATA SCSI controllers do a hardware ATA emulation:
-	 * Ignore them if there is a driver for them available.
-	 */
-	if ((id->model[0] == 'P' && id->model[1] == 'M')
-	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
-		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
-		goto err_misc;
-	}
-#endif
-
-	/*
-	 *  WIN_IDENTIFY returns little-endian info,
-	 *  WIN_PIDENTIFY *usually* returns little-endian info.
-	 */
-	if (cmd == WIN_PIDENTIFY) {
-		if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
-		 || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
-		 || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
-			bswap ^= 1;	/* Vertos drives may still be weird */
-	}
-	ide_fixstring (id->model,     sizeof(id->model),     bswap);
-	ide_fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
-	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
-
-	if (strstr(id->model, "E X A B Y T E N E S T"))
-		goto err_misc;
-
-	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
-	printk("%s: %s, ", drive->name, id->model);
-	drive->present = 1;
-
-	/*
-	 * Check for an ATAPI device:
-	 */
-	if (cmd == WIN_PIDENTIFY) {
-		byte type = (id->config >> 8) & 0x1f;
-		printk("ATAPI ");
-#ifdef CONFIG_BLK_DEV_PDC4030
-		if (drive->channel->unit == 1 && drive->channel->chipset == ide_pdc4030) {
-			printk(" -- not supported on 2nd Promise port\n");
-			goto err_misc;
-		}
-#endif
-		switch (type) {
-			case ATA_FLOPPY:
-				if (!strstr(id->model, "CD-ROM")) {
-					if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP"))
-						printk("cdrom or floppy?, assuming ");
-					if (drive->type != ATA_ROM) {
-						printk ("FLOPPY");
-						break;
-					}
-				}
-				type = ATA_ROM;	/* Early cdrom models used zero */
-			case ATA_ROM:
-				drive->removable = 1;
-#ifdef CONFIG_PPC
-				/* kludge for Apple PowerBook internal zip */
-				if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) {
-					printk ("FLOPPY");
-					type = ATA_FLOPPY;
-					break;
-				}
-#endif
-				printk ("CD/DVD-ROM");
-				break;
-			case ATA_TAPE:
-				printk ("TAPE");
-				break;
-			case ATA_MOD:
-				printk ("OPTICAL");
-				drive->removable = 1;
-				break;
-			default:
-				printk("UNKNOWN (type %d)", type);
-				break;
-		}
-		printk (" drive\n");
-		drive->type = type;
-		return;
-	}
-
-	/*
-	 * Not an ATAPI device: looks like a "regular" hard disk:
-	 */
-	if (id->config & (1<<7))
-		drive->removable = 1;
-
-	/*
-	 * FIXME: This is just plain ugly or plain unnecessary.
-	 *
-	 * Prevent long system lockup probing later for non-existant slave
-	 * drive if the hwif is actually a flash memory card of some variety:
-	 */
-
-	if (drive_is_flashcard(drive)) {
-		struct ata_device *mate = &drive->channel->drives[1 ^ drive->select.b.unit];
-		if (!mate->ata_flash) {
-			mate->present = 0;
-			mate->noprobe = 1;
-		}
-	}
-	drive->type = ATA_DISK;
-	printk("ATA DISK drive\n");
-
-	/* Initialize our quirk list. */
-	if (drive->channel->quirkproc)
-		drive->quirk_list = drive->channel->quirkproc(drive);
-
-	/* Initialize queue depth settings */
-	drive->queue_depth = 1;
-#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEPTH
-	drive->queue_depth = CONFIG_BLK_DEV_IDE_TCQ_DEPTH;
-#else
-	drive->queue_depth = drive->id->queue_depth + 1;
-#endif
-	if (drive->queue_depth < 1 || drive->queue_depth > IDE_MAX_TAG)
-		drive->queue_depth = IDE_MAX_TAG;
-
-	return;
-
-err_misc:
-	kfree(id);
-err_kmalloc:
-	drive->present = 0;
-
-	return;
-}
-
-/*
- * Sends an ATA(PI) IDENTIFY request to a drive and wait for a response.  It
- * also monitor irqs while this is happening, in hope of automatically
- * determining which one is being used by the interface.
- *
- * Returns:	0  device was identified
- *		1  device timed-out (no response to identify request)
- *		2  device aborted the command (refused to identify itself)
- */
-static int identify(struct ata_device *drive, u8 cmd)
-{
-	int rc;
-	int autoprobe = 0;
-	unsigned long cookie = 0;
-	ide_ioreg_t hd_status;
-	unsigned long timeout;
-	u8 s;
-	u8 a;
-
-
-	if (IDE_CONTROL_REG && !drive->channel->irq) {
-		autoprobe = 1;
-		cookie = probe_irq_on();
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
-	}
-
-	rc = 1;
-	if (IDE_CONTROL_REG) {
-		/* take a deep breath */
-		ide_delay_50ms();
-		a = IN_BYTE(IDE_ALTSTATUS_REG);
-		s = IN_BYTE(IDE_STATUS_REG);
-		if ((a ^ s) & ~INDEX_STAT) {
-			printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
-			hd_status = IDE_STATUS_REG;	/* ancient Seagate drives, broken interfaces */
-		} else {
-			hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
-		}
-	} else {
-		ide_delay_50ms();
-		hd_status = IDE_STATUS_REG;
-	}
-
-	/* set features register for atapi identify command to be sure of reply */
-	if ((cmd == WIN_PIDENTIFY))
-		OUT_BYTE(0,IDE_FEATURE_REG);	/* disable dma & overlap */
-
-#if CONFIG_BLK_DEV_PDC4030
-	if (drive->channel->chipset == ide_pdc4030) {
-		/* DC4030 hosted drives need their own identify... */
-		extern int pdc4030_identify(struct ata_device *);
-
-		if (pdc4030_identify(drive))
-			goto out;
-	} else
-#endif
-		OUT_BYTE(cmd,IDE_COMMAND_REG);		/* ask drive for ID */
-	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
-	timeout += jiffies;
-	do {
-		if (time_after(jiffies, timeout))
-			goto out;	/* drive timed-out */
-		ide_delay_50ms();		/* give drive a breather */
-	} while (IN_BYTE(hd_status) & BUSY_STAT);
-
-	ide_delay_50ms();		/* wait for IRQ and DRQ_STAT */
-	if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
-		unsigned long flags;
-		__save_flags(flags);	/* local CPU only */
-		__cli();		/* local CPU only; some systems need this */
-		do_identify(drive, cmd); /* drive returned ID */
-		rc = 0;			/* drive responded with ID */
-		(void) GET_STAT();	/* clear drive IRQ */
-		__restore_flags(flags);	/* local CPU only */
-	} else
-		rc = 2;			/* drive refused ID */
-
-out:
-	if (autoprobe) {
-		int irq;
-		OUT_BYTE(drive->ctl | 0x02, IDE_CONTROL_REG);	/* mask device irq */
-		GET_STAT();			/* clear drive IRQ */
-		udelay(5);
-		irq = probe_irq_off(cookie);
-		if (!drive->channel->irq) {
-			if (irq > 0)
-				drive->channel->irq = irq;
-			else	/* Mmmm.. multiple IRQs.. don't know which was ours */
-				printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
-		}
-	}
-
-	return rc;
-}
-
-
-/*
- * do_probe() has the difficult job of finding a drive if it exists,
- * without getting hung up if it doesn't exist, without trampling on
- * ethernet cards, and without leaving any IRQs dangling to haunt us later.
- *
- * If a drive is "known" to exist (from CMOS or kernel parameters),
- * but does not respond right away, the probe will "hang in there"
- * for the maximum wait time (about 30 seconds), otherwise it will
- * exit much more quickly.
- *
- * Returns:	0  device was identified
- *		1  device timed-out (no response to identify request)
- *		2  device aborted the command (refused to identify itself)
- *		3  bad status from device (possible for ATAPI drives)
- *		4  probe was not attempted because failure was obvious
- */
-static int do_probe(struct ata_device *drive, byte cmd)
-{
-	int rc;
-	struct ata_channel *hwif = drive->channel;
-
-	if (drive->present) {	/* avoid waiting for inappropriate probes */
-		if ((drive->type != ATA_DISK) && (cmd == WIN_IDENTIFY))
-			return 4;
-	}
-#ifdef DEBUG
-	printk("probing for %s: present=%d, type=%d, probetype=%s\n",
-		drive->name, drive->present, drive->type,
-		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
-#endif
-	ide_delay_50ms();	/* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */
-	SELECT_DRIVE(hwif,drive);
-	ide_delay_50ms();
-	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
-		if (drive->select.b.unit != 0) {
-			SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
-			ide_delay_50ms();		/* allow BUSY_STAT to assert & clear */
-		}
-		return 3;    /* no i/f present: mmm.. this should be a 4 -ml */
-	}
-
-	if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) || drive->present || cmd == WIN_PIDENTIFY)
-	{
-		if ((rc = identify(drive,cmd)))   /* send cmd and wait */
-			rc = identify(drive,cmd); /* failed: try again */
-		if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {
-			unsigned long timeout;
-			printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT());
-			ide_delay_50ms();
-			OUT_BYTE (drive->select.all, IDE_SELECT_REG);
-			ide_delay_50ms();
-			OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
-			timeout = jiffies;
-			while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE))
-				ide_delay_50ms();
-			rc = identify(drive, cmd);
-		}
-		if (rc == 1)
-			printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT());
-		(void) GET_STAT();		/* ensure drive irq is clear */
-	} else
-		rc = 3;				/* not present or maybe ATAPI */
-
-	if (drive->select.b.unit != 0) {
-		SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
-		ide_delay_50ms();
-		(void) GET_STAT();		/* ensure drive irq is clear */
-	}
-	return rc;
-}
-
-static void enable_nest(struct ata_device *drive)
-{
-	unsigned long timeout;
-
-	printk("%s: enabling %s -- ", drive->channel->name, drive->id->model);
-	SELECT_DRIVE(drive->channel, drive);
-	ide_delay_50ms();
-	OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
-	timeout = jiffies + WAIT_WORSTCASE;
-	do {
-		if (time_after(jiffies, timeout)) {
-			printk("failed (timeout)\n");
-			return;
-		}
-		ide_delay_50ms();
-	} while (GET_STAT() & BUSY_STAT);
-	ide_delay_50ms();
-	if (!OK_STAT(GET_STAT(), 0, BAD_STAT))
-		printk("failed (status = 0x%02x)\n", GET_STAT());
-	else
-		printk("success\n");
-	if (do_probe(drive, WIN_IDENTIFY) >= 2) {	/* if !(success||timed-out) */
-		(void) do_probe(drive, WIN_PIDENTIFY);	/* look for ATAPI device */
-	}
-}
-
-/*
- * Tests for existence of a given drive using do_probe().
- */
-static inline void probe_for_drive(struct ata_device *drive)
-{
-	if (drive->noprobe)			/* skip probing? */
-		return;
-
-	if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
-		do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
-	}
-
-	if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T"))
-		enable_nest(drive);
-
-	if (!drive->present)
-		return;			/* drive not found */
-
-	if (drive->id == NULL) {		/* identification failed? */
-		if (drive->type == ATA_DISK) {
-			printk ("%s: non-IDE drive, CHS=%d/%d/%d\n",
-			 drive->name, drive->cyl, drive->head, drive->sect);
-		} else if (drive->type == ATA_ROM) {
-			printk("%s: ATAPI cdrom (?)\n", drive->name);
-		} else {
-			drive->present = 0;	/* nuke it */
-		}
-	}
-}
-
-/*
- * This routine only knows how to look for drive units 0 and 1
- * on an interface, so any setting of MAX_DRIVES > 2 won't work here.
- */
-static void channel_probe(struct ata_channel *ch)
-{
-	unsigned int i;
-	unsigned long flags;
-	int error;
-
-	if (ch->noprobe)
-		return;
-
-	ch->straight8 = 0;
-
-	__save_flags(flags);	/* local CPU only */
-	__sti();		/* local CPU only; needed for jiffies and irq probing */
-
-	/*
-	 * Check for the presence of a channel by probing for drives on it.
-	 */
-	for (i = 0; i < MAX_DRIVES; ++i) {
-		struct ata_device *drive = &ch->drives[i];
-
-		probe_for_drive(drive);
-
-		/* drive found, there is a channel it is attached too. */
-		if (drive->present)
-			ch->present = 1;
-	}
-
-	if (!ch->present)
-		goto not_found;
-
-	error = 0;
-
-	if (((unsigned long)ch->io_ports[IDE_DATA_OFFSET] | 7) ==
-			((unsigned long)ch->io_ports[IDE_STATUS_OFFSET])) {
-		error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 8, ch->name);
-		ch->straight8 = 1;
-	} else {
-		for (i = 0; i < 8; i++)
-			error += !request_region(ch->io_ports[i], 1, ch->name);
-	}
-	if (ch->io_ports[IDE_CONTROL_OFFSET])
-		error += !request_region(ch->io_ports[IDE_CONTROL_OFFSET], 1, ch->name);
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-	if (ch->io_ports[IDE_IRQ_OFFSET])
-		error += !request_region(ch->io_ports[IDE_IRQ_OFFSET], 1, ch->name);
-#endif
-
-	/* Some neccessary register area was already used. Skip this device.
-	 */
-
-	if (
-#if CONFIG_BLK_DEV_PDC4030
-			(ch->chipset != ide_pdc4030 || ch->unit == 0) &&
-#endif
-			error) {
-
-		/* FIXME: We should be dealing properly with partial IO region
-		 * allocations here.
-		 */
-
-		ch->present = 0;
-		printk("%s: error: ports already in use!\n", ch->name);
-	}
-
-	if (!ch->present)
-		goto not_found;
-
-	/* Register this hardware interface within the global device tree.
-	 */
-	sprintf(ch->dev.bus_id, "%04x", ch->io_ports[IDE_DATA_OFFSET]);
-	sprintf(ch->dev.name, "ide");
-	ch->dev.driver_data = ch;
-#ifdef CONFIG_PCI
-	if (ch->pci_dev)
-		ch->dev.parent = &ch->pci_dev->dev;
-	else
-#endif
-		ch->dev.parent = NULL; /* Would like to do = &device_legacy */
-
-	device_register(&ch->dev);
-
-	if (ch->io_ports[IDE_CONTROL_OFFSET] && ch->reset) {
-		unsigned long timeout = jiffies + WAIT_WORSTCASE;
-		byte stat;
-
-		printk("%s: reset\n", ch->name);
-		OUT_BYTE(12, ch->io_ports[IDE_CONTROL_OFFSET]);
-		udelay(10);
-		OUT_BYTE(8, ch->io_ports[IDE_CONTROL_OFFSET]);
-		do {
-			ide_delay_50ms();
-			stat = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]);
-		} while ((stat & BUSY_STAT) && time_before(jiffies, timeout));
-	}
-
-	__restore_flags(flags);	/* local CPU only */
-
-	/*
-	 * Now setup the PIO transfer modes of the drives on this channel.
-	 */
-	for (i = 0; i < MAX_DRIVES; ++i) {
-		struct ata_device *drive = &ch->drives[i];
-
-		if (drive->present && (drive->autotune == 1)) {
-			if (drive->channel->tuneproc)
-				drive->channel->tuneproc(drive, 255);	/* auto-tune PIO mode */
-		}
-	}
-
-	return;
-
-not_found:
-	__restore_flags(flags);
-}
-
-/*
- * This routine sets up the irq for an ide interface, and creates a new hwgroup
- * for the irq/channel if none was previously assigned.
- *
- * Much of the code is for correctly detecting/handling irq sharing and irq
- * serialization situations.  This is somewhat complex because it handles
- * static as well as dynamic (PCMCIA) IDE interfaces.
- *
- * The SA_INTERRUPT in sa_flags means ata_irq_request() is always entered with
- * interrupts completely disabled.  This can be bad for interrupt latency, but
- * anything else has led to problems on some machines.  We re-enable interrupts
- * as much as we can safely do in most places.
- */
-static int init_irq(struct ata_channel *ch)
-{
-	unsigned long flags;
-	int i;
-	spinlock_t *lock;
-	spinlock_t *new_lock;
-	unsigned long *active;
-	unsigned long *new_active;
-	struct ata_channel *match = NULL;
-
-	/* Spare allocation before sleep. */
-	new_lock = kmalloc(sizeof(*lock), GFP_KERNEL);
-	new_active = kmalloc(sizeof(*active), GFP_KERNEL);
-	*new_active = 0L;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	ch->lock = NULL;
-
-#if MAX_HWIFS > 1
-	/*
-	 * Group up with any other channels that share our irq(s).
-	 */
-	for (i = 0; i < MAX_HWIFS; ++i) {
-		struct ata_channel *h = &ide_hwifs[i];
-
-		/* scan only initialized channels */
-		if (!h->lock)
-			continue;
-
-		if (ch->irq != h->irq)
-		        continue;
-
-		ch->sharing_irq = h->sharing_irq = 1;
-
-		if (ch->chipset != ide_pci || h->chipset != ide_pci ||
-		     ch->serialized || h->serialized) {
-			if (match && match->lock && match->lock != h->lock)
-				printk("%s: potential irq problem with %s and %s\n", ch->name, h->name, match->name);
-			/* don't undo a prior perfect match */
-			if (!match || match->irq != ch->irq)
-				match = h;
-		}
-	}
-#endif
-	/*
-	 * If we are still without a lock group, then form a new one
-	 */
-	if (!match) {
-		lock = new_lock;
-		active = new_active;
-		if (!lock) {
-			spin_unlock_irqrestore(&ide_lock, flags);
-
-			return 1;
-		}
-		spin_lock_init(lock);
-	} else {
-		lock = match->lock;
-		active = match->active;
-		if(new_lock)
-			kfree(new_lock);
-	}
-
-	/*
-	 * Allocate the irq, if not already obtained for another channel
-	 */
-	if (!match || match->irq != ch->irq) {
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
-		int sa = IDE_CHIPSET_IS_PCI(ch->chipset) ? SA_SHIRQ : SA_INTERRUPT;
-#else
-		int sa = IDE_CHIPSET_IS_PCI(ch->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
-#endif
-
-		if (ch->io_ports[IDE_CONTROL_OFFSET])
-			OUT_BYTE(0x08, ch->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */
-
-		if (request_irq(ch->irq, &ata_irq_request, sa, ch->name, ch)) {
-			if (!match) {
-				kfree(lock);
-				kfree(active);
-			}
-
-			spin_unlock_irqrestore(&ide_lock, flags);
-
-			return 1;
-		}
-	}
-
-	/*
-	 * Everything is okay. Tag us as member of this lock group.
-	 */
-	ch->lock = lock;
-	ch->active = active;
-
-	init_timer(&ch->timer);
-	ch->timer.function = &ide_timer_expiry;
-	ch->timer.data = (unsigned long) ch;
-
-	for (i = 0; i < MAX_DRIVES; ++i) {
-		struct ata_device *drive = &ch->drives[i];
-		request_queue_t *q;
-		int max_sectors = 255;
-
-		if (!drive->present)
-			continue;
-
-		if (!ch->drive)
-			ch->drive = drive;
-
-		/*
-		 * Init the per device request queue
-		 */
-
-		q = &drive->queue;
-		q->queuedata = drive->channel;
-		blk_init_queue(q, do_ide_request, drive->channel->lock);
-		blk_queue_segment_boundary(q, 0xffff);
-
-		/* ATA can do up to 128K per request, pdc4030 needs smaller limit */
-#ifdef CONFIG_BLK_DEV_PDC4030
-		if (drive->channel->chipset == ide_pdc4030)
-			max_sectors = 127;
-#endif
-		blk_queue_max_sectors(q, max_sectors);
-
-		/* IDE DMA can do PRD_ENTRIES number of segments. */
-		blk_queue_max_hw_segments(q, PRD_ENTRIES);
-
-		/* FIXME: This is a driver limit and could be eliminated. */
-		blk_queue_max_phys_segments(q, PRD_ENTRIES);
-	}
-	spin_unlock_irqrestore(&ide_lock, flags);
-
-#if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
-	printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", ch->name,
-		ch->io_ports[IDE_DATA_OFFSET],
-		ch->io_ports[IDE_DATA_OFFSET]+7,
-		ch->io_ports[IDE_CONTROL_OFFSET], ch->irq);
-#elif defined(__sparc__)
-	printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %s", ch->name,
-		ch->io_ports[IDE_DATA_OFFSET],
-		ch->io_ports[IDE_DATA_OFFSET]+7,
-		ch->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(ch->irq));
-#else
-	printk("%s at %p on irq 0x%08x", ch->name,
-		ch->io_ports[IDE_DATA_OFFSET], ch->irq);
-#endif
-	if (match)
-		printk(" (%sed with %s)",
-			ch->sharing_irq ? "shar" : "serializ", match->name);
-	printk("\n");
-
-	return 0;
-}
-
-/*
- * Returns the queue which corresponds to a given device.
- *
- * FIXME: this should take struct block_device * as argument in future.
- */
-static request_queue_t *ata_get_queue(kdev_t dev)
-{
-	struct ata_channel *ch = (struct ata_channel *)blk_dev[major(dev)].data;
-
-	/* FIXME: ALLERT: This discriminates between master and slave! */
-	return &ch->drives[DEVICE_NR(dev) & 1].queue;
-}
-
-/* Number of minor numbers we consume par channel. */
-#define ATA_MINORS	(MAX_DRIVES * (1 << PARTN_BITS))
-
-static void channel_init(struct ata_channel *ch)
-{
-	struct gendisk *gd;
-	unsigned int unit;
-	extern devfs_handle_t ide_devfs_handle;
-
-	if (!ch->present)
-		return;
-
-	/* we set it back to 1 if all is ok below */
-	ch->present = 0;
-
-	if (!ch->irq) {
-		if (!(ch->irq = ide_default_irq(ch->io_ports[IDE_DATA_OFFSET]))) {
-			printk("%s: DISABLED, NO IRQ\n", ch->name);
-
-			return;
-		}
-	}
-#ifdef CONFIG_BLK_DEV_HD
-	if (ch->irq == HD_IRQ && ch->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
-		printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", ch->name);
-
-		return;
-	}
-#endif
-
-	if (devfs_register_blkdev (ch->major, ch->name, ide_fops)) {
-		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", ch->name, ch->major);
-
-		return;
-	}
-
-	if (init_irq(ch)) {
-		int irq = ch->irq;
-		/*
-		 * It failed to initialise. Find the default IRQ for
-		 * this port and try that.
-		 */
-		if (!(ch->irq = ide_default_irq(ch->io_ports[IDE_DATA_OFFSET]))) {
-			printk(KERN_INFO "%s: disabled; unable to get IRQ %d.\n", ch->name, irq);
-			(void) unregister_blkdev (ch->major, ch->name);
-
-			return;
-		}
-		if (init_irq(ch)) {
-			printk(KERN_INFO "%s: probed IRQ %d and default IRQ %d failed.\n",
-				ch->name, irq, ch->irq);
-			(void) unregister_blkdev(ch->major, ch->name);
-
-			return;
-		}
-		printk(KERN_INFO "%s: probed IRQ %d failed, using default.\n", ch->name, ch->irq);
-	}
-
-	/* Initialize partition and global device data.  ide_geninit() gets
-	 * called somewhat later, during the partition check.
-	 */
-
-	gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
-	if (!gd)
-		goto err_kmalloc_gd;
-
-	gd->sizes = kmalloc(ATA_MINORS * sizeof(int), GFP_KERNEL);
-	if (!gd->sizes)
-		goto err_kmalloc_gd_sizes;
-
-	gd->part = kmalloc(ATA_MINORS * sizeof(struct hd_struct), GFP_KERNEL);
-	if (!gd->part)
-		goto err_kmalloc_gd_part;
-	memset(gd->part, 0, ATA_MINORS * sizeof(struct hd_struct));
-
-	gd->de_arr = kmalloc (sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL);
-	if (!gd->de_arr)
-		goto err_kmalloc_gd_de_arr;
-	memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES);
-
-	gd->flags = kmalloc (sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL);
-	if (!gd->flags)
-		goto err_kmalloc_gd_flags;
-	memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES);
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit)
-		ch->drives[unit].part = &gd->part[unit << PARTN_BITS];
-
-	gd->major	= ch->major;		/* our major device number */
-	gd->major_name	= IDE_MAJOR_NAME;	/* treated special in genhd.c */
-	gd->minor_shift	= PARTN_BITS;		/* num bits for partitions */
-	gd->nr_real	= MAX_DRIVES;		/* current num real drives */
-	gd->next	= NULL;			/* linked list of major devs */
-	gd->fops        = ide_fops;             /* file operations */
-
-	gd->de_arr	= kmalloc(sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL);
-	if (gd->de_arr)
-		memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES);
-	else
-	    goto err_kmalloc_gd_de_arr;
-
-	gd->flags	= kmalloc(sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL);
-	if (gd->flags)
-		memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES);
-	else
-	    goto err_kmalloc_gd_flags;
-
-	ch->gd = gd;
-	add_gendisk(gd);
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		char name[80];
-
-		ch->drives[unit].dn = ((ch->unit ? 2 : 0) + unit);
-		sprintf(name, "host%d/bus%d/target%d/lun%d",
-			ch->index, ch->unit, unit, ch->drives[unit].lun);
-		if (ch->drives[unit].present)
-			ch->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
-	}
-
-	blk_dev[ch->major].data = ch;
-	blk_dev[ch->major].queue = ata_get_queue;
-
-	/* All went well, flag this channel entry as valid again. */
-	ch->present = 1;
-
-	return;
-
-err_kmalloc_gd_flags:
-	kfree(gd->de_arr);
-err_kmalloc_gd_de_arr:
-	kfree(gd->part);
-err_kmalloc_gd_part:
-	kfree(gd->sizes);
-err_kmalloc_gd_sizes:
-	kfree(gd);
-err_kmalloc_gd:
-	printk(KERN_CRIT "(%s) Out of memory\n", __FUNCTION__);
-}
-
-int ideprobe_init (void)
-{
-	unsigned int i;
-	int probe[MAX_HWIFS];
-
-	for (i = 0; i < MAX_HWIFS; ++i)
-		probe[i] = !ide_hwifs[i].present;
-
-	/*
-	 * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
-	 */
-	for (i = 0; i < MAX_HWIFS; ++i)
-		if (probe[i])
-			channel_probe(&ide_hwifs[i]);
-	for (i = 0; i < MAX_HWIFS; ++i)
-		if (probe[i])
-			channel_init(&ide_hwifs[i]);
-
-	return 0;
-}
diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
--- a/drivers/ide/ide-tape.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/ide-tape.c	Wed May 29 11:43:02 2002
@@ -2789,14 +2789,14 @@
 	struct bio *prev_bio, *bio;
 	int pages = tape->pages_per_stage;
 	char *b_data = NULL;
-	struct bio_vec *bv; 
+	struct bio_vec *bv;
 
 	if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
 		return NULL;
 	stage->next = NULL;
 
 	bio = stage->bio = bio_alloc(GFP_KERNEL,1);
-	bv = bio_iovec(bio);	
+	bv = bio_iovec(bio);
 	bv->bv_len = 0;
 	if (bio == NULL)
 		goto abort;
@@ -2806,9 +2806,14 @@
 	if (clear)
 		memset(bio_data(bio), 0, PAGE_SIZE);
 	bio->bi_size = PAGE_SIZE;
-	if(bv->bv_len == full) bv->bv_len = bio->bi_size;
-	set_bit (BH_Lock, &bio->bi_flags);
+	if(bv->bv_len == full)
+	    bv->bv_len = bio->bi_size;
+#if 0
+
+	/* FIXME: What what this supposed to achieve? */
 
+	set_bit (BH_Lock, &bio->bi_flags);
+#endif
 	while (--pages) {
 		if ((bio->bi_io_vec[pages].bv_page = alloc_page(GFP_KERNEL)) == NULL)
 			goto abort;
@@ -2837,7 +2842,11 @@
 		//bio->bi_io_vec[0].bv_offset = b_data;
 		bio->bi_size = PAGE_SIZE;
 		atomic_set(&bio->bi_cnt, full ? bio->bi_size : 0);
+#if 0
+		/* FIXME: What what this supposed to achieve? */
+
 		set_bit (BH_Lock, &bio->bi_flags);
+#endif
 		prev_bio->bi_next = bio;
 	}
 	bio->bi_size -= tape->excess_bh_size;
@@ -6153,7 +6162,7 @@
 	channel = drive->channel;
 	unit = drive - channel->drives;
 
-	ide_revalidate_disk(mk_kdev(channel->major, unit << PARTN_BITS));
+	ata_revalidate(mk_kdev(channel->major, unit << PARTN_BITS));
 }
 
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c	Wed May 29 11:43:03 2002
+++ b/drivers/ide/ide-taskfile.c	Wed May 29 11:43:03 2002
@@ -161,53 +161,6 @@
 }
 
 /*
- * The following routines are mainly used by the ATAPI drivers.
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd bytecount is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-void atapi_read(struct ata_device *drive, void *buffer, unsigned int bytecount)
-{
-	if (drive->channel->atapi_read) {
-		drive->channel->atapi_read(drive, buffer, bytecount);
-		return;
-	}
-
-	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
-		return;
-	}
-#endif
-	ata_read(drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		insw(IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-void atapi_write(struct ata_device *drive, void *buffer, unsigned int bytecount)
-{
-	if (drive->channel->atapi_write) {
-		drive->channel->atapi_write(drive, buffer, bytecount);
-		return;
-	}
-
-	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
-		return;
-	}
-#endif
-	ata_write(drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		outsw(IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-/*
  * Needed for PCI irq sharing
  */
 int drive_is_ready(struct ata_device *drive)
@@ -400,13 +353,20 @@
 
 	OUT_BYTE((args->taskfile.device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
 	if (args->handler != NULL) {
+
+		/* This is apparently supposed to reset the wait timeout for
+		 * the interrupt to accur.
+		 */
+
 		ide_set_handler(drive, args->handler, WAIT_CMD, NULL);
 		OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
+
 		/*
 		 * Warning check for race between handler and prehandler for
 		 * writing first block of data.  however since we are well
 		 * inside the boundaries of the seek, we should be okay.
 		 */
+
 		if (args->prehandler != NULL)
 			return args->prehandler(drive, rq);
 	} else {
@@ -626,7 +586,8 @@
 	return ide_started;
 }
 
-/* Called by ioctl to feature out type of command being called */
+/* Called to figure out the type of command being called.
+ */
 void ide_cmd_type_parser(struct ata_taskfile *args)
 {
 	struct hd_drive_task_hdr *taskfile = &args->taskfile;
@@ -1016,7 +977,6 @@
 		/* FIXME: what about the setup for the drive?! */
 		if (drive->channel->speedproc)
 			drive->channel->speedproc(drive, pio);
-		ide_driveid_update(drive);
 	}
 
 abort:
@@ -1032,8 +992,6 @@
 EXPORT_SYMBOL(drive_is_ready);
 EXPORT_SYMBOL(ata_read);
 EXPORT_SYMBOL(ata_write);
-EXPORT_SYMBOL(atapi_read);
-EXPORT_SYMBOL(atapi_write);
 EXPORT_SYMBOL(ata_taskfile);
 EXPORT_SYMBOL(recal_intr);
 EXPORT_SYMBOL(task_no_data_intr);
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/ide.c	Wed May 29 11:43:02 2002
@@ -32,8 +32,6 @@
  *  Some additional driver compile-time options are in <linux/ide.h>
  */
 
-#define	VERSION	"7.0.0"
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -67,163 +65,11 @@
 
 #include "ata-timing.h"
 #include "pcihost.h"
-
-
-MODULE_DESCRIPTION("ATA/ATAPI driver infrastructure");
-MODULE_PARM(options,"s");
-MODULE_LICENSE("GPL");
-
-/*
- * Those will be moved into separate header files eventually.
- */
-#ifdef CONFIG_ETRAX_IDE
-extern void init_e100_ide(void);
-#endif
-#ifdef CONFIG_BLK_DEV_CMD640
-extern void ide_probe_for_cmd640x(void);
-#endif
-#ifdef CONFIG_BLK_DEV_PDC4030
-extern int ide_probe_for_pdc4030(void);
-#endif
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-extern void pmac_ide_probe(void);
-#endif
-#ifdef CONFIG_BLK_DEV_IDE_ICSIDE
-extern void icside_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_IDE_RAPIDE
-extern void rapide_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_GAYLE
-extern void gayle_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_FALCON_IDE
-extern void falconide_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-extern void macide_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_Q40IDE
-extern void q40ide_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_BUDDHA
-extern void buddha_init(void);
-#endif
-#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
-extern void pnpide_init(int);
-#endif
+#include "ioctl.h"
 
 /* default maximum number of failures */
 #define IDE_DEFAULT_MAX_FAILURES	1
 
-static int idebus_parameter;	/* holds the "idebus=" parameter */
-int system_bus_speed;		/* holds what we think is VESA/PCI bus speed */
-static int initializing;	/* set while initializing built-in drivers */
-
-/*
- * Protects access to global structures etc.
- */
-spinlock_t ide_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
-
-#ifdef CONFIG_PCI
-static int ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
-#endif
-
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-/*
- * This is used by the Atari code to obtain access to the IDE interrupt,
- * which is shared between several drivers.
- */
-static int irq_lock;
-#endif
-
-int noautodma = 0;
-
-/* Single linked list of sub device type drivers */
-static struct ata_operations *ata_drivers; /* = NULL */
-static spinlock_t ata_drivers_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- * This is declared extern in ide.h, for access by other IDE modules:
- */
-struct ata_channel ide_hwifs[MAX_HWIFS];	/* master data repository */
-
-static void init_hwif_data(struct ata_channel *ch, unsigned int index)
-{
-	static const byte ide_major[] = {
-		IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR,
-		IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR
-	};
-
-	unsigned int unit;
-	hw_regs_t hw;
-
-	/* bulk initialize channel & drive info with zeros */
-	memset(ch, 0, sizeof(struct ata_channel));
-	memset(&hw, 0, sizeof(hw_regs_t));
-
-	/* fill in any non-zero initial values */
-	ch->index     = index;
-	ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &ch->irq);
-	memcpy(&ch->hw, &hw, sizeof(hw));
-	memcpy(ch->io_ports, hw.io_ports, sizeof(hw.io_ports));
-	ch->noprobe	= !ch->io_ports[IDE_DATA_OFFSET];
-#ifdef CONFIG_BLK_DEV_HD
-	if (ch->io_ports[IDE_DATA_OFFSET] == HD_DATA)
-		ch->noprobe = 1; /* may be overridden by ide_setup() */
-#endif
-	ch->major = ide_major[index];
-	sprintf(ch->name, "ide%d", index);
-	ch->bus_state = BUSSTATE_ON;
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		struct ata_device *drive = &ch->drives[unit];
-
-		drive->type		= ATA_DISK;
-		drive->select.all	= (unit<<4)|0xa0;
-		drive->channel		= ch;
-		drive->ctl		= 0x08;
-		drive->ready_stat	= READY_STAT;
-		drive->bad_wstat	= BAD_W_STAT;
-		sprintf(drive->name, "hd%c", 'a' + (index * MAX_DRIVES) + unit);
-		drive->max_failures	= IDE_DEFAULT_MAX_FAILURES;
-
-		init_waitqueue_head(&drive->wqueue);
-	}
-}
-
-/*
- * init_ide_data() sets reasonable default values into all fields
- * of all instances of the hwifs and drives, but only on the first call.
- * Subsequent calls have no effect (they don't wipe out anything).
- *
- * This routine is normally called at driver initialization time,
- * but may also be called MUCH earlier during kernel "command-line"
- * parameter processing.  As such, we cannot depend on any other parts
- * of the kernel (such as memory allocation) to be functioning yet.
- *
- * This is too bad, as otherwise we could dynamically allocate the
- * ata_device structs as needed, rather than always consuming memory
- * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
- */
-#define MAGIC_COOKIE 0x12345678
-static void __init init_ide_data (void)
-{
-	unsigned int h;
-	static unsigned long magic_cookie = MAGIC_COOKIE;
-
-	if (magic_cookie != MAGIC_COOKIE)
-		return;		/* already initialized */
-	magic_cookie = 0;
-
-	/* Initialize all interface structures */
-	for (h = 0; h < MAX_HWIFS; ++h)
-		init_hwif_data(&ide_hwifs[h], h);
-
-	/* Add default hw interfaces */
-	ide_init_default_hwifs();
-}
-
 /*
  * CompactFlash cards and their relatives pretend to be removable hard disks, except:
  *	(1) they never have a slave unit, and
@@ -305,6 +151,12 @@
 	return ret;
 }
 
+/* This is the default end request function as well */
+int ide_end_request(struct ata_device *drive, struct request *rq, int uptodate)
+{
+	return __ide_end_request(drive, rq, uptodate, 0);
+}
+
 /*
  * This should get invoked any time we exit the driver to
  * wait for an interrupt response from a drive.  handler() points
@@ -396,31 +248,6 @@
 
 extern struct block_device_operations ide_fops[];
 
-/*
- * This is called exactly *once* for each channel.
- */
-void ide_geninit(struct ata_channel *ch)
-{
-	unsigned int unit;
-	struct gendisk *gd = ch->gd;
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		struct ata_device *drive = &ch->drives[unit];
-
-		if (!drive->present)
-			continue;
-
-		if (drive->type != ATA_DISK && drive->type != ATA_FLOPPY)
-			continue;
-
-		register_disk(gd,mk_kdev(ch->major,unit<<PARTN_BITS),
-#ifdef CONFIG_BLK_DEV_ISAPNP
-			(drive->forced_geom && drive->noprobe) ? 1 :
-#endif
-			1 << PARTN_BITS, ide_fops, ata_capacity(drive));
-	}
-}
-
 static ide_startstop_t do_reset1(struct ata_device *, int); /* needed below */
 
 /*
@@ -687,7 +514,7 @@
 	printk("} ");
 }
 #else
-#define ata_dump_bits(msgs,nr,bits) do { } while (0)
+# define ata_dump_bits(msgs,nr,bits) do { } while (0)
 #endif
 
 /*
@@ -1617,136 +1444,18 @@
 	spin_unlock_irqrestore(ch->lock, flags);
 }
 
-/*
- * get_info_ptr() returns the (struct ata_device *) for a given device number.
- * It returns NULL if the given device number does not match any present drives.
- */
-struct ata_device *get_info_ptr(kdev_t i_rdev)
-{
-	unsigned int major = major(i_rdev);
-	int h;
-
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		struct ata_channel *ch = &ide_hwifs[h];
-		if (ch->present && major == ch->major) {
-			int unit = DEVICE_NR(i_rdev);
-			if (unit < MAX_DRIVES) {
-				struct ata_device *drive = &ch->drives[unit];
-				if (drive->present)
-					return drive;
-			}
-			break;
-		}
-	}
-	return NULL;
-}
-
-/*
- * FIXME: rename to ata_wipe_partitions.
- *
- * This routine is called to flush all partitions and partition tables
- * for a changed disk, and then re-read the new partition table.
- * If we are revalidating a disk because of a media change, then we
- * enter with usage == 0.  If we are using an ioctl, we automatically have
- * usage == 1 (we need an open channel to use an ioctl :-), so this
- * is our limit.
- */
-int ide_revalidate_disk(kdev_t i_rdev)
-{
-	struct ata_device *drive;
-	unsigned long flags;
-	int res;
-
-	if ((drive = get_info_ptr(i_rdev)) == NULL)
-		return -ENODEV;
-
-	/* FIXME: The locking here doesn't make the slightest sense! */
-	spin_lock_irqsave(&ide_lock, flags);
-
-	if (drive->busy || (drive->usage > 1)) {
-
-		spin_unlock_irqrestore(&ide_lock, flags);
-
-		return -EBUSY;
-	}
-
-	drive->busy = 1;
-	MOD_INC_USE_COUNT;
-
-	spin_unlock_irqrestore(&ide_lock, flags);
-
-	res = wipe_partitions(i_rdev);
-	if (!res) {
-		if (ata_ops(drive) && ata_ops(drive)->revalidate) {
-			ata_get(ata_ops(drive));
-			/* this is a no-op for tapes and SCSI based access */
-			ata_ops(drive)->revalidate(drive);
-			ata_put(ata_ops(drive));
-		} else
-			grok_partitions(i_rdev, ata_capacity(drive));
-	}
-
-	drive->busy = 0;
-	wake_up(&drive->wqueue);
-	MOD_DEC_USE_COUNT;
-
-	return res;
-}
-
-/*
- * Look again for all drives in the system on all interfaces.
- */
-static void revalidate_drives(void)
-{
-	int i;
-
-	for (i = 0; i < MAX_HWIFS; ++i) {
-		int unit;
-		struct ata_channel *ch = &ide_hwifs[i];
-
-		for (unit = 0; unit < MAX_DRIVES; ++unit) {
-			struct ata_device *drive = &ch->drives[unit];
-
-			if (drive->revalidate) {
-				drive->revalidate = 0;
-				if (!initializing)
-					ide_revalidate_disk(mk_kdev(ch->major, unit<<PARTN_BITS));
-			}
-		}
-	}
-}
-
-static void ide_driver_module(void)
-{
-	int i;
-
-	/* Don't reinit the probe if there is already one channel detected. */
-
-	for (i = 0; i < MAX_HWIFS; ++i) {
-		if (ide_hwifs[i].present)
-			goto revalidate;
-	}
-
-	ideprobe_init();
-
-revalidate:
-	revalidate_drives();
-}
-
 static int ide_open(struct inode * inode, struct file * filp)
 {
 	struct ata_device *drive;
 
 	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENXIO;
-	if (drive->driver == NULL)
-		ide_driver_module();
 
 	/* Request a particular device type module.
 	 *
-	 * FIXME: The function which should rather requests the drivers in
+	 * FIXME: The function which should rather requests the drivers is
 	 * ide_driver_module(), since it seems illogical and even a bit
-	 * dangerous to delay this until open time!
+	 * dangerous to postpone this until open time!
 	 */
 
 #ifdef CONFIG_KMOD
@@ -1776,8 +1485,13 @@
 			request_module(module);
 	}
 #endif
+
+	if (drive->driver == NULL)
+		ide_driver_module();
+
 	while (drive->busy)
 		sleep_on(&drive->wqueue);
+
 	++drive->usage;
 	if (ata_ops(drive) && ata_ops(drive)->open)
 		return ata_ops(drive)->open(inode, filp, drive);
@@ -1787,7 +1501,8 @@
 	}
 
 	printk(KERN_INFO "%s: driver not present\n", drive->name);
-	drive->usage--;
+	--drive->usage;
+
 	return -ENXIO;
 }
 
@@ -1808,362 +1523,6 @@
 	return 0;
 }
 
-void ide_unregister(struct ata_channel *ch)
-{
-	struct gendisk *gd;
-	struct ata_device *d;
-	spinlock_t *lock;
-	int unit;
-	int i;
-	unsigned long flags;
-	unsigned int p, minor;
-	struct ata_channel old;
-	int n_irq;
-	int n_ch;
-
-	spin_lock_irqsave(&ide_lock, flags);
-
-	if (!ch->present)
-		goto abort;
-
-	put_device(&ch->dev);
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		struct ata_device * drive = &ch->drives[unit];
-
-		if (!drive->present)
-			continue;
-
-		if (drive->busy || drive->usage)
-			goto abort;
-
-		if (ata_ops(drive)) {
-			if (ata_ops(drive)->cleanup) {
-				if (ata_ops(drive)->cleanup(drive))
-					goto abort;
-			} else
-				ide_unregister_subdriver(drive);
-		}
-	}
-	ch->present = 0;
-
-	/*
-	 * All clear?  Then blow away the buffer cache
-	 */
-	spin_unlock_irqrestore(&ide_lock, flags);
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		struct ata_device * drive = &ch->drives[unit];
-
-		if (!drive->present)
-			continue;
-
-		minor = drive->select.b.unit << PARTN_BITS;
-		for (p = 0; p < (1<<PARTN_BITS); ++p) {
-			if (drive->part[p].nr_sects > 0) {
-				kdev_t devp = mk_kdev(ch->major, minor+p);
-				invalidate_device(devp, 0);
-			}
-		}
-	}
-
-	spin_lock_irqsave(&ide_lock, flags);
-
-	/*
-	 * Note that we only release the standard ports, and do not even try to
-	 * handle any extra ports allocated for weird IDE interface chipsets.
-	 */
-
-	if (ch->straight8) {
-		release_region(ch->io_ports[IDE_DATA_OFFSET], 8);
-	} else {
-		for (i = 0; i < 8; i++)
-			if (ch->io_ports[i])
-				release_region(ch->io_ports[i], 1);
-	}
-	if (ch->io_ports[IDE_CONTROL_OFFSET])
-		release_region(ch->io_ports[IDE_CONTROL_OFFSET], 1);
-/* FIXME: check if we can remove this ifdef */
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-	if (ch->io_ports[IDE_IRQ_OFFSET])
-		release_region(ch->io_ports[IDE_IRQ_OFFSET], 1);
-#endif
-
-	/*
-	 * Remove us from the lock group.
-	 */
-
-	lock = ch->lock;
-	d = ch->drive;
-	for (i = 0; i < MAX_DRIVES; ++i) {
-		struct ata_device *drive = &ch->drives[i];
-
-		if (drive->de) {
-			devfs_unregister (drive->de);
-			drive->de = NULL;
-		}
-		if (!drive->present)
-			continue;
-
-		/* FIXME: possibly unneccessary */
-		if (ch->drive == drive)
-			ch->drive = NULL;
-
-		if (drive->id != NULL) {
-			kfree(drive->id);
-			drive->id = NULL;
-		}
-		drive->present = 0;
-		blk_cleanup_queue(&drive->queue);
-	}
-	if (d->present)
-		ch->drive = d;
-
-
-	/*
-	 * Free the irq if we were the only channel using it.
-	 *
-	 * Free the lock group if we were the only member.
-	 */
-	n_irq = n_ch = 0;
-	for (i = 0; i < MAX_HWIFS; ++i) {
-		struct ata_channel *tmp = &ide_hwifs[i];
-
-		if (!tmp->present)
-			continue;
-
-		if (tmp->irq == ch->irq)
-			++n_irq;
-		if (tmp->lock == ch->lock)
-			++n_ch;
-	}
-	if (n_irq == 1)
-		free_irq(ch->irq, ch);
-	if (n_ch == 1) {
-		kfree(ch->lock);
-		kfree(ch->active);
-		ch->lock = NULL;
-		ch->active = NULL;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	ide_release_dma(ch);
-#endif
-
-	/*
-	 * Remove us from the kernel's knowledge.
-	 */
-	unregister_blkdev(ch->major, ch->name);
-	blk_dev[ch->major].data = NULL;
-	blk_dev[ch->major].queue = NULL;
-	blk_clear(ch->major);
-	gd = ch->gd;
-	if (gd) {
-		del_gendisk(gd);
-		kfree(gd->sizes);
-		kfree(gd->part);
-		if (gd->de_arr)
-			kfree (gd->de_arr);
-		if (gd->flags)
-			kfree (gd->flags);
-		kfree(gd);
-		ch->gd = NULL;
-	}
-
-	/*
-	 * Reinitialize the channel handler, but preserve any special methods for
-	 * it.
-	 */
-
-	old = *ch;
-	init_hwif_data(ch, ch->index);
-	ch->lock = old.lock;
-	ch->tuneproc = old.tuneproc;
-	ch->speedproc = old.speedproc;
-	ch->selectproc = old.selectproc;
-	ch->resetproc = old.resetproc;
-	ch->intrproc = old.intrproc;
-	ch->maskproc = old.maskproc;
-	ch->quirkproc = old.quirkproc;
-	ch->ata_read = old.ata_read;
-	ch->ata_write = old.ata_write;
-	ch->atapi_read = old.atapi_read;
-	ch->atapi_write = old.atapi_write;
-	ch->XXX_udma = old.XXX_udma;
-	ch->udma_enable = old.udma_enable;
-	ch->udma_start = old.udma_start;
-	ch->udma_stop = old.udma_stop;
-	ch->udma_read = old.udma_read;
-	ch->udma_write = old.udma_write;
-	ch->udma_irq_status = old.udma_irq_status;
-	ch->udma_timeout = old.udma_timeout;
-	ch->udma_irq_lost = old.udma_irq_lost;
-	ch->busproc = old.busproc;
-	ch->bus_state = old.bus_state;
-	ch->dma_base = old.dma_base;
-	ch->dma_extra = old.dma_extra;
-	ch->config_data = old.config_data;
-	ch->select_data = old.select_data;
-	ch->proc = old.proc;
-	/* FIXME: most propably this is always right:! */
-#ifndef CONFIG_BLK_DEV_IDECS
-	ch->irq = old.irq;
-#endif
-	ch->major = old.major;
-	ch->chipset = old.chipset;
-	ch->autodma = old.autodma;
-	ch->udma_four = old.udma_four;
-#ifdef CONFIG_PCI
-	ch->pci_dev = old.pci_dev;
-#endif
-	ch->straight8 = old.straight8;
-
-abort:
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-/*
- * Setup hw_regs_t structure described by parameters.  You
- * may set up the hw structure yourself OR use this routine to
- * do it for you.
- */
-void ide_setup_ports(hw_regs_t *hw,
-		ide_ioreg_t base, int *offsets,
-		ide_ioreg_t ctrl, ide_ioreg_t intr,
-		ide_ack_intr_t *ack_intr, int irq)
-{
-	int i;
-
-	for (i = 0; i < IDE_NR_PORTS; i++) {
-		if (offsets[i] != -1)
-			hw->io_ports[i] = base + offsets[i];
-		else
-			hw->io_ports[i] = 0;
-	}
-	if (offsets[IDE_CONTROL_OFFSET] == -1)
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl;
-/* FIMXE: check if we can remove this ifdef */
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-	if (offsets[IDE_IRQ_OFFSET] == -1)
-		hw->io_ports[IDE_IRQ_OFFSET] = intr;
-#endif
-	hw->irq = irq;
-	hw->dma = NO_DMA;
-	hw->ack_intr = ack_intr;
-}
-
-static int subdriver_match(struct ata_channel *channel, struct ata_operations *ops)
-{
-	int count, unit;
-
-	if (!channel->present)
-		return 0;
-
-	count = 0;
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		struct ata_device *drive = &channel->drives[unit];
-		if (drive->present && !drive->driver) {
-			(*ops->attach)(drive);
-			if (drive->driver != NULL)
-				count++;
-		}
-	}
-	return count;
-}
-
-static struct ata_operations * subdriver_interator(struct ata_operations *prev)
-{
-	struct ata_operations *tmp;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ata_drivers_lock, flags);
-
-	/* Restart from beginning if current ata_operations was deallocated,
-	   or if prev is NULL. */
-	for(tmp = ata_drivers; tmp != prev && tmp; tmp = tmp->next);
-	if (!tmp)
-		tmp = ata_drivers;
-	else
-		tmp = tmp->next;
-
-	spin_unlock_irqrestore(&ata_drivers_lock, flags);
-
-	return tmp;
-
-}
-
-/*
- * Register an IDE interface, specifing exactly the registers etc
- * Set init=1 iff calling before probes have taken place.
- */
-int ide_register_hw(hw_regs_t *hw, struct ata_channel **hwifp)
-{
-	int h;
-	int retry = 1;
-	struct ata_channel *ch;
-	struct ata_operations *subdriver;
-
-	do {
-		for (h = 0; h < MAX_HWIFS; ++h) {
-			ch = &ide_hwifs[h];
-			if (ch->hw.io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET])
-				goto found;
-		}
-		for (h = 0; h < MAX_HWIFS; ++h) {
-			ch = &ide_hwifs[h];
-			if ((!ch->present && (ch->unit == ATA_PRIMARY) && !initializing) ||
-			    (!ch->hw.io_ports[IDE_DATA_OFFSET] && initializing))
-				goto found;
-		}
-		for (h = 0; h < MAX_HWIFS; ++h)
-			ide_unregister(&ide_hwifs[h]);
-	} while (retry--);
-
-	return -1;
-
-found:
-	ide_unregister(ch);
-	if (ch->present)
-		return -1;
-	memcpy(&ch->hw, hw, sizeof(*hw));
-	memcpy(ch->io_ports, ch->hw.io_ports, sizeof(ch->hw.io_ports));
-	ch->irq = hw->irq;
-	ch->noprobe = 0;
-	ch->chipset = hw->chipset;
-
-	if (!initializing) {
-		ideprobe_init();
-		revalidate_drives();
-		/* FIXME: Do we really have to call it second time here?! */
-		ide_driver_module();
-	}
-
-	/* Look up whatever there is a subdriver, which will serve this
-	 * device.
-	 */
-	subdriver = NULL;
-	while ((subdriver = subdriver_interator(subdriver))) {
-		if (subdriver_match(ch, subdriver) > 0)
-			break;
-	}
-
-	if (hwifp)
-		*hwifp = ch;
-
-	return (initializing || ch->present) ? h : -1;
-}
-
-/*
- * Compatability function for existing drivers.  If you want
- * something different, use the function above.
- */
-int ide_register(int arg1, int arg2, int irq)
-{
-	hw_regs_t hw;
-	ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
-	hw.irq = irq;
-	return ide_register_hw(&hw, NULL);
-}
-
 int ide_spin_wait_hwgroup(struct ata_device *drive)
 {
 	/* FIXME: Wait on a proper timer. Instead of playing games on the
@@ -2189,306 +1548,6 @@
 	return 0;
 }
 
-static int set_io_32bit(struct ata_device *drive, int arg)
-{
-	if (drive->channel->no_io_32bit)
-		return -EIO;
-
-	drive->channel->io_32bit = arg;
-
-	return 0;
-}
-
-static int set_using_dma(struct ata_device *drive, int arg)
-{
-	if (!drive->driver)
-		return -EPERM;
-
-	if (!drive->id || !(drive->id->capability & 1) || !drive->channel->XXX_udma)
-		return -EPERM;
-
-	udma_enable(drive, arg, 1);
-
-	return 0;
-}
-
-static int set_pio_mode(struct ata_device *drive, int arg)
-{
-	if (!drive->channel->tuneproc)
-		return -ENOSYS;
-
-	if (drive->channel->tuneproc != NULL)
-		drive->channel->tuneproc(drive, (u8) arg);
-
-	return 0;
-}
-
-/*
- * Delay for *at least* 50ms.  As we don't know how much time is left
- * until the next tick occurs, we wait an extra tick to be safe.
- * This is used only during the probing/polling for drives at boot time.
- *
- * However, its usefullness may be needed in other places, thus we export it now.
- * The future may change this to a millisecond setable delay.
- */
-void ide_delay_50ms (void)
-{
-#ifndef CONFIG_BLK_DEV_IDECS
-	mdelay(50);
-#else
-	__set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/20);
-#endif
-}
-
-/*
- * Handle ioctls.
- *
- * NOTE: Due to ridiculous coding habbits in the hdparm utility we have to
- * always return unsigned long in case we are returning simple values.
- */
-static int ide_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	unsigned int major, minor;
-	struct ata_device *drive;
-	struct request rq;
-	kdev_t dev;
-
-	dev = inode->i_rdev;
-	major = major(dev);
-	minor = minor(dev);
-
-	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
-		return -ENODEV;
-
-
-	/* Contrary to popular beleve we disallow even the reading of the ioctl
-	 * values for users which don't have permission too. We do this becouse
-	 * such information could be used by an attacker to deply a simple-user
-	 * attack, which triggers bugs present only on a particular
-	 * configuration.
-	 */
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
-	ide_init_drive_cmd(&rq);
-	switch (cmd) {
-		case HDIO_GET_32BIT: {
-			unsigned long val = drive->channel->io_32bit;
-
-			if (put_user(val, (unsigned long *) arg))
-				return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_SET_32BIT: {
-			int val;
-
-			if (arg < 0 || arg > 1)
-				return -EINVAL;
-
-			if (ide_spin_wait_hwgroup(drive))
-				return -EBUSY;
-
-			val = set_io_32bit(drive, arg);
-			spin_unlock_irq(drive->channel->lock);
-
-			return val;
-		}
-
-		case HDIO_SET_PIO_MODE: {
-			int val;
-
-			if (arg < 0 || arg > 255)
-				return -EINVAL;
-
-			if (ide_spin_wait_hwgroup(drive))
-				return -EBUSY;
-
-			val = set_pio_mode(drive, arg);
-			spin_unlock_irq(drive->channel->lock);
-
-			return val;
-		}
-
-		case HDIO_GET_UNMASKINTR: {
-			unsigned long val = drive->channel->unmask;
-
-			if (put_user(val, (unsigned long *) arg))
-				return -EFAULT;
-
-			return 0;
-		}
-
-
-		case HDIO_SET_UNMASKINTR: {
-			if (arg < 0 || arg > 1)
-				return -EINVAL;
-
-			if (drive->channel->no_unmask)
-				return -EIO;
-
-			if (ide_spin_wait_hwgroup(drive))
-				return -EBUSY;
-
-			drive->channel->unmask = arg;
-			spin_unlock_irq(drive->channel->lock);
-
-			return 0;
-		}
-
-		case HDIO_GET_DMA: {
-			unsigned long val = drive->using_dma;
-
-			if (put_user(val, (unsigned long *) arg))
-				return -EFAULT;
-
-			return 0;
-		}
-
-		case HDIO_SET_DMA: {
-			int val;
-
-			if (arg < 0 || arg > 1)
-				return -EINVAL;
-
-			if (ide_spin_wait_hwgroup(drive))
-				return -EBUSY;
-
-			val = set_using_dma(drive, arg);
-			spin_unlock_irq(drive->channel->lock);
-
-			return val;
-		}
-
-		case HDIO_GETGEO: {
-			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl = drive->bios_cyl; /* truncate */
-
-			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
-				return -EINVAL;
-
-			if (put_user(drive->bios_head, (byte *) &loc->heads))
-				return -EFAULT;
-
-			if (put_user(drive->bios_sect, (byte *) &loc->sectors))
-				return -EFAULT;
-
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders))
-				return -EFAULT;
-
-			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
-				(unsigned long *) &loc->start))
-				return -EFAULT;
-
-			return 0;
-		}
-
-		case HDIO_GETGEO_BIG_RAW: {
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-
-			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
-				return -EINVAL;
-
-			if (put_user(drive->head, (u8 *) &loc->heads))
-				return -EFAULT;
-
-			if (put_user(drive->sect, (u8 *) &loc->sectors))
-				return -EFAULT;
-
-			if (put_user(drive->cyl, (unsigned int *) &loc->cylinders))
-				return -EFAULT;
-
-			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
-				(unsigned long *) &loc->start))
-				return -EFAULT;
-
-			return 0;
-		}
-
-		case BLKRRPART: /* Re-read partition tables */
-			return ide_revalidate_disk(inode->i_rdev);
-
-		case HDIO_GET_IDENTITY:
-			if (minor(inode->i_rdev) & PARTN_MASK)
-				return -EINVAL;
-
-			if (drive->id == NULL)
-				return -ENOMSG;
-
-			if (copy_to_user((char *)arg, (char *)drive->id, sizeof(*drive->id)))
-				return -EFAULT;
-
-			return 0;
-
-		case HDIO_GET_NICE:
-			return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP |
-					drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP,
-					(long *) arg);
-
-		case HDIO_DRIVE_CMD:
-			if (!capable(CAP_SYS_RAWIO))
-				return -EACCES;
-
-			return ide_cmd_ioctl(drive, arg);
-
-		case HDIO_SET_NICE:
-			if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP))))
-				return -EPERM;
-
-			drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
-			/* Only CD-ROM's and tapes support DSC overlap. */
-			if (drive->dsc_overlap && !(drive->type == ATA_ROM || drive->type == ATA_TAPE)) {
-				drive->dsc_overlap = 0;
-				return -EPERM;
-			}
-
-			return 0;
-
-		case BLKGETSIZE:
-		case BLKGETSIZE64:
-		case BLKROSET:
-		case BLKROGET:
-		case BLKFLSBUF:
-		case BLKSSZGET:
-		case BLKPG:
-		case BLKELVGET:
-		case BLKELVSET:
-		case BLKBSZGET:
-		case BLKBSZSET:
-			return blk_ioctl(inode->i_bdev, cmd, arg);
-
-		/*
-		 * uniform packet command handling
-		 */
-		case CDROMEJECT:
-		case CDROMCLOSETRAY:
-			return block_ioctl(inode->i_bdev, cmd, arg);
-
-		case HDIO_GET_BUSSTATE:
-			if (put_user(drive->channel->bus_state, (long *)arg))
-				return -EFAULT;
-
-			return 0;
-
-		case HDIO_SET_BUSSTATE:
-			if (drive->channel->busproc)
-				drive->channel->busproc(drive, (int)arg);
-
-			return 0;
-
-		/* Now check whatever this particular ioctl has a device type
-		 * specific implementation.
-		 */
-		default:
-			if (ata_ops(drive) && ata_ops(drive)->ioctl)
-				return ata_ops(drive)->ioctl(drive, inode, file, cmd, arg);
-
-			return -EINVAL;
-	}
-}
-
 static int ide_check_media_change(kdev_t i_rdev)
 {
 	struct ata_device *drive;
@@ -2537,642 +1596,22 @@
 		*p++ = '\0';
 }
 
-/****************************************************************************
- * FIXME: rewrite the following crap:
- */
-
-/*
- * stridx() returns the offset of c within s,
- * or -1 if c is '\0' or not found within s.
- */
-static int __init stridx (const char *s, char c)
-{
-	char *i = strchr(s, c);
-
-	return (i && c) ? i - s : -1;
-}
-
-/*
- * Parsing for ide_setup():
- *
- * 1. the first char of s must be '='.
- * 2. if the remainder matches one of the supplied keywords,
- *     the index (1 based) of the keyword is negated and returned.
- * 3. if the remainder is a series of no more than max_vals numbers
- *     separated by commas, the numbers are saved in vals[] and a
- *     count of how many were saved is returned.  Base10 is assumed,
- *     and base16 is allowed when prefixed with "0x".
- * 4. otherwise, zero is returned.
- */
-static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals)
-{
-	static const char *decimal = "0123456789";
-	static const char *hex = "0123456789abcdef";
-	int i, n;
-
-	if (*s++ == '=') {
-		/*
-		 * Try matching against the supplied keywords,
-		 * and return -(index+1) if we match one
-		 */
-		if (keywords != NULL) {
-			for (i = 0; *keywords != NULL; ++i) {
-				if (!strcmp(s, *keywords++))
-					return -(i+1);
-			}
-		}
-		/*
-		 * Look for a series of no more than "max_vals"
-		 * numeric values separated by commas, in base10,
-		 * or base16 when prefixed with "0x".
-		 * Return a count of how many were found.
-		 */
-		for (n = 0; (i = stridx(decimal, *s)) >= 0;) {
-			vals[n] = i;
-			while ((i = stridx(decimal, *++s)) >= 0)
-				vals[n] = (vals[n] * 10) + i;
-			if (*s == 'x' && !vals[n]) {
-				while ((i = stridx(hex, *++s)) >= 0)
-					vals[n] = (vals[n] * 0x10) + i;
-			}
-			if (++n == max_vals)
-				break;
-			if (*s == ',' || *s == ';')
-				++s;
-		}
-		if (!*s)
-			return n;
-	}
-	return 0;	/* zero = nothing matched */
-}
-
-/*
- * This gets called VERY EARLY during initialization, to handle kernel "command
- * line" strings beginning with "hdx=" or "ide".It gets called even before the
- * actual module gets initialized.
- *
- * Here is the complete set currently supported comand line options:
- *
- * "hdx="  is recognized for all "x" from "a" to "h", such as "hdc".
- * "idex=" is recognized for all "x" from "0" to "3", such as "ide1".
- *
- * "hdx=noprobe"	: drive may be present, but do not probe for it
- * "hdx=none"		: drive is NOT present, ignore cmos and do not probe
- * "hdx=nowerr"		: ignore the WRERR_STAT bit on this drive
- * "hdx=cdrom"		: drive is present, and is a cdrom drive
- * "hdx=cyl,head,sect"	: disk drive is present, with specified geometry
- * "hdx=noremap"	: do not remap 0->1 even though EZD was detected
- * "hdx=autotune"	: driver will attempt to tune interface speed
- *				to the fastest PIO mode supported,
- *				if possible for this drive only.
- *				Not fully supported by all chipset types,
- *				and quite likely to cause trouble with
- *				older/odd IDE drives.
- *
- * "hdx=slow"		: insert a huge pause after each access to the data
- *				port. Should be used only as a last resort.
- *
- * "hdxlun=xx"          : set the drive last logical unit.
- * "hdx=flash"		: allows for more than one ata_flash disk to be
- *				registered. In most cases, only one device
- *				will be present.
- * "hdx=ide-scsi"	: the return of the ide-scsi flag, this is useful for
- *				allowwing ide-floppy, ide-tape, and ide-cdrom|writers
- *				to use ide-scsi emulation on a device specific option.
- * "idebus=xx"		: inform IDE driver of VESA/PCI bus speed in MHz,
- *				where "xx" is between 20 and 66 inclusive,
- *				used when tuning chipset PIO modes.
- *				For PCI bus, 25 is correct for a P75 system,
- *				30 is correct for P90,P120,P180 systems,
- *				and 33 is used for P100,P133,P166 systems.
- *				If in doubt, use idebus=33 for PCI.
- *				As for VLB, it is safest to not specify it.
- *
- * "idex=noprobe"	: do not attempt to access/use this interface
- * "idex=base"		: probe for an interface at the address specified,
- *				where "base" is usually 0x1f0 or 0x170
- *				and "ctl" is assumed to be "base"+0x206
- * "idex=base,ctl"	: specify both base and ctl
- * "idex=base,ctl,irq"	: specify base, ctl, and irq number
- * "idex=autotune"	: driver will attempt to tune interface speed
- *				to the fastest PIO mode supported,
- *				for all drives on this interface.
- *				Not fully supported by all chipset types,
- *				and quite likely to cause trouble with
- *				older/odd IDE drives.
- * "idex=noautotune"	: driver will NOT attempt to tune interface speed
- *				This is the default for most chipsets,
- *				except the cmd640.
- * "idex=serialize"	: do not overlap operations on idex and ide(x^1)
- * "idex=four"		: four drives on idex and ide(x^1) share same ports
- * "idex=reset"		: reset interface before first use
- * "idex=dma"		: enable DMA by default on both drives if possible
- * "idex=ata66"		: informs the interface that it has an 80c cable
- *				for chipsets that are ATA-66 capable, but
- *				the ablity to bit test for detection is
- *				currently unknown.
- * "ide=reverse"	: Formerly called to pci sub-system, but now local.
- *
- * The following are valid ONLY on ide0, (except dc4030)
- * and the defaults for the base,ctl ports must not be altered.
- *
- * "ide0=dtc2278"	: probe/support DTC2278 interface
- * "ide0=ht6560b"	: probe/support HT6560B interface
- * "ide0=cmd640_vlb"	: *REQUIRED* for VLB cards with the CMD640 chip
- *			  (not for PCI -- automatically detected)
- * "ide0=qd65xx"	: probe/support qd65xx interface
- * "ide0=ali14xx"	: probe/support ali14xx chipsets (ALI M1439, M1443, M1445)
- * "ide0=umc8672"	: probe/support umc8672 chipsets
- * "idex=dc4030"	: probe/support Promise DC4030VL interface
- * "ide=doubler"	: probe/support IDE doublers on Amiga
- */
-int __init ide_setup (char *s)
-{
-	int i, vals[3];
-	struct ata_channel *hwif;
-	struct ata_device *drive;
-	unsigned int hw, unit;
-	const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
-	const char max_hwif  = '0' + (MAX_HWIFS - 1);
-
-	if (!strncmp(s, "hd=", 3))	/* hd= is for hd.c driver and not us */
-		return 0;
-
-	if (strncmp(s,"ide",3) &&
-	    strncmp(s,"idebus",6) &&
-	    strncmp(s,"hd",2))		/* hdx= & hdxlun= */
-		return 0;
-
-	printk(KERN_INFO  "ide_setup: %s", s);
-	init_ide_data ();
-
-#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-	if (!strcmp(s, "ide=doubler")) {
-		extern int ide_doubler;
-
-		printk(KERN_INFO" : Enabled support for IDE doublers\n");
-		ide_doubler = 1;
-
-		return 1;
-	}
-#endif
-
-	if (!strcmp(s, "ide=nodma")) {
-		printk(KERN_INFO "ATA: Prevented DMA\n");
-		noautodma = 1;
-
-		return 1;
-	}
-
-#ifdef CONFIG_PCI
-	if (!strcmp(s, "ide=reverse")) {
-		ide_scan_direction = 1;
-		printk(" : Enabled support for IDE inverse scan order.\n");
-
-		return 1;
-	}
-#endif
-
-	/*
-	 * Look for drive options:  "hdx="
-	 */
-	if (!strncmp(s, "hd", 2) && s[2] >= 'a' && s[2] <= max_drive) {
-		const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
-				"serialize", "autotune", "noautotune",
-				"slow", "flash", "remap", "noremap", "scsi", NULL};
-		unit = s[2] - 'a';
-		hw   = unit / MAX_DRIVES;
-		unit = unit % MAX_DRIVES;
-		hwif = &ide_hwifs[hw];
-		drive = &hwif->drives[unit];
-		if (!strncmp(s + 4, "ide-", 4)) {
-			strncpy(drive->driver_req, s + 4, 9);
-			goto done;
-		}
-		/*
-		 * Look for last lun option:  "hdxlun="
-		 */
-		if (!strncmp(&s[3], "lun", 3)) {
-			if (match_parm(&s[6], NULL, vals, 1) != 1)
-				goto bad_option;
-			if (vals[0] >= 0 && vals[0] <= 7) {
-				drive->last_lun = vals[0];
-				drive->forced_lun = 1;
-			} else
-				printk(" -- BAD LAST LUN! Expected value from 0 to 7");
-			goto done;
-		}
-		switch (match_parm(&s[3], hd_words, vals, 3)) {
-			case -1: /* "none" */
-				drive->nobios = 1;  /* drop into "noprobe" */
-			case -2: /* "noprobe" */
-				drive->noprobe = 1;
-				goto done;
-			case -3: /* "nowerr" */
-				drive->bad_wstat = BAD_R_STAT;
-				hwif->noprobe = 0;
-				goto done;
-			case -4: /* "cdrom" */
-				drive->present = 1;
-				drive->type = ATA_ROM;
-				hwif->noprobe = 0;
-				goto done;
-			case -5: /* "serialize" */
-				printk(" -- USE \"ide%d=serialize\" INSTEAD", hw);
-				goto do_serialize;
-			case -6: /* "autotune" */
-				drive->autotune = 1;
-				goto done;
-			case -7: /* "noautotune" */
-				drive->autotune = 2;
-				goto done;
-			case -8: /* "slow" */
-				hwif->slow = 1;
-				goto done;
-			case -9: /* "flash" */
-				drive->ata_flash = 1;
-				goto done;
-			case -10: /* "remap" */
-				drive->remap_0_to_1 = 1;
-				goto done;
-			case -11: /* "noremap" */
-				drive->remap_0_to_1 = 2;
-				goto done;
-			case -12: /* "scsi" */
-#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
-				drive->scsi = 1;
-				goto done;
-#else
-				drive->scsi = 0;
-				goto bad_option;
-#endif
-			case 3: /* cyl,head,sect */
-				drive->type	= ATA_DISK;
-				drive->cyl	= drive->bios_cyl  = vals[0];
-				drive->head	= drive->bios_head = vals[1];
-				drive->sect	= drive->bios_sect = vals[2];
-				drive->present	= 1;
-				drive->forced_geom = 1;
-				hwif->noprobe = 0;
-				goto done;
-			default:
-				goto bad_option;
-		}
-	}
-
-	/*
-	 * Look for bus speed option:  "idebus="
-	 */
-	if (!strncmp(s, "idebus", 6)) {
-		if (match_parm(&s[6], NULL, vals, 1) != 1)
-			goto bad_option;
-		idebus_parameter = vals[0];
-		goto done;
-	}
-
-	/*
-	 * Look for interface options:  "idex="
-	 */
-	if (!strncmp(s, "ide", 3) && s[3] >= '0' && s[3] <= max_hwif) {
-		/*
-		 * Be VERY CAREFUL changing this: note hardcoded indexes below
-		 * -8,-9,-10. -11 : are reserved for future idex calls to ease the hardcoding.
-		 */
-		const char *ide_words[] = {
-			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
-			"minus8", "minus9", "minus10", "minus11",
-			"qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
-		hw = s[3] - '0';
-		hwif = &ide_hwifs[hw];
-
-		i = match_parm(&s[4], ide_words, vals, 3);
-
-		/*
-		 * Cryptic check to ensure chipset not already set for hwif:
-		 */
-		if (i > 0 || i <= -11) {			/* is parameter a chipset name? */
-			if (hwif->chipset != ide_unknown)
-				goto bad_option;	/* chipset already specified */
-			if (i <= -11 && i != -18 && hw != 0)
-				goto bad_hwif;		/* chipset drivers are for "ide0=" only */
-			if (i <= -11 && i != -18 && ide_hwifs[hw+1].chipset != ide_unknown)
-				goto bad_option;	/* chipset for 2nd port already specified */
-			printk("\n");
-		}
-
-		switch (i) {
-#ifdef CONFIG_BLK_DEV_PDC4030
-			case -18: /* "dc4030" */
-			{
-				extern void init_pdc4030(void);
-				init_pdc4030();
-				goto done;
-			}
-#endif
-#ifdef CONFIG_BLK_DEV_ALI14XX
-			case -17: /* "ali14xx" */
-			{
-				extern void init_ali14xx (void);
-				init_ali14xx();
-				goto done;
-			}
-#endif
-#ifdef CONFIG_BLK_DEV_UMC8672
-			case -16: /* "umc8672" */
-			{
-				extern void init_umc8672 (void);
-				init_umc8672();
-				goto done;
-			}
-#endif
-#ifdef CONFIG_BLK_DEV_DTC2278
-			case -15: /* "dtc2278" */
-			{
-				extern void init_dtc2278 (void);
-				init_dtc2278();
-				goto done;
-			}
-#endif
-#ifdef CONFIG_BLK_DEV_CMD640
-			case -14: /* "cmd640_vlb" */
-			{
-				extern int cmd640_vlb; /* flag for cmd640.c */
-				cmd640_vlb = 1;
-				goto done;
-			}
-#endif
-#ifdef CONFIG_BLK_DEV_HT6560B
-			case -13: /* "ht6560b" */
-			{
-				extern void init_ht6560b (void);
-				init_ht6560b();
-				goto done;
-			}
-#endif
-#if CONFIG_BLK_DEV_QD65XX
-			case -12: /* "qd65xx" */
-			{
-				extern void init_qd65xx (void);
-				init_qd65xx();
-				goto done;
-			}
-#endif
-			case -11: /* minus11 */
-			case -10: /* minus10 */
-			case -9: /* minus9 */
-			case -8: /* minus8 */
-				goto bad_option;
-			case -7: /* ata66 */
-#ifdef CONFIG_PCI
-				hwif->udma_four = 1;
-				goto done;
-#else
-				hwif->udma_four = 0;
-				goto bad_hwif;
-#endif
-			case -6: /* dma */
-				hwif->autodma = 1;
-				goto done;
-			case -5: /* "reset" */
-				hwif->reset = 1;
-				goto done;
-			case -4: /* "noautotune" */
-				hwif->drives[0].autotune = 2;
-				hwif->drives[1].autotune = 2;
-				goto done;
-			case -3: /* "autotune" */
-				hwif->drives[0].autotune = 1;
-				hwif->drives[1].autotune = 1;
-				goto done;
-			case -2: /* "serialize" */
-			do_serialize:
-				{
-					struct ata_channel *mate;
-
-					mate = &ide_hwifs[hw ^ 1];
-					hwif->serialized = 1;
-					mate->serialized = 1;
-				}
-				goto done;
-
-			case -1: /* "noprobe" */
-				hwif->noprobe = 1;
-				goto done;
-
-			case 1:	/* base */
-				vals[1] = vals[0] + 0x206; /* default ctl */
-			case 2: /* base,ctl */
-				vals[2] = 0;	/* default irq = probe for it */
-			case 3: /* base,ctl,irq */
-				hwif->hw.irq = vals[2];
-				ide_init_hwif_ports(&hwif->hw, (ide_ioreg_t) vals[0], (ide_ioreg_t) vals[1], &hwif->irq);
-				memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-				hwif->irq      = vals[2];
-				hwif->noprobe  = 0;
-				hwif->chipset  = ide_generic;
-				goto done;
-
-			case 0: goto bad_option;
-			default:
-				printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n");
-				return 1;
-		}
-	}
-
-bad_option:
-	printk(" -- BAD OPTION\n");
-	return 1;
-
-bad_hwif:
-	printk("-- NOT SUPPORTED ON ide%d", hw);
-
-done:
-	printk("\n");
-
-	return 1;
-}
-
-/****************************************************************************/
-
-/* This is the default end request function as well */
-int ide_end_request(struct ata_device *drive, struct request *rq, int uptodate)
-{
-	return __ide_end_request(drive, rq, uptodate, 0);
-}
-
-/*
- * This is in fact registering a device not a driver.
- */
-int ide_register_subdriver(struct ata_device *drive, struct ata_operations *driver)
-{
-	unsigned long flags;
-
-	save_flags(flags);		/* all CPUs */
-	cli();				/* all CPUs */
-	if (!drive->present || drive->driver != NULL || drive->busy || drive->usage) {
-		restore_flags(flags);	/* all CPUs */
-		return 1;
-	}
-
-	/* FIXME: This will be pushed to the drivers! Thus allowing us to
-	 * save one parameter here separate this out.
-	 */
-
-	drive->driver = driver;
-
-	restore_flags(flags);		/* all CPUs */
-	/* FIXME: Check what this magic number is supposed to be about? */
-	if (drive->autotune != 2) {
-		if (drive->channel->XXX_udma) {
-
-			/*
-			 * Force DMAing for the beginning of the check.  Some
-			 * chipsets appear to do interesting things, if not
-			 * checked and cleared.
-			 *
-			 *   PARANOIA!!!
-			 */
-
-			udma_enable(drive, 0, 0);
-			drive->channel->XXX_udma(drive);
-#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
-			udma_tcq_enable(drive, 1);
-#endif
-		}
-
-		/* Only CD-ROMs and tape drives support DSC overlap.  But only
-		 * if they are alone on a channel. */
-		if (drive->type == ATA_ROM || drive->type == ATA_TAPE) {
-			int single = 0;
-			int unit;
-
-			for (unit = 0; unit < MAX_DRIVES; ++unit)
-				if (drive->channel->drives[unit].present)
-					++single;
-
-			drive->dsc_overlap = (single == 1);
-		} else
-			drive->dsc_overlap = 0;
-
-	}
-	drive->revalidate = 1;
-	drive->suspend_reset = 0;
-
-	return 0;
-}
-
-/*
- * This is in fact the default cleanup routine.
- *
- * FIXME: Check whatever we maybe don't call it twice!.
- */
-int ide_unregister_subdriver(struct ata_device *drive)
-{
-	unsigned long flags;
-
-	save_flags(flags);		/* all CPUs */
-	cli();				/* all CPUs */
-
-#if 0
-	if (__MOD_IN_USE(ata_ops(drive)->owner)) {
-		restore_flags(flags);
-		return 1;
-	}
-#endif
-
-	if (drive->usage || drive->busy || !ata_ops(drive)) {
-		restore_flags(flags);	/* all CPUs */
-		return 1;
-	}
-
-#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
-	pnpide_init(0);
-#endif
-	drive->driver = NULL;
-
-	restore_flags(flags);		/* all CPUs */
-
-	return 0;
-}
-
-
-/*
- * Register an ATA subdriver for a particular device type.
- */
-
-int register_ata_driver(struct ata_operations *driver)
-{
-	unsigned long flags;
-	int index;
-	int count = 0;
-
-	spin_lock_irqsave(&ata_drivers_lock, flags);
-	driver->next = ata_drivers;
-	ata_drivers = driver;
-	spin_unlock_irqrestore(&ata_drivers_lock, flags);
-
-	for (index = 0; index < MAX_HWIFS; ++index)
-		count += subdriver_match(&ide_hwifs[index], driver);
-
-	return count;
-}
-
-EXPORT_SYMBOL(register_ata_driver);
-
-/*
- * Unregister an ATA subdriver for a particular device type.
- */
-void unregister_ata_driver(struct ata_operations *driver)
-{
-	struct ata_operations **tmp;
-	unsigned long flags;
-	int index;
-	int unit;
-
-	spin_lock_irqsave(&ata_drivers_lock, flags);
-	for (tmp = &ata_drivers; *tmp != NULL; tmp = &(*tmp)->next) {
-		if (*tmp == driver) {
-			*tmp = driver->next;
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&ata_drivers_lock, flags);
-
-	for (index = 0; index < MAX_HWIFS; ++index) {
-		struct ata_channel *ch = &ide_hwifs[index];
-		for (unit = 0; unit < MAX_DRIVES; ++unit) {
-			struct ata_device *drive = &ch->drives[unit];
-
-			if (drive->driver == driver)
-				(*ata_ops(drive)->cleanup)(drive);
-		}
-	}
-}
-
-EXPORT_SYMBOL(unregister_ata_driver);
-
 struct block_device_operations ide_fops[] = {{
 	owner:			THIS_MODULE,
 	open:			ide_open,
 	release:		ide_release,
-	ioctl:			ide_ioctl,
+	ioctl:			ata_ioctl,
 	check_media_change:	ide_check_media_change,
-	revalidate:		ide_revalidate_disk
+	revalidate:		ata_revalidate
 }};
 
 EXPORT_SYMBOL(ide_fops);
-EXPORT_SYMBOL(ide_hwifs);
 EXPORT_SYMBOL(ide_spin_wait_hwgroup);
 
-devfs_handle_t ide_devfs_handle;
-
-EXPORT_SYMBOL(ide_lock);
 EXPORT_SYMBOL(drive_is_flashcard);
 EXPORT_SYMBOL(ide_timer_expiry);
 EXPORT_SYMBOL(do_ide_request);
 
-EXPORT_SYMBOL(ide_register_subdriver);
-EXPORT_SYMBOL(ide_unregister_subdriver);
 EXPORT_SYMBOL(ide_set_handler);
 EXPORT_SYMBOL(ide_dump_status);
 EXPORT_SYMBOL(ide_error);
@@ -3182,324 +1621,6 @@
 EXPORT_SYMBOL(ide_end_drive_cmd);
 EXPORT_SYMBOL(__ide_end_request);
 EXPORT_SYMBOL(ide_end_request);
-EXPORT_SYMBOL(ide_revalidate_disk);
-EXPORT_SYMBOL(ide_delay_50ms);
 EXPORT_SYMBOL(ide_stall_queue);
 
-EXPORT_SYMBOL(ide_register_hw);
-EXPORT_SYMBOL(ide_register);
-EXPORT_SYMBOL(ide_unregister);
 EXPORT_SYMBOL(ide_setup_ports);
-EXPORT_SYMBOL(get_info_ptr);
-
-/*
- * Handle power handling related events ths system informs us about.
- */
-static int ata_sys_notify(struct notifier_block *this, unsigned long event, void *x)
-{
-	int i;
-
-	switch (event) {
-		case SYS_HALT:
-		case SYS_POWER_OFF:
-		case SYS_RESTART:
-			break;
-		default:
-			return NOTIFY_DONE;
-	}
-
-	printk("flushing ide devices: ");
-
-	for (i = 0; i < MAX_HWIFS; i++) {
-		int unit;
-		struct ata_channel *ch = &ide_hwifs[i];
-
-		if (!ch->present)
-			continue;
-
-		for (unit = 0; unit < MAX_DRIVES; ++unit) {
-			struct ata_device *drive = &ch->drives[unit];
-
-			if (!drive->present)
-				continue;
-
-			/* set the drive to standby */
-			printk("%s ", drive->name);
-			if (ata_ops(drive)) {
-				if (event != SYS_RESTART)
-					if (ata_ops(drive)->standby && ata_ops(drive)->standby(drive))
-						continue;
-
-				if (ata_ops(drive)->cleanup)
-					ata_ops(drive)->cleanup(drive);
-			}
-		}
-	}
-	printk("\n");
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block ata_notifier = {
-	ata_sys_notify,
-	NULL,
-	5
-};
-
-/*
- * This is the global initialization entry point.
- */
-static int __init ata_module_init(void)
-{
-	int h;
-
-	printk(KERN_INFO "ATA/ATAPI device driver v" VERSION "\n");
-
-	ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL);
-
-	/*
-	 * Because most of the ATA adapters represent the timings in unit of
-	 * bus clocks, and there is no known reliable way to detect the bus
-	 * clock frequency, we assume 50 MHz for non-PCI (VLB, EISA) and 33 MHz
-	 * for PCI based systems. Since assuming only hurts performance and not
-	 * stability, this is OK. The user can change this on the command line
-	 * by using the "idebus=XX" parameter. While the system_bus_speed
-	 * variable is in kHz units, we accept both MHz and kHz entry on the
-	 * command line for backward compatibility.
-	 */
-
-	system_bus_speed = 50000;
-
-	if (pci_present())
-	    system_bus_speed = 33333;
-
-	if (idebus_parameter >= 20 && idebus_parameter <= 80) {
-
-		system_bus_speed = idebus_parameter * 1000;
-
-		switch (system_bus_speed) {
-			case 33000: system_bus_speed = 33333; break;
-			case 37000: system_bus_speed = 37500; break;
-			case 41000: system_bus_speed = 41666; break;
-			case 66000: system_bus_speed = 66666; break;
-		}
-	}
-
-	if (idebus_parameter >= 20000 && idebus_parameter <= 80000)
-	    system_bus_speed = idebus_parameter;
-
-	printk(KERN_INFO "ATA: %s bus speed %d.%dMHz\n",
-		pci_present() ? "PCI" : "System", system_bus_speed / 1000, system_bus_speed / 100 % 10);
-
-	init_ide_data();
-
-	initializing = 1;
-
-#ifdef CONFIG_PCI
-	/*
-	 * Register the host chip drivers.
-	 */
-# ifdef CONFIG_BLK_DEV_PIIX
-	init_piix();
-# endif
-# ifdef CONFIG_BLK_DEV_VIA82CXXX
-	init_via82cxxx();
-# endif
-# ifdef CONFIG_BLK_DEV_PDC202XX
-	init_pdc202xx();
-# endif
-# ifdef CONFIG_BLK_DEV_RZ1000
-	init_rz1000();
-# endif
-# ifdef CONFIG_BLK_DEV_SIS5513
-	init_sis5513();
-# endif
-# ifdef CONFIG_BLK_DEV_CMD64X
-	init_cmd64x();
-# endif
-# ifdef CONFIG_BLK_DEV_OPTI621
-	init_opti621();
-# endif
-# ifdef CONFIG_BLK_DEV_TRM290
-	init_trm290();
-# endif
-# ifdef CONFIG_BLK_DEV_NS87415
-	init_ns87415();
-# endif
-# ifdef CONFIG_BLK_DEV_AEC62XX
-	init_aec62xx();
-# endif
-# ifdef CONFIG_BLK_DEV_SL82C105
-	init_sl82c105();
-# endif
-# ifdef CONFIG_BLK_DEV_HPT34X
-	init_hpt34x();
-# endif
-# ifdef CONFIG_BLK_DEV_HPT366
-	init_hpt366();
-# endif
-# ifdef CONFIG_BLK_DEV_ALI15X3
-	init_ali15x3();
-# endif
-# ifdef CONFIG_BLK_DEV_CY82C693
-	init_cy82c693();
-# endif
-# ifdef CONFIG_BLK_DEV_CS5530
-	init_cs5530();
-# endif
-# ifdef CONFIG_BLK_DEV_AMD74XX
-	init_amd74xx();
-# endif
-# ifdef CONFIG_BLK_DEV_SVWKS
-	init_svwks();
-# endif
-# ifdef CONFIG_BLK_DEV_IT8172
-	init_it8172();
-# endif
-
-	init_ata_pci_misc();
-
-	/*
-	 * Detect and initialize "known" IDE host chip types.
-	 */
-	if (pci_present()) {
-# ifdef CONFIG_PCI
-		ide_scan_pcibus(ide_scan_direction);
-# else
-#  ifdef CONFIG_BLK_DEV_RZ1000
-		ide_probe_for_rz100x();
-#  endif
-# endif
-	}
-#endif
-
-#ifdef CONFIG_ETRAX_IDE
-	init_e100_ide();
-#endif
-#ifdef CONFIG_BLK_DEV_CMD640
-	ide_probe_for_cmd640x();
-#endif
-#ifdef CONFIG_BLK_DEV_PDC4030
-	ide_probe_for_pdc4030();
-#endif
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	pmac_ide_probe();
-#endif
-#ifdef CONFIG_BLK_DEV_IDE_ICSIDE
-	icside_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDE_RAPIDE
-	rapide_init();
-#endif
-#ifdef CONFIG_BLK_DEV_GAYLE
-	gayle_init();
-#endif
-#ifdef CONFIG_BLK_DEV_FALCON_IDE
-	falconide_init();
-#endif
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-	macide_init();
-#endif
-#ifdef CONFIG_BLK_DEV_Q40IDE
-	q40ide_init();
-#endif
-#ifdef CONFIG_BLK_DEV_BUDDHA
-	buddha_init();
-#endif
-#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
-	pnpide_init(1);
-#endif
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-# if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		// ide_get_lock(&irq_lock, NULL, NULL);/* for atari only */
-		disable_irq(ide_hwifs[0].irq);	/* disable_irq_nosync ?? */
-//		disable_irq_nosync(ide_hwifs[0].irq);
-	}
-# endif
-
-	ideprobe_init();
-
-# if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		enable_irq(ide_hwifs[0].irq);
-		ide_release_lock(&irq_lock);/* for atari only */
-	}
-# endif
-#endif
-
-	/*
-	 * Initialize all device type driver modules.
-	 */
-#ifdef CONFIG_BLK_DEV_IDEDISK
-	idedisk_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDECD
-	ide_cdrom_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDETAPE
-	idetape_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDEFLOPPY
-	idefloppy_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDESCSI
-# ifdef CONFIG_SCSI
-	idescsi_init();
-# else
-   #error ATA SCSI emulation selected but no SCSI-subsystem in kernel
-# endif
-#endif
-
-	initializing = 0;
-
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		struct ata_channel *channel = &ide_hwifs[h];
-		if (channel->present)
-			ide_geninit(channel);
-	}
-
-	register_reboot_notifier(&ata_notifier);
-
-	return 0;
-}
-
-static char *options = NULL;
-
-static int __init init_ata(void)
-{
-
-	if (options != NULL && *options) {
-		char *next = options;
-
-		while ((options = next) != NULL) {
-			if ((next = strchr(options,' ')) != NULL)
-				*next++ = 0;
-			if (!ide_setup(options))
-				printk(KERN_ERR "Unknown option '%s'\n", options);
-		}
-	}
-	return ata_module_init();
-}
-
-static void __exit cleanup_ata(void)
-{
-	int h;
-
-	unregister_reboot_notifier(&ata_notifier);
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		ide_unregister(&ide_hwifs[h]);
-	}
-
-	devfs_unregister(ide_devfs_handle);
-}
-
-module_init(init_ata);
-module_exit(cleanup_ata);
-
-#ifndef MODULE
-
-/* command line option parser */
-__setup("", ide_setup);
-
-#endif
diff -Nru a/drivers/ide/ioctl.c b/drivers/ide/ioctl.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ioctl.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,285 @@
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
+ * Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is 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.
+ */
+
+/*
+ * Generic ioctl handling for all ATA/ATAPI device drivers.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/blkpg.h>
+#include <linux/pci.h>
+#include <linux/cdrom.h>
+#include <linux/device.h>
+
+#include <linux/ide.h>
+
+#include <asm/uaccess.h>
+
+#include "ioctl.h"
+
+/*
+ * NOTE: Due to ridiculous coding habbits in the hdparm utility we have to
+ * always return unsigned long in case we are returning simple values.
+ */
+int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int major, minor;
+	struct ata_device *drive;
+	struct request rq;
+	kdev_t dev;
+
+	dev = inode->i_rdev;
+	major = major(dev);
+	minor = minor(dev);
+
+	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
+		return -ENODEV;
+
+
+	/* Contrary to popular beleve we disallow even the reading of the ioctl
+	 * values for users which don't have permission too. We do this becouse
+	 * such information could be used by an attacker to deply a simple-user
+	 * attack, which triggers bugs present only on a particular
+	 * configuration.
+	 */
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	ide_init_drive_cmd(&rq);
+	switch (cmd) {
+		case HDIO_GET_32BIT: {
+			unsigned long val = drive->channel->io_32bit;
+
+			if (put_user(val, (unsigned long *) arg))
+				return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_SET_32BIT:
+			if (arg < 0 || arg > 1)
+				return -EINVAL;
+
+			if (drive->channel->no_io_32bit)
+				return -EIO;
+
+			if (ide_spin_wait_hwgroup(drive))
+				return -EBUSY;
+
+			drive->channel->io_32bit = arg;
+			spin_unlock_irq(drive->channel->lock);
+
+			return 0;
+
+		case HDIO_SET_PIO_MODE:
+			if (arg < 0 || arg > 255)
+				return -EINVAL;
+
+			if (!drive->channel->tuneproc)
+				return -ENOSYS;
+
+			/* FIXME: we can see that tuneproc whould do the
+			 * locking!.
+			 */
+
+			if (ide_spin_wait_hwgroup(drive))
+				return -EBUSY;
+
+			drive->channel->tuneproc(drive, (u8) arg);
+			spin_unlock_irq(drive->channel->lock);
+
+			return 0;
+
+		case HDIO_GET_UNMASKINTR: {
+			unsigned long val = drive->channel->unmask;
+
+			if (put_user(val, (unsigned long *) arg))
+				return -EFAULT;
+
+			return 0;
+		}
+
+
+		case HDIO_SET_UNMASKINTR:
+			if (arg < 0 || arg > 1)
+				return -EINVAL;
+
+			if (drive->channel->no_unmask)
+				return -EIO;
+
+			if (ide_spin_wait_hwgroup(drive))
+				return -EBUSY;
+
+			drive->channel->unmask = arg;
+			spin_unlock_irq(drive->channel->lock);
+
+			return 0;
+
+		case HDIO_GET_DMA: {
+			unsigned long val = drive->using_dma;
+
+			if (put_user(val, (unsigned long *) arg))
+				return -EFAULT;
+
+			return 0;
+		}
+
+		case HDIO_SET_DMA:
+			if (arg < 0 || arg > 1)
+				return -EINVAL;
+
+			if (!drive->driver)
+				return -EPERM;
+
+			if (!drive->id || !(drive->id->capability & 1) || !drive->channel->XXX_udma)
+				return -EPERM;
+
+			if (ide_spin_wait_hwgroup(drive))
+				return -EBUSY;
+
+			udma_enable(drive, arg, 1);
+			spin_unlock_irq(drive->channel->lock);
+
+			return 0;
+
+		case HDIO_GETGEO: {
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl = drive->bios_cyl; /* truncate */
+
+			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
+				return -EINVAL;
+
+			if (put_user(drive->bios_head, (byte *) &loc->heads))
+				return -EFAULT;
+
+			if (put_user(drive->bios_sect, (byte *) &loc->sectors))
+				return -EFAULT;
+
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders))
+				return -EFAULT;
+
+			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
+				(unsigned long *) &loc->start))
+				return -EFAULT;
+
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG_RAW: {
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+
+			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
+				return -EINVAL;
+
+			if (put_user(drive->head, (u8 *) &loc->heads))
+				return -EFAULT;
+
+			if (put_user(drive->sect, (u8 *) &loc->sectors))
+				return -EFAULT;
+
+			if (put_user(drive->cyl, (unsigned int *) &loc->cylinders))
+				return -EFAULT;
+
+			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
+				(unsigned long *) &loc->start))
+				return -EFAULT;
+
+			return 0;
+		}
+
+		case BLKRRPART: /* Re-read partition tables */
+			return ata_revalidate(inode->i_rdev);
+
+		case HDIO_GET_IDENTITY:
+			if (minor(inode->i_rdev) & PARTN_MASK)
+				return -EINVAL;
+
+			if (drive->id == NULL)
+				return -ENOMSG;
+
+			if (copy_to_user((char *)arg, (char *)drive->id, sizeof(*drive->id)))
+				return -EFAULT;
+
+			return 0;
+
+		case HDIO_GET_NICE:
+			return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP |
+					drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP,
+					(long *) arg);
+
+		case HDIO_DRIVE_CMD:
+			if (!capable(CAP_SYS_RAWIO))
+				return -EACCES;
+
+			return ide_cmd_ioctl(drive, arg);
+
+		case HDIO_SET_NICE:
+			if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP))))
+				return -EPERM;
+
+			drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
+			/* Only CD-ROM's and tapes support DSC overlap. */
+			if (drive->dsc_overlap && !(drive->type == ATA_ROM || drive->type == ATA_TAPE)) {
+				drive->dsc_overlap = 0;
+				return -EPERM;
+			}
+
+			return 0;
+
+		case BLKGETSIZE:
+		case BLKGETSIZE64:
+		case BLKROSET:
+		case BLKROGET:
+		case BLKFLSBUF:
+		case BLKSSZGET:
+		case BLKPG:
+		case BLKELVGET:
+		case BLKELVSET:
+		case BLKBSZGET:
+		case BLKBSZSET:
+			return blk_ioctl(inode->i_bdev, cmd, arg);
+
+		/*
+		 * uniform packet command handling
+		 */
+		case CDROMEJECT:
+		case CDROMCLOSETRAY:
+			return block_ioctl(inode->i_bdev, cmd, arg);
+
+		case HDIO_GET_BUSSTATE:
+			if (put_user(drive->channel->bus_state, (long *)arg))
+				return -EFAULT;
+
+			return 0;
+
+		case HDIO_SET_BUSSTATE:
+			if (drive->channel->busproc)
+				drive->channel->busproc(drive, (int)arg);
+
+			return 0;
+
+		/* Now check whatever this particular ioctl has a device type
+		 * specific implementation.
+		 */
+		default:
+			if (ata_ops(drive) && ata_ops(drive)->ioctl)
+				return ata_ops(drive)->ioctl(drive, inode, file, cmd, arg);
+
+			return -EINVAL;
+	}
+}
diff -Nru a/drivers/ide/ioctl.h b/drivers/ide/ioctl.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ioctl.h	Wed May 29 11:43:03 2002
@@ -0,0 +1,15 @@
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
+ * Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is 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.
+ */
+
+extern int ata_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
diff -Nru a/drivers/ide/it8172.c b/drivers/ide/it8172.c
--- a/drivers/ide/it8172.c	Wed May 29 11:43:01 2002
+++ b/drivers/ide/it8172.c	Wed May 29 11:43:01 2002
@@ -187,8 +187,6 @@
 
     it8172_tune_drive(drive, it8172_dma_2_pio(speed));
 
-    if (!drive->init_speed)
-	drive->init_speed = speed;
     err = ide_config_drive_speed(drive, speed);
     drive->current_speed = speed;
     return err;
diff -Nru a/drivers/ide/macide.c b/drivers/ide/macide.c
--- a/drivers/ide/macide.c	Wed May 29 11:43:01 2002
+++ b/drivers/ide/macide.c	Wed May 29 11:43:01 2002
@@ -100,17 +100,17 @@
 	case MAC_IDE_QUADRA:
 		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
 				0, 0, macide_ack_intr, IRQ_NUBUS_F);
-		index = ide_register_hw(&hw, NULL);
+		index = ide_register_hw(&hw);
 		break;
 	case MAC_IDE_PB:
 		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
 				0, 0, macide_ack_intr, IRQ_NUBUS_C);
-		index = ide_register_hw(&hw, NULL);
+		index = ide_register_hw(&hw);
 		break;
 	case MAC_IDE_BABOON:
 		ide_setup_ports(&hw, (ide_ioreg_t)BABOON_BASE, macide_offsets,
 				0, 0, NULL, IRQ_BABOON_1);
-		index = ide_register_hw(&hw, NULL);
+		index = ide_register_hw(&hw);
 		if (index == -1) break;
 		if (macintosh_config->ident == MAC_MODEL_PB190) {
 
diff -Nru a/drivers/ide/main.c b/drivers/ide/main.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/main.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,1537 @@
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
+ *  Copyright (C) 1994-1998,2002  Linus Torvalds and authors:
+ *
+ *	Mark Lord	<mlord@pobox.com>
+ *      Gadi Oxman	<gadio@netvision.net.il>
+ *      Andre Hedrick	<andre@linux-ide.org>
+ *	Jens Axboe	<axboe@suse.de>
+ *      Marcin Dalecki	<martin@dalecki.de>
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
+ */
+
+/*
+ * Handle overall infrastructure of the driver
+ */
+
+#define	VERSION	"7.0.0"
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#ifndef MODULE
+# include <linux/init.h>
+#endif
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/reboot.h>
+#include <linux/cdrom.h>
+#include <linux/device.h>
+#include <linux/kmod.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#include "ata-timing.h"
+#include "pcihost.h"
+#include "ioctl.h"
+
+
+MODULE_DESCRIPTION("ATA/ATAPI driver infrastructure");
+MODULE_PARM(options,"s");
+MODULE_LICENSE("GPL");
+
+/*
+ * Those will be moved into separate header files eventually.
+ */
+#ifdef CONFIG_ETRAX_IDE
+extern void init_e100_ide(void);
+#endif
+#ifdef CONFIG_BLK_DEV_CMD640
+extern void ide_probe_for_cmd640x(void);
+#endif
+#ifdef CONFIG_BLK_DEV_PDC4030
+extern int ide_probe_for_pdc4030(void);
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+extern void pmac_ide_probe(void);
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_ICSIDE
+extern void icside_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_RAPIDE
+extern void rapide_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_GAYLE
+extern void gayle_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_FALCON_IDE
+extern void falconide_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+extern void macide_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_Q40IDE
+extern void q40ide_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_BUDDHA
+extern void buddha_init(void);
+#endif
+#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
+extern void pnpide_init(int);
+#endif
+
+/* default maximum number of failures */
+#define IDE_DEFAULT_MAX_FAILURES	1
+
+int system_bus_speed;		/* holds what we think is VESA/PCI bus speed */
+
+static int initializing;	/* set while initializing built-in drivers */
+static int idebus_parameter;	/* the "idebus=" parameter */
+
+/*
+ * Protects access to global structures etc.
+ */
+spinlock_t ide_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
+
+#ifdef CONFIG_PCI
+static int ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
+#endif
+
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+/*
+ * This is used by the Atari code to obtain access to the IDE interrupt,
+ * which is shared between several drivers.
+ */
+static int irq_lock;
+#endif
+
+int noautodma = 0;
+
+/* Single linked list of sub device type drivers */
+static struct ata_operations *ata_drivers; /* = NULL */
+static spinlock_t ata_drivers_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * This is declared extern in ide.h, for access by other IDE modules:
+ */
+struct ata_channel ide_hwifs[MAX_HWIFS];	/* master data repository */
+
+/*
+ * FIXME: This function should be unrolled in the palces where it get's used,
+ * since in reality it's simple architecture specific initialization.
+ *
+ * Setup hw_regs_t structure described by parameters.  You may set up the hw
+ * structure yourself OR use this routine to do it for you.
+ */
+void ide_setup_ports(hw_regs_t *hw,
+		ide_ioreg_t base,
+		int *offsets,
+		ide_ioreg_t ctrl,
+		ide_ioreg_t intr,
+		ide_ack_intr_t *ack_intr,
+		int irq)
+{
+	int i;
+
+	for (i = 0; i < IDE_NR_PORTS; i++) {
+		if (offsets[i] != -1)
+			hw->io_ports[i] = base + offsets[i];
+		else
+			hw->io_ports[i] = 0;
+	}
+	if (offsets[IDE_CONTROL_OFFSET] == -1)
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl;
+
+	/* FIMXE: check if we can remove this ifdef */
+#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
+	if (offsets[IDE_IRQ_OFFSET] == -1)
+		hw->io_ports[IDE_IRQ_OFFSET] = intr;
+#endif
+
+	hw->irq = irq;
+	hw->dma = NO_DMA;
+	hw->ack_intr = ack_intr;
+}
+
+static void init_hwif_data(struct ata_channel *ch, unsigned int index)
+{
+	static const unsigned int majors[] = {
+		IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR,
+		IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR
+	};
+
+	unsigned int unit;
+	hw_regs_t hw;
+
+	/* bulk initialize channel & drive info with zeros */
+	memset(ch, 0, sizeof(struct ata_channel));
+	memset(&hw, 0, sizeof(hw_regs_t));
+
+	/* fill in any non-zero initial values */
+	ch->index = index;
+	ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &ch->irq);
+
+	memcpy(&ch->hw, &hw, sizeof(hw));
+	memcpy(ch->io_ports, hw.io_ports, sizeof(hw.io_ports));
+
+	ch->noprobe	= !ch->io_ports[IDE_DATA_OFFSET];
+#ifdef CONFIG_BLK_DEV_HD
+	if (ch->io_ports[IDE_DATA_OFFSET] == HD_DATA)
+		ch->noprobe = 1; /* may be overridden by ide_setup() */
+#endif
+
+	ch->major = majors[index];
+	sprintf(ch->name, "ide%d", index);
+	ch->bus_state = BUSSTATE_ON;
+
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		struct ata_device *drive = &ch->drives[unit];
+
+		drive->type		= ATA_DISK;
+		drive->select.all	= (unit<<4)|0xa0;
+		drive->channel		= ch;
+		drive->ctl		= 0x08;
+		drive->ready_stat	= READY_STAT;
+		drive->bad_wstat	= BAD_W_STAT;
+		sprintf(drive->name, "hd%c", 'a' + (index * MAX_DRIVES) + unit);
+		drive->max_failures	= IDE_DEFAULT_MAX_FAILURES;
+
+		init_waitqueue_head(&drive->wqueue);
+	}
+}
+
+extern struct block_device_operations ide_fops[];
+
+/*
+ * Returns the (struct ata_device *) for a given device number.  Return
+ * NULL if the given device number does not match any present drives.
+ */
+struct ata_device *get_info_ptr(kdev_t i_rdev)
+{
+	unsigned int major = major(i_rdev);
+	int h;
+
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		struct ata_channel *ch = &ide_hwifs[h];
+		if (ch->present && major == ch->major) {
+			int unit = DEVICE_NR(i_rdev);
+			if (unit < MAX_DRIVES) {
+				struct ata_device *drive = &ch->drives[unit];
+				if (drive->present)
+					return drive;
+			}
+			break;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * This routine is called to flush all partitions and partition tables
+ * for a changed disk, and then re-read the new partition table.
+ * If we are revalidating a disk because of a media change, then we
+ * enter with usage == 0.  If we are using an ioctl, we automatically have
+ * usage == 1 (we need an open channel to use an ioctl :-), so this
+ * is our limit.
+ */
+int ata_revalidate(kdev_t i_rdev)
+{
+	struct ata_device *drive;
+	unsigned long flags;
+	int res;
+
+	if ((drive = get_info_ptr(i_rdev)) == NULL)
+		return -ENODEV;
+
+	/* FIXME: The locking here doesn't make the slightest sense! */
+	spin_lock_irqsave(&ide_lock, flags);
+
+	if (drive->busy || (drive->usage > 1)) {
+		spin_unlock_irqrestore(&ide_lock, flags);
+
+		return -EBUSY;
+	}
+
+	drive->busy = 1;
+	MOD_INC_USE_COUNT;
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	res = wipe_partitions(i_rdev);
+	if (!res) {
+		if (ata_ops(drive) && ata_ops(drive)->revalidate) {
+			ata_get(ata_ops(drive));
+
+			/* This is expected to be a no-op for tapes and SCSI
+			 * based access.
+			 */
+			ata_ops(drive)->revalidate(drive);
+			ata_put(ata_ops(drive));
+		} else
+			grok_partitions(i_rdev, ata_capacity(drive));
+	}
+
+	drive->busy = 0;
+	wake_up(&drive->wqueue);
+
+	MOD_DEC_USE_COUNT;
+
+	return res;
+}
+
+/*
+ * FIXME: this is most propably just totally unnecessary.
+ *
+ * Look again for all drives in the system on all interfaces.
+ */
+static void revalidate_drives(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_HWIFS; ++i) {
+		int unit;
+		struct ata_channel *ch = &ide_hwifs[i];
+
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			struct ata_device *drive = &ch->drives[unit];
+
+			if (drive->revalidate) {
+				drive->revalidate = 0;
+				if (!initializing)
+					ata_revalidate(mk_kdev(ch->major, unit<<PARTN_BITS));
+			}
+		}
+	}
+}
+
+void ide_driver_module(void)
+{
+	int i;
+
+	/* Don't reinit the probe if there is already one channel detected. */
+
+	for (i = 0; i < MAX_HWIFS; ++i) {
+		if (ide_hwifs[i].present)
+			goto revalidate;
+	}
+
+	ideprobe_init();
+
+revalidate:
+	revalidate_drives();
+}
+
+/*
+ * Release the data associated with a channel.
+ */
+void ide_unregister(struct ata_channel *ch)
+{
+	struct gendisk *gd;
+	struct ata_device *d;
+	spinlock_t *lock;
+	int unit;
+	int i;
+	unsigned long flags;
+	unsigned int p, minor;
+	struct ata_channel old;
+	int n_irq;
+	int n_ch;
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	if (!ch->present)
+		goto abort;
+
+	put_device(&ch->dev);
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		struct ata_device * drive = &ch->drives[unit];
+
+		if (!drive->present)
+			continue;
+
+		if (drive->busy || drive->usage)
+			goto abort;
+
+		if (ata_ops(drive)) {
+			if (ata_ops(drive)->cleanup) {
+				if (ata_ops(drive)->cleanup(drive))
+					goto abort;
+			} else
+				ide_unregister_subdriver(drive);
+		}
+	}
+	ch->present = 0;
+
+	/*
+	 * All clear?  Then blow away the buffer cache
+	 */
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		struct ata_device * drive = &ch->drives[unit];
+
+		if (!drive->present)
+			continue;
+
+		minor = drive->select.b.unit << PARTN_BITS;
+		for (p = 0; p < (1<<PARTN_BITS); ++p) {
+			if (drive->part[p].nr_sects > 0) {
+				kdev_t devp = mk_kdev(ch->major, minor+p);
+				invalidate_device(devp, 0);
+			}
+		}
+	}
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	/*
+	 * Note that we only release the standard ports, and do not even try to
+	 * handle any extra ports allocated for weird IDE interface chipsets.
+	 */
+
+	if (ch->straight8) {
+		release_region(ch->io_ports[IDE_DATA_OFFSET], 8);
+	} else {
+		for (i = 0; i < 8; i++)
+			if (ch->io_ports[i])
+				release_region(ch->io_ports[i], 1);
+	}
+	if (ch->io_ports[IDE_CONTROL_OFFSET])
+		release_region(ch->io_ports[IDE_CONTROL_OFFSET], 1);
+/* FIXME: check if we can remove this ifdef */
+#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
+	if (ch->io_ports[IDE_IRQ_OFFSET])
+		release_region(ch->io_ports[IDE_IRQ_OFFSET], 1);
+#endif
+
+	/*
+	 * Remove us from the lock group.
+	 */
+
+	lock = ch->lock;
+	d = ch->drive;
+	for (i = 0; i < MAX_DRIVES; ++i) {
+		struct ata_device *drive = &ch->drives[i];
+
+		if (drive->de) {
+			devfs_unregister (drive->de);
+			drive->de = NULL;
+		}
+		if (!drive->present)
+			continue;
+
+		/* FIXME: possibly unneccessary */
+		if (ch->drive == drive)
+			ch->drive = NULL;
+
+		if (drive->id != NULL) {
+			kfree(drive->id);
+			drive->id = NULL;
+		}
+		drive->present = 0;
+		blk_cleanup_queue(&drive->queue);
+	}
+	if (d->present)
+		ch->drive = d;
+
+
+	/*
+	 * Free the irq if we were the only channel using it.
+	 *
+	 * Free the lock group if we were the only member.
+	 */
+	n_irq = n_ch = 0;
+	for (i = 0; i < MAX_HWIFS; ++i) {
+		struct ata_channel *tmp = &ide_hwifs[i];
+
+		if (!tmp->present)
+			continue;
+
+		if (tmp->irq == ch->irq)
+			++n_irq;
+		if (tmp->lock == ch->lock)
+			++n_ch;
+	}
+	if (n_irq == 1)
+		free_irq(ch->irq, ch);
+	if (n_ch == 1) {
+		kfree(ch->lock);
+		kfree(ch->active);
+		ch->lock = NULL;
+		ch->active = NULL;
+	}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	ide_release_dma(ch);
+#endif
+
+	/*
+	 * Remove us from the kernel's knowledge.
+	 */
+	unregister_blkdev(ch->major, ch->name);
+	blk_dev[ch->major].data = NULL;
+	blk_dev[ch->major].queue = NULL;
+	blk_clear(ch->major);
+	gd = ch->gd;
+	if (gd) {
+		del_gendisk(gd);
+		kfree(gd->sizes);
+		kfree(gd->part);
+		if (gd->de_arr)
+			kfree (gd->de_arr);
+		if (gd->flags)
+			kfree (gd->flags);
+		kfree(gd);
+		ch->gd = NULL;
+	}
+
+	/*
+	 * Reinitialize the channel handler, but preserve any special methods for
+	 * it.
+	 */
+
+	old = *ch;
+	init_hwif_data(ch, ch->index);
+	ch->lock = old.lock;
+	ch->tuneproc = old.tuneproc;
+	ch->speedproc = old.speedproc;
+	ch->selectproc = old.selectproc;
+	ch->resetproc = old.resetproc;
+	ch->intrproc = old.intrproc;
+	ch->maskproc = old.maskproc;
+	ch->quirkproc = old.quirkproc;
+	ch->ata_read = old.ata_read;
+	ch->ata_write = old.ata_write;
+	ch->atapi_read = old.atapi_read;
+	ch->atapi_write = old.atapi_write;
+	ch->XXX_udma = old.XXX_udma;
+	ch->udma_enable = old.udma_enable;
+	ch->udma_start = old.udma_start;
+	ch->udma_stop = old.udma_stop;
+	ch->udma_read = old.udma_read;
+	ch->udma_write = old.udma_write;
+	ch->udma_irq_status = old.udma_irq_status;
+	ch->udma_timeout = old.udma_timeout;
+	ch->udma_irq_lost = old.udma_irq_lost;
+	ch->busproc = old.busproc;
+	ch->bus_state = old.bus_state;
+	ch->dma_base = old.dma_base;
+	ch->dma_extra = old.dma_extra;
+	ch->config_data = old.config_data;
+	ch->select_data = old.select_data;
+	ch->proc = old.proc;
+	/* FIXME: most propably this is always right:! */
+#ifndef CONFIG_BLK_DEV_IDECS
+	ch->irq = old.irq;
+#endif
+	ch->major = old.major;
+	ch->chipset = old.chipset;
+	ch->autodma = old.autodma;
+	ch->udma_four = old.udma_four;
+#ifdef CONFIG_PCI
+	ch->pci_dev = old.pci_dev;
+#endif
+	ch->straight8 = old.straight8;
+
+abort:
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static int subdriver_match(struct ata_channel *channel, struct ata_operations *ops)
+{
+	int count, unit;
+
+	if (!channel->present)
+		return 0;
+
+	count = 0;
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		struct ata_device *drive = &channel->drives[unit];
+		if (drive->present && !drive->driver) {
+			(*ops->attach)(drive);
+			if (drive->driver != NULL)
+				count++;
+		}
+	}
+	return count;
+}
+
+static struct ata_operations * subdriver_iterator(struct ata_operations *prev)
+{
+	struct ata_operations *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ata_drivers_lock, flags);
+
+	/* Restart from beginning if current ata_operations was deallocated,
+	   or if prev is NULL. */
+	for(tmp = ata_drivers; tmp != prev && tmp; tmp = tmp->next);
+	if (!tmp)
+		tmp = ata_drivers;
+	else
+		tmp = tmp->next;
+
+	spin_unlock_irqrestore(&ata_drivers_lock, flags);
+
+	return tmp;
+
+}
+
+/*
+ * Register an IDE interface, specifing exactly the registers etc
+ * Set initializing=1 iff calling before probes have taken place.
+ */
+int ide_register_hw(hw_regs_t *hw)
+{
+	int h;
+	int retry = 1;
+	struct ata_channel *ch;
+	struct ata_operations *subdriver;
+
+	do {
+		for (h = 0; h < MAX_HWIFS; ++h) {
+			ch = &ide_hwifs[h];
+			if (ch->hw.io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET])
+				goto found;
+		}
+		for (h = 0; h < MAX_HWIFS; ++h) {
+			ch = &ide_hwifs[h];
+			if ((!ch->present && (ch->unit == ATA_PRIMARY) && !initializing) ||
+			    (!ch->hw.io_ports[IDE_DATA_OFFSET] && initializing))
+				goto found;
+		}
+		for (h = 0; h < MAX_HWIFS; ++h)
+			ide_unregister(&ide_hwifs[h]);
+	} while (retry--);
+
+	return -1;
+
+found:
+	ide_unregister(ch);
+	if (ch->present)
+		return -1;
+	memcpy(&ch->hw, hw, sizeof(*hw));
+	memcpy(ch->io_ports, ch->hw.io_ports, sizeof(ch->hw.io_ports));
+	ch->irq = hw->irq;
+	ch->noprobe = 0;
+	ch->chipset = hw->chipset;
+
+	if (!initializing) {
+		ideprobe_init();
+		revalidate_drives();
+		/* FIXME: Do we really have to call it second time here?! */
+		ide_driver_module();
+	}
+
+	/* Look up whatever there is a subdriver, which will serve this
+	 * device.
+	 */
+	subdriver = NULL;
+	while ((subdriver = subdriver_iterator(subdriver))) {
+		if (subdriver_match(ch, subdriver) > 0)
+			break;
+	}
+
+	return (initializing || ch->present) ? h : -1;
+}
+
+/****************************************************************************
+ * FIXME: rewrite the following crap:
+ */
+
+/*
+ * stridx() returns the offset of c within s,
+ * or -1 if c is '\0' or not found within s.
+ */
+static int __init stridx (const char *s, char c)
+{
+	char *i = strchr(s, c);
+
+	return (i && c) ? i - s : -1;
+}
+
+/*
+ * Parsing for ide_setup():
+ *
+ * 1. the first char of s must be '='.
+ * 2. if the remainder matches one of the supplied keywords,
+ *     the index (1 based) of the keyword is negated and returned.
+ * 3. if the remainder is a series of no more than max_vals numbers
+ *     separated by commas, the numbers are saved in vals[] and a
+ *     count of how many were saved is returned.  Base10 is assumed,
+ *     and base16 is allowed when prefixed with "0x".
+ * 4. otherwise, zero is returned.
+ */
+static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals)
+{
+	static const char *decimal = "0123456789";
+	static const char *hex = "0123456789abcdef";
+	int i, n;
+
+	if (*s++ == '=') {
+		/*
+		 * Try matching against the supplied keywords,
+		 * and return -(index+1) if we match one
+		 */
+		if (keywords != NULL) {
+			for (i = 0; *keywords != NULL; ++i) {
+				if (!strcmp(s, *keywords++))
+					return -(i+1);
+			}
+		}
+		/*
+		 * Look for a series of no more than "max_vals"
+		 * numeric values separated by commas, in base10,
+		 * or base16 when prefixed with "0x".
+		 * Return a count of how many were found.
+		 */
+		for (n = 0; (i = stridx(decimal, *s)) >= 0;) {
+			vals[n] = i;
+			while ((i = stridx(decimal, *++s)) >= 0)
+				vals[n] = (vals[n] * 10) + i;
+			if (*s == 'x' && !vals[n]) {
+				while ((i = stridx(hex, *++s)) >= 0)
+					vals[n] = (vals[n] * 0x10) + i;
+			}
+			if (++n == max_vals)
+				break;
+			if (*s == ',' || *s == ';')
+				++s;
+		}
+		if (!*s)
+			return n;
+	}
+	return 0;	/* zero = nothing matched */
+}
+
+/*
+ * This sets reasonable default values into all fields of all instances of the
+ * channles and drives, but only on the first call.  Subsequent calls have no
+ * effect (they don't wipe out anything).
+ *
+ * This routine is normally called at driver initialization time, but may also
+ * be called MUCH earlier during kernel "command-line" parameter processing.
+ * As such, we cannot depend on any other parts of the kernel (such as memory
+ * allocation) to be functioning yet.
+ *
+ * This is too bad, as otherwise we could dynamically allocate the ata_device
+ * structs as needed, rather than always consuming memory for the max possible
+ * number (MAX_HWIFS * MAX_DRIVES) of them.
+ */
+#define MAGIC_COOKIE 0x12345678
+static void __init init_global_data(void)
+{
+	unsigned int h;
+	static unsigned long magic_cookie = MAGIC_COOKIE;
+
+	if (magic_cookie != MAGIC_COOKIE)
+		return;		/* already initialized */
+	magic_cookie = 0;
+
+	/* Initialize all interface structures */
+	for (h = 0; h < MAX_HWIFS; ++h)
+		init_hwif_data(&ide_hwifs[h], h);
+
+	/* Add default hw interfaces */
+	ide_init_default_hwifs();
+}
+
+/*
+ * This gets called VERY EARLY during initialization, to handle kernel "command
+ * line" strings beginning with "hdx=" or "ide".It gets called even before the
+ * actual module gets initialized.
+ *
+ * Please look at Documentation/ide.txt to see the complete list of supported
+ * options.
+ */
+int __init ide_setup(char *s)
+{
+	int i, vals[3];
+	struct ata_channel *ch;
+	struct ata_device *drive;
+	unsigned int hw, unit;
+	const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
+	const char max_ch  = '0' + (MAX_HWIFS - 1);
+
+	if (!strncmp(s, "hd=", 3))	/* hd= is for hd.c driver and not us */
+		return 0;
+
+	if (strncmp(s,"ide",3) &&
+	    strncmp(s,"idebus",6) &&
+	    strncmp(s,"hd",2))		/* hdx= & hdxlun= */
+		return 0;
+
+	printk(KERN_INFO  "ide_setup: %s", s);
+	init_global_data();
+
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+	if (!strcmp(s, "ide=doubler")) {
+		extern int ide_doubler;
+
+		printk(KERN_INFO" : Enabled support for IDE doublers\n");
+		ide_doubler = 1;
+
+		return 1;
+	}
+#endif
+
+	if (!strcmp(s, "ide=nodma")) {
+		printk(KERN_INFO "ATA: Prevented DMA\n");
+		noautodma = 1;
+
+		return 1;
+	}
+
+#ifdef CONFIG_PCI
+	if (!strcmp(s, "ide=reverse")) {
+		ide_scan_direction = 1;
+		printk(" : Enabled support for IDE inverse scan order.\n");
+
+		return 1;
+	}
+#endif
+
+	/*
+	 * Look for drive options:  "hdx="
+	 */
+	if (!strncmp(s, "hd", 2) && s[2] >= 'a' && s[2] <= max_drive) {
+		const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
+				"serialize", "autotune", "noautotune",
+				"slow", "flash", "remap", "noremap", "scsi", NULL};
+		unit = s[2] - 'a';
+		hw   = unit / MAX_DRIVES;
+		unit = unit % MAX_DRIVES;
+		ch = &ide_hwifs[hw];
+		drive = &ch->drives[unit];
+		if (!strncmp(s + 4, "ide-", 4)) {
+			strncpy(drive->driver_req, s + 4, 9);
+			goto done;
+		}
+		/*
+		 * Look for last lun option:  "hdxlun="
+		 */
+		if (!strncmp(&s[3], "lun", 3)) {
+			if (match_parm(&s[6], NULL, vals, 1) != 1)
+				goto bad_option;
+			if (vals[0] >= 0 && vals[0] <= 7) {
+				drive->last_lun = vals[0];
+				drive->forced_lun = 1;
+			} else
+				printk(" -- BAD LAST LUN! Expected value from 0 to 7");
+			goto done;
+		}
+		switch (match_parm(&s[3], hd_words, vals, 3)) {
+			case -1: /* "none" */
+				drive->nobios = 1;  /* drop into "noprobe" */
+			case -2: /* "noprobe" */
+				drive->noprobe = 1;
+				goto done;
+			case -3: /* "nowerr" */
+				drive->bad_wstat = BAD_R_STAT;
+				ch->noprobe = 0;
+				goto done;
+			case -4: /* "cdrom" */
+				drive->present = 1;
+				drive->type = ATA_ROM;
+				ch->noprobe = 0;
+				goto done;
+			case -5: /* "serialize" */
+				printk(" -- USE \"ide%d=serialize\" INSTEAD", hw);
+				goto do_serialize;
+			case -6: /* "autotune" */
+				drive->autotune = 1;
+				goto done;
+			case -7: /* "noautotune" */
+				drive->autotune = 2;
+				goto done;
+			case -8: /* "slow" */
+				ch->slow = 1;
+				goto done;
+			case -9: /* "flash" */
+				drive->ata_flash = 1;
+				goto done;
+			case -10: /* "remap" */
+				drive->remap_0_to_1 = 1;
+				goto done;
+			case -11: /* "noremap" */
+				drive->remap_0_to_1 = 2;
+				goto done;
+			case -12: /* "scsi" */
+#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
+				drive->scsi = 1;
+				goto done;
+#else
+				drive->scsi = 0;
+				goto bad_option;
+#endif
+			case 3: /* cyl,head,sect */
+				drive->type	= ATA_DISK;
+				drive->cyl	= drive->bios_cyl  = vals[0];
+				drive->head	= drive->bios_head = vals[1];
+				drive->sect	= drive->bios_sect = vals[2];
+				drive->present	= 1;
+				drive->forced_geom = 1;
+				ch->noprobe = 0;
+				goto done;
+			default:
+				goto bad_option;
+		}
+	}
+
+	/*
+	 * Look for bus speed option:  "idebus="
+	 */
+	if (!strncmp(s, "idebus", 6)) {
+		if (match_parm(&s[6], NULL, vals, 1) != 1)
+			goto bad_option;
+		idebus_parameter = vals[0];
+		goto done;
+	}
+
+	/*
+	 * Look for interface options:  "idex="
+	 */
+	if (!strncmp(s, "ide", 3) && s[3] >= '0' && s[3] <= max_ch) {
+		/*
+		 * Be VERY CAREFUL changing this: note hardcoded indexes below
+		 * -8,-9,-10. -11 : are reserved for future idex calls to ease the hardcoding.
+		 */
+		const char *ide_words[] = {
+			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
+			"minus8", "minus9", "minus10", "minus11",
+			"qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
+		hw = s[3] - '0';
+		ch = &ide_hwifs[hw];
+
+		i = match_parm(&s[4], ide_words, vals, 3);
+
+		/*
+		 * Cryptic check to ensure chipset not already set for a channel:
+		 */
+		if (i > 0 || i <= -11) {			/* is parameter a chipset name? */
+			if (ch->chipset != ide_unknown)
+				goto bad_option;	/* chipset already specified */
+			if (i <= -11 && i != -18 && hw != 0)
+				goto bad_channel;		/* chipset drivers are for "ide0=" only */
+			if (i <= -11 && i != -18 && ide_hwifs[hw+1].chipset != ide_unknown)
+				goto bad_option;	/* chipset for 2nd port already specified */
+			printk("\n");
+		}
+
+		switch (i) {
+#ifdef CONFIG_BLK_DEV_PDC4030
+			case -18: /* "dc4030" */
+			{
+				extern void init_pdc4030(void);
+				init_pdc4030();
+				goto done;
+			}
+#endif
+#ifdef CONFIG_BLK_DEV_ALI14XX
+			case -17: /* "ali14xx" */
+			{
+				extern void init_ali14xx (void);
+				init_ali14xx();
+				goto done;
+			}
+#endif
+#ifdef CONFIG_BLK_DEV_UMC8672
+			case -16: /* "umc8672" */
+			{
+				extern void init_umc8672 (void);
+				init_umc8672();
+				goto done;
+			}
+#endif
+#ifdef CONFIG_BLK_DEV_DTC2278
+			case -15: /* "dtc2278" */
+			{
+				extern void init_dtc2278 (void);
+				init_dtc2278();
+				goto done;
+			}
+#endif
+#ifdef CONFIG_BLK_DEV_CMD640
+			case -14: /* "cmd640_vlb" */
+			{
+				extern int cmd640_vlb; /* flag for cmd640.c */
+				cmd640_vlb = 1;
+				goto done;
+			}
+#endif
+#ifdef CONFIG_BLK_DEV_HT6560B
+			case -13: /* "ht6560b" */
+			{
+				extern void init_ht6560b (void);
+				init_ht6560b();
+				goto done;
+			}
+#endif
+#if CONFIG_BLK_DEV_QD65XX
+			case -12: /* "qd65xx" */
+			{
+				extern void init_qd65xx (void);
+				init_qd65xx();
+				goto done;
+			}
+#endif
+			case -11: /* minus11 */
+			case -10: /* minus10 */
+			case -9: /* minus9 */
+			case -8: /* minus8 */
+				goto bad_option;
+			case -7: /* ata66 */
+#ifdef CONFIG_PCI
+				ch->udma_four = 1;
+				goto done;
+#else
+				ch->udma_four = 0;
+				goto bad_channel;
+#endif
+			case -6: /* dma */
+				ch->autodma = 1;
+				goto done;
+			case -5: /* reset */
+				ch->reset = 1;
+				goto done;
+			case -4: /* noautotune */
+				ch->drives[0].autotune = 2;
+				ch->drives[1].autotune = 2;
+				goto done;
+			case -3: /* autotune */
+				ch->drives[0].autotune = 1;
+				ch->drives[1].autotune = 1;
+				goto done;
+			case -2: /* "serialize" */
+			do_serialize:
+				{
+					struct ata_channel *mate;
+
+					mate = &ide_hwifs[hw ^ 1];
+					ch->serialized = 1;
+					mate->serialized = 1;
+				}
+				goto done;
+
+			case -1: /* "noprobe" */
+				ch->noprobe = 1;
+				goto done;
+
+			case 1:	/* base */
+				vals[1] = vals[0] + 0x206; /* default ctl */
+			case 2: /* base,ctl */
+				vals[2] = 0;	/* default irq = probe for it */
+			case 3: /* base,ctl,irq */
+				ch->hw.irq = vals[2];
+				ide_init_hwif_ports(&ch->hw, (ide_ioreg_t) vals[0], (ide_ioreg_t) vals[1], &ch->irq);
+				memcpy(ch->io_ports, ch->hw.io_ports, sizeof(ch->io_ports));
+				ch->irq = vals[2];
+				ch->noprobe  = 0;
+				ch->chipset  = ide_generic;
+				goto done;
+
+			case 0:
+				goto bad_option;
+			default:
+				printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n");
+				return 1;
+		}
+	}
+
+bad_option:
+	printk(" -- BAD OPTION\n");
+	return 1;
+
+bad_channel:
+	printk("-- NOT SUPPORTED ON ide%d", hw);
+
+done:
+	printk("\n");
+
+	return 1;
+}
+
+/****************************************************************************/
+
+/*
+ * This is in fact registering a device not a driver.
+ */
+int ide_register_subdriver(struct ata_device *drive, struct ata_operations *driver)
+{
+	unsigned long flags;
+
+	/* FIXME: The locking here doesn't make the slightest sense! */
+	spin_lock_irqsave(&ide_lock, flags);
+
+	if (!drive->present || drive->driver != NULL || drive->busy || drive->usage) {
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return 1;
+	}
+
+	/* FIXME: This will be pushed to the drivers! Thus allowing us to
+	 * save one parameter here and to separate this out.
+	 */
+	drive->driver = driver;
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+	/* Default autotune or requested autotune */
+	if (drive->autotune != 2) {
+		if (drive->channel->XXX_udma) {
+
+			/*
+			 * Force DMAing for the beginning of the check.  Some
+			 * chipsets appear to do interesting things, if not
+			 * checked and cleared.
+			 *
+			 *   PARANOIA!!!
+			 */
+
+			udma_enable(drive, 0, 0);
+			drive->channel->XXX_udma(drive);
+#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
+			udma_tcq_enable(drive, 1);
+#endif
+		}
+
+		/* Only CD-ROMs and tape drives support DSC overlap.  But only
+		 * if they are alone on a channel. */
+		if (drive->type == ATA_ROM || drive->type == ATA_TAPE) {
+			int single = 0;
+			int unit;
+
+			for (unit = 0; unit < MAX_DRIVES; ++unit)
+				if (drive->channel->drives[unit].present)
+					++single;
+
+			drive->dsc_overlap = (single == 1);
+		} else
+			drive->dsc_overlap = 0;
+
+	}
+	drive->revalidate = 1;
+	drive->suspend_reset = 0;
+
+	return 0;
+}
+
+/*
+ * This is in fact the default cleanup routine.
+ *
+ * FIXME: Check whatever we maybe don't call it twice!.
+ */
+int ide_unregister_subdriver(struct ata_device *drive)
+{
+	unsigned long flags;
+
+	save_flags(flags);		/* all CPUs */
+	cli();				/* all CPUs */
+
+#if 0
+	if (__MOD_IN_USE(ata_ops(drive)->owner)) {
+		restore_flags(flags);
+		return 1;
+	}
+#endif
+
+	if (drive->usage || drive->busy || !ata_ops(drive)) {
+		restore_flags(flags);	/* all CPUs */
+		return 1;
+	}
+
+#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
+	pnpide_init(0);
+#endif
+	drive->driver = NULL;
+
+	restore_flags(flags);		/* all CPUs */
+
+	return 0;
+}
+
+
+/*
+ * Register an ATA subdriver for a particular device type.
+ */
+int register_ata_driver(struct ata_operations *driver)
+{
+	unsigned long flags;
+	int index;
+	int count = 0;
+
+	spin_lock_irqsave(&ata_drivers_lock, flags);
+	driver->next = ata_drivers;
+	ata_drivers = driver;
+	spin_unlock_irqrestore(&ata_drivers_lock, flags);
+
+	for (index = 0; index < MAX_HWIFS; ++index)
+		count += subdriver_match(&ide_hwifs[index], driver);
+
+	return count;
+}
+
+EXPORT_SYMBOL(register_ata_driver);
+
+/*
+ * Unregister an ATA subdriver for a particular device type.
+ */
+void unregister_ata_driver(struct ata_operations *driver)
+{
+	struct ata_operations **tmp;
+	unsigned long flags;
+	int index;
+	int unit;
+
+	spin_lock_irqsave(&ata_drivers_lock, flags);
+	for (tmp = &ata_drivers; *tmp != NULL; tmp = &(*tmp)->next) {
+		if (*tmp == driver) {
+			*tmp = driver->next;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&ata_drivers_lock, flags);
+
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		struct ata_channel *ch = &ide_hwifs[index];
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			struct ata_device *drive = &ch->drives[unit];
+
+			if (drive->driver == driver)
+				(*ata_ops(drive)->cleanup)(drive);
+		}
+	}
+}
+
+EXPORT_SYMBOL(unregister_ata_driver);
+
+EXPORT_SYMBOL(ide_hwifs);
+EXPORT_SYMBOL(ide_lock);
+
+devfs_handle_t ide_devfs_handle;
+
+EXPORT_SYMBOL(ide_register_subdriver);
+EXPORT_SYMBOL(ide_unregister_subdriver);
+EXPORT_SYMBOL(ata_revalidate);
+EXPORT_SYMBOL(ide_register_hw);
+EXPORT_SYMBOL(ide_unregister);
+EXPORT_SYMBOL(get_info_ptr);
+
+/*
+ * Handle power handling related events ths system informs us about.
+ */
+static int ata_sys_notify(struct notifier_block *this, unsigned long event, void *x)
+{
+	int i;
+
+	switch (event) {
+		case SYS_HALT:
+		case SYS_POWER_OFF:
+		case SYS_RESTART:
+			break;
+		default:
+			return NOTIFY_DONE;
+	}
+
+	printk("flushing ide devices: ");
+
+	for (i = 0; i < MAX_HWIFS; i++) {
+		int unit;
+		struct ata_channel *ch = &ide_hwifs[i];
+
+		if (!ch->present)
+			continue;
+
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			struct ata_device *drive = &ch->drives[unit];
+
+			if (!drive->present)
+				continue;
+
+			/* set the drive to standby */
+			printk("%s ", drive->name);
+			if (ata_ops(drive)) {
+				if (event != SYS_RESTART)
+					if (ata_ops(drive)->standby && ata_ops(drive)->standby(drive))
+						continue;
+
+				if (ata_ops(drive)->cleanup)
+					ata_ops(drive)->cleanup(drive);
+			}
+		}
+	}
+	printk("\n");
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ata_notifier = {
+	ata_sys_notify,
+	NULL,
+	5
+};
+
+/*
+ * This is the global initialization entry point.
+ */
+static int __init ata_module_init(void)
+{
+	printk(KERN_INFO "ATA/ATAPI device driver v" VERSION "\n");
+
+	ide_devfs_handle = devfs_mk_dir(NULL, "ata", NULL);
+
+	/*
+	 * Because most of the ATA adapters represent the timings in unit of
+	 * bus clocks, and there is no known reliable way to detect the bus
+	 * clock frequency, we assume 50 MHz for non-PCI (VLB, EISA) and 33 MHz
+	 * for PCI based systems. Since assuming only hurts performance and not
+	 * stability, this is OK. The user can change this on the command line
+	 * by using the "idebus=XX" parameter. While the system_bus_speed
+	 * variable is in kHz units, we accept both MHz and kHz entry on the
+	 * command line for backward compatibility.
+	 */
+
+	system_bus_speed = 50000;
+
+	if (pci_present())
+	    system_bus_speed = 33333;
+
+	if (idebus_parameter >= 20 && idebus_parameter <= 80) {
+
+		system_bus_speed = idebus_parameter * 1000;
+
+		switch (system_bus_speed) {
+			case 33000: system_bus_speed = 33333; break;
+			case 37000: system_bus_speed = 37500; break;
+			case 41000: system_bus_speed = 41666; break;
+			case 66000: system_bus_speed = 66666; break;
+		}
+	}
+
+	if (idebus_parameter >= 20000 && idebus_parameter <= 80000)
+	    system_bus_speed = idebus_parameter;
+
+	printk(KERN_INFO "ATA: %s bus speed %d.%dMHz\n",
+		pci_present() ? "PCI" : "System", system_bus_speed / 1000, system_bus_speed / 100 % 10);
+
+	init_global_data();
+
+	initializing = 1;
+
+#ifdef CONFIG_PCI
+	/*
+	 * Register the host chip drivers.
+	 */
+# ifdef CONFIG_BLK_DEV_PIIX
+	init_piix();
+# endif
+# ifdef CONFIG_BLK_DEV_VIA82CXXX
+	init_via82cxxx();
+# endif
+# ifdef CONFIG_BLK_DEV_PDC202XX
+	init_pdc202xx();
+# endif
+# ifdef CONFIG_BLK_DEV_RZ1000
+	init_rz1000();
+# endif
+# ifdef CONFIG_BLK_DEV_SIS5513
+	init_sis5513();
+# endif
+# ifdef CONFIG_BLK_DEV_CMD64X
+	init_cmd64x();
+# endif
+# ifdef CONFIG_BLK_DEV_OPTI621
+	init_opti621();
+# endif
+# ifdef CONFIG_BLK_DEV_TRM290
+	init_trm290();
+# endif
+# ifdef CONFIG_BLK_DEV_NS87415
+	init_ns87415();
+# endif
+# ifdef CONFIG_BLK_DEV_AEC62XX
+	init_aec62xx();
+# endif
+# ifdef CONFIG_BLK_DEV_SL82C105
+	init_sl82c105();
+# endif
+# ifdef CONFIG_BLK_DEV_HPT34X
+	init_hpt34x();
+# endif
+# ifdef CONFIG_BLK_DEV_HPT366
+	init_hpt366();
+# endif
+# ifdef CONFIG_BLK_DEV_ALI15X3
+	init_ali15x3();
+# endif
+# ifdef CONFIG_BLK_DEV_CY82C693
+	init_cy82c693();
+# endif
+# ifdef CONFIG_BLK_DEV_CS5530
+	init_cs5530();
+# endif
+# ifdef CONFIG_BLK_DEV_AMD74XX
+	init_amd74xx();
+# endif
+# ifdef CONFIG_BLK_DEV_SVWKS
+	init_svwks();
+# endif
+# ifdef CONFIG_BLK_DEV_IT8172
+	init_it8172();
+# endif
+
+	init_ata_pci_misc();
+
+	/*
+	 * Detect and initialize "known" IDE host chip types.
+	 */
+	if (pci_present()) {
+# ifdef CONFIG_PCI
+		ide_scan_pcibus(ide_scan_direction);
+# else
+#  ifdef CONFIG_BLK_DEV_RZ1000
+		ide_probe_for_rz100x();
+#  endif
+# endif
+	}
+#endif
+
+#ifdef CONFIG_ETRAX_IDE
+	init_e100_ide();
+#endif
+#ifdef CONFIG_BLK_DEV_CMD640
+	ide_probe_for_cmd640x();
+#endif
+#ifdef CONFIG_BLK_DEV_PDC4030
+	ide_probe_for_pdc4030();
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+	pmac_ide_probe();
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_ICSIDE
+	icside_init();
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_RAPIDE
+	rapide_init();
+#endif
+#ifdef CONFIG_BLK_DEV_GAYLE
+	gayle_init();
+#endif
+#ifdef CONFIG_BLK_DEV_FALCON_IDE
+	falconide_init();
+#endif
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+	macide_init();
+#endif
+#ifdef CONFIG_BLK_DEV_Q40IDE
+	q40ide_init();
+#endif
+#ifdef CONFIG_BLK_DEV_BUDDHA
+	buddha_init();
+#endif
+#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
+	pnpide_init(1);
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+# if defined(__mc68000__) || defined(CONFIG_APUS)
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
+		// ide_get_lock(&irq_lock, NULL, NULL);/* for atari only */
+		disable_irq(ide_hwifs[0].irq);	/* disable_irq_nosync ?? */
+//		disable_irq_nosync(ide_hwifs[0].irq);
+	}
+# endif
+
+	ideprobe_init();
+
+# if defined(__mc68000__) || defined(CONFIG_APUS)
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
+		enable_irq(ide_hwifs[0].irq);
+		ide_release_lock(&irq_lock);/* for atari only */
+	}
+# endif
+#endif
+
+	/*
+	 * Initialize all device type driver modules.
+	 */
+#ifdef CONFIG_BLK_DEV_IDEDISK
+	idedisk_init();
+#endif
+#ifdef CONFIG_BLK_DEV_IDECD
+	ide_cdrom_init();
+#endif
+#ifdef CONFIG_BLK_DEV_IDETAPE
+	idetape_init();
+#endif
+#ifdef CONFIG_BLK_DEV_IDEFLOPPY
+	idefloppy_init();
+#endif
+#ifdef CONFIG_BLK_DEV_IDESCSI
+# ifdef CONFIG_SCSI
+	idescsi_init();
+# else
+   #error ATA SCSI emulation selected but no SCSI-subsystem in kernel
+# endif
+#endif
+
+	initializing = 0;
+
+	register_reboot_notifier(&ata_notifier);
+
+	return 0;
+}
+
+static char *options = NULL;
+
+static int __init init_ata(void)
+{
+
+	if (options != NULL && *options) {
+		char *next = options;
+
+		while ((options = next) != NULL) {
+			if ((next = strchr(options,' ')) != NULL)
+				*next++ = 0;
+			if (!ide_setup(options))
+				printk(KERN_ERR "Unknown option '%s'\n", options);
+		}
+	}
+	return ata_module_init();
+}
+
+static void __exit cleanup_ata(void)
+{
+	int h;
+
+	unregister_reboot_notifier(&ata_notifier);
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		ide_unregister(&ide_hwifs[h]);
+	}
+
+	devfs_unregister(ide_devfs_handle);
+}
+
+module_init(init_ata);
+module_exit(cleanup_ata);
+
+#ifndef MODULE
+
+/* command line option parser */
+__setup("", ide_setup);
+
+#endif
diff -Nru a/drivers/ide/pcihost.h b/drivers/ide/pcihost.h
--- a/drivers/ide/pcihost.h	Wed May 29 11:43:01 2002
+++ b/drivers/ide/pcihost.h	Wed May 29 11:43:01 2002
@@ -102,14 +102,16 @@
 
 /* Flags used to untangle quirk handling.
  */
-#define ATA_F_DMA	0x01
-#define ATA_F_NODMA	0x02	/* no DMA mode supported at all */
-#define ATA_F_NOADMA	0x04	/* DMA has to be enabled explicitely */
-#define ATA_F_FIXIRQ	0x08	/* fixed irq wiring */
-#define ATA_F_SER	0x10	/* serialize on first and second channel interrupts */
-#define ATA_F_IRQ	0x20	/* trust IRQ information from config */
-#define ATA_F_PHACK	0x40	/* apply PROMISE hacks */
-#define ATA_F_HPTHACK	0x80	/* apply HPT366 hacks */
+#define ATA_F_DMA	0x001
+#define ATA_F_NODMA	0x002	/* no DMA mode supported at all */
+#define ATA_F_NOADMA	0x004	/* DMA has to be enabled explicitely */
+#define ATA_F_FDMA	0x008	/* force autodma */
+#define ATA_F_FIXIRQ	0x010	/* fixed irq wiring */
+#define ATA_F_SER	0x020	/* serialize on first and second channel interrupts */
+#define ATA_F_IRQ	0x040	/* trust IRQ information from config */
+#define ATA_F_PHACK	0x080	/* apply PROMISE hacks */
+#define ATA_F_HPTHACK	0x100	/* apply HPT366 hacks */
+#define ATA_F_SIMPLEX	0x200	/* force treatment as simple device */
 
 
 struct ata_pci_device {
diff -Nru a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c
--- a/drivers/ide/pdc202xx.c	Wed May 29 11:43:03 2002
+++ b/drivers/ide/pdc202xx.c	Wed May 29 11:43:03 2002
@@ -1,6 +1,6 @@
 /**** vi:set ts=8 sts=8 sw=8:************************************************
  *
- *  linux/drivers/ide/pdc202xx.c	Version 0.30	Mar. 18, 2000
+ *  linux/drivers/ide/pdc202xx.c	Version 0.30	May. 28, 2002
  *
  *  Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
  *  May be copied or modified under the terms of the GNU General Public License
@@ -53,12 +53,6 @@
 #define PDC202XX_DEBUG_DRIVE_INFO		0
 #define PDC202XX_DECODE_REGISTER_INFO		0
 
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
 /* A Register */
 #define	SYNC_ERRDY_EN	0xC0
 
@@ -67,105 +61,75 @@
 #define	IORDY_EN	0x20	/* PIO: IOREADY */
 #define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
 
-#define	PA3		0x08	/* PIO"A" timing */
-#define	PA2		0x04	/* PIO"A" timing */
-#define	PA1		0x02	/* PIO"A" timing */
-#define	PA0		0x01	/* PIO"A" timing */
-
-/* B Register */
-
-#define	MB2		0x80	/* DMA"B" timing */
-#define	MB1		0x40	/* DMA"B" timing */
-#define	MB0		0x20	/* DMA"B" timing */
-
-#define	PB4		0x10	/* PIO_FORCE 1:0 */
-
-#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
-#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
-#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
-#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
-
-/* C Register */
-#define	IORDYp_NO_SPEED	0x4F
-#define	SPEED_DIS	0x0F
-
-#define	DMARQp		0x80
-#define	IORDYp		0x40
-#define	DMAR_EN		0x20
-#define	DMAW_EN		0x10
-
-#define	MC3		0x08	/* DMA"C" timing */
-#define	MC2		0x04	/* DMA"C" timing */
-#define	MC1		0x02	/* DMA"C" timing */
-#define	MC0		0x01	/* DMA"C" timing */
+
+#define PDC_CLOCK(high_16) IN_BYTE(high_16 + 0x11)
+#define UDMA_SPEED_FLAG(high_16) IN_BYTE(high_16 + 0x001f)
 
 #if PDC202XX_DECODE_REGISTER_INFO
 
-#define REG_A		0x01
-#define REG_B		0x02
-#define REG_C		0x04
-#define REG_D		0x08
+struct pdc_bit_messages {
+	u8 mask;
+	const char *msg;
+};
+
+static struct pdc_bit_messages pdc_reg_A[] = {
+	{ 0x80, "SYNC_IN" },
+	{ 0x40, "ERRDY_EN" },
+	{ 0x20, "IORDY_EN" },
+	{ 0x10, "PREFETCH_EN" },
+	/* PA3-PA0 - PIO "A" timing */
+	{ 0x08, "PA3" },
+	{ 0x04, "PA2" },
+	{ 0x02, "PA1" },
+	{ 0x01, "PA0" }
+};
+
+static struct pdc_bit_messages pdc_reg_B[] = {
+	/* MB2-MB0 - DMA "B" timing */
+	{ 0x80, "MB2" },
+	{ 0x40, "MB1" },
+	{ 0x20, "MB0" },
+	{ 0x10, "PIO_FORCED/PB4" },	/* PIO_FORCE 1:0 */
+	/* PB3-PB0 - PIO "B" timing */
+	{ 0x08, "PB3" },		/* PIO flow Control mode */
+	{ 0x04, "PB2" },		/* PIO 4 */
+	{ 0x02, "PB1" },		/* PIO 3 half */
+	{ 0x01, "PB0" }			/* PIO 3 other half */
+};
+
+static struct pdc_bit_messages pdc_reg_C[] = {
+	{ 0x80, "DMARQp" },
+	{ 0x40, "IORDYp" },
+	{ 0x20, "DMAR_EN" },
+	{ 0x10, "DMAW_EN" },
+	/* MC3-MC0 - DMA "C" timing */
+	{ 0x08, "MC3" },
+	{ 0x04, "MC2" },
+	{ 0x02, "MC1" },
+	{ 0x01, "MC0" }
+};
 
-static void decode_registers (byte registers, byte value)
+static void pdc_dump_bits(struct pdc_bit_messages *msgs, byte bits)
 {
-	byte	bit = 0, bit1 = 0, bit2 = 0;
+	int i;
 
-	switch(registers) {
-		case REG_A:
-			printk("A Register ");
-			if (value & 0x80) printk("SYNC_IN ");
-			if (value & 0x40) printk("ERRDY_EN ");
-			if (value & 0x20) printk("IORDY_EN ");
-			if (value & 0x10) printk("PREFETCH_EN ");
-			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
-			printk("PIO(A) = %d ", bit2);
-			break;
-		case REG_B:
-			printk("B Register ");
-			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
-			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
-			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
-			printk("DMA(B) = %d ", bit1 >> 5);
-			if (value & 0x10) printk("PIO_FORCED/PB4 ");
-			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
-			printk("PIO(B) = %d ", bit2);
-			break;
-		case REG_C:
-			printk("C Register ");
-			if (value & 0x80) printk("DMARQp ");
-			if (value & 0x40) printk("IORDYp ");
-			if (value & 0x20) printk("DMAR_EN ");
-			if (value & 0x10) printk("DMAW_EN ");
-
-			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
-			printk("DMA(C) = %d ", bit2);
-			break;
-		case REG_D:
-			printk("D Register ");
-			break;
-		default:
-			return;
-	}
-	printk("\n        %s ", (registers & REG_D) ? "DP" :
-				(registers & REG_C) ? "CP" :
-				(registers & REG_B) ? "BP" :
-				(registers & REG_A) ? "AP" : "ERROR");
-	for (bit=128;bit>0;bit/=2)
-		printk("%s", (value & bit) ? "1" : "0");
-	printk("\n");
-}
+	printk(KERN_DEBUG " { ");
 
+	for (i = 0; i < 8; i++, msgs++)
+		if (bits & msgs->mask)
+			printk(KERN_DEBUG "%s ", msgs->msg);
+
+	printk(KERN_DEBUG " }\n");
+}
 #endif /* PDC202XX_DECODE_REGISTER_INFO */
 
+
+static inline int init_high_16 (struct pci_dev *dev)
+{
+	return pci_resource_start(dev, 4);
+}
+
+
 int check_in_drive_lists(struct ata_device *drive)
 {
 	static const char *pdc_quirk_drives[] = {
@@ -219,16 +183,13 @@
 	struct pci_dev *dev = hwif->pci_dev;
 
 	unsigned int		drive_conf;
-	byte			drive_pci, AP, BP, CP, DP;
+	byte			drive_pci, AP, BP, CP;
 	byte			TA = 0, TB = 0, TC = 0;
 
-	switch (drive->dn) {
-		case 0: drive_pci = 0x60; break;
-		case 1: drive_pci = 0x64; break;
-		case 2: drive_pci = 0x68; break;
-		case 3: drive_pci = 0x6c; break;
-		default: return -1;
-	}
+	if (drive->dn > 3)
+		return -1;
+
+	drive_pci = 0x60 + (drive->dn << 2);
 
 	if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0))
 		return -1;
@@ -237,7 +198,6 @@
 	pci_read_config_byte(dev, (drive_pci), &AP);
 	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
 	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (speed >= XFER_SW_DMA_0) {
@@ -245,27 +205,17 @@
 			/* clear DMA modes of upper 842 bits of B Register */
 			/* clear PIO forced mode upper 1 bit of B Register */
 			pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0xF0);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
 			/* clear DMA modes of lower 8421 bits of C Register */
 			pci_write_config_byte(dev, (drive_pci)|0x02, CP & ~0x0F);
-			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
 		}
-	} else {
-#else
-	{
+	} else
 #endif /* CONFIG_BLK_DEV_IDEDMA */
+	{
 		if ((AP & 0x0F) || (BP & 0x07)) {
 			/* clear PIO modes of lower 8421 bits of A Register */
 			pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
-			pci_read_config_byte(dev, (drive_pci), &AP);
-
 			/* clear PIO modes of lower 421 bits of B Register */
 			pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-			pci_read_config_byte(dev, (drive_pci), &AP);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
 		}
 	}
 
@@ -277,17 +227,17 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		/* case XFER_UDMA_6: */
 		case XFER_UDMA_5:
-		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;	/* speed 8 == UDMA mode 4 */
-		case XFER_UDMA_3:	TB = 0x40; TC = 0x02; break;	/* speed 7 == UDMA mode 3 */
-		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;	/* speed 6 == UDMA mode 2 */
-		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;	/* speed 5 == UDMA mode 1 */
-		case XFER_UDMA_0:	TB = 0x60; TC = 0x03; break;	/* speed 4 == UDMA mode 0 */
-		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;	/* speed 4 == MDMA mode 2 */
-		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;	/* speed 3 == MDMA mode 1 */
-		case XFER_MW_DMA_0:	TB = 0x60; TC = 0x05; break;	/* speed 2 == MDMA mode 0 */
-		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;	/* speed 0 == SDMA mode 2 */
-		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;	/* speed 1 == SDMA mode 1 */
-		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;	/* speed 0 == SDMA mode 0 */
+		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_3:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_0:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
+		case XFER_MW_DMA_0:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
+		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
 		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
@@ -301,10 +251,9 @@
         if (speed >= XFER_SW_DMA_0) {
 		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
 		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
-	} else {
-#else
-	{
+	} else
 #endif /* CONFIG_BLK_DEV_IDEDMA */
+	{
 		pci_write_config_byte(dev, (drive_pci), AP|TA);
 		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
 	}
@@ -315,23 +264,28 @@
 	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
 	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
 
-	decode_registers(REG_A, AP);
-	decode_registers(REG_B, BP);
-	decode_registers(REG_C, CP);
-	decode_registers(REG_D, DP);
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
+	printk(KERN_DEBUG "AP(%x): PIO(A) = %d\n", AP, AP & 0x0f);
+	pdc_dump_bits(pdc_reg_A, AP);
+
+	printk(KERN_DEBUG "BP(%x): DMA(B) = %d PIO(B) = %d\n",
+			  BP, (BP & 0xe0) >> 5, BP & 0x0f);
+	pdc_dump_bits(pdc_reg_B, BP);
+
+	printk(KERN_DEBUG "CP(%x): DMA(C) = %d\n", CP, CP & 0x0f);
+	pdc_dump_bits(pdc_reg_C, CP);
+
+	printk(KERN_DEBUG "DP(%x)\n", DP);
+#endif
 
-	if (!drive->init_speed)
-		drive->init_speed = speed;
 	drive->current_speed = speed;
 
 #if PDC202XX_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d 0x%08x ",
-		drive->name, ide_xfer_verbose(speed),
+	printk("%s: %02x drive%d 0x%08x ",
+		drive->name, speed,
 		drive->dn, drive_conf);
 		pci_read_config_dword(dev, drive_pci, &drive_conf);
 	printk("0x%08x\n", drive_conf);
-#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+#endif
 
 	return ide_config_drive_speed(drive, speed);
 }
@@ -352,8 +306,7 @@
 	unsigned long indexreg	= (hwif->dma_base + 1);
 	unsigned long datareg	= (hwif->dma_base + 3);
 #else
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long high_16	= init_high_16(hwif->pci_dev);
 	unsigned long indexreg	= high_16 + (hwif->unit ? 0x09 : 0x01);
 	unsigned long datareg	= (indexreg + 2);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -447,8 +400,6 @@
 			;
 	}
 
-	if (!drive->init_speed)
-		drive->init_speed = speed;
 	drive->current_speed = speed;
 
 	return ide_config_drive_speed(drive, speed);
@@ -473,29 +424,24 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
+/* FIXME: split this for old & new chipsets (jumpbit) --bkz */
 static int config_chipset_for_dma(struct ata_device *drive, byte udma)
 {
 	struct hd_driveid *id	= drive->id;
 	struct ata_channel *hwif = drive->channel;
 	struct hd_driveid *mate_id = hwif->drives[!(drive->dn%2)].id;
 	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long high_16   = pci_resource_start(dev, 4);
+	unsigned long high_16   = init_high_16(dev);
 	unsigned long dma_base  = hwif->dma_base;
 	unsigned long indexreg	= dma_base + 1;
 	unsigned long datareg	= dma_base + 3;
-	byte iordy		= 0x13;
 	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
-	byte cable		= 0;
 	byte jumpbit		= 0;
 	unsigned int		drive_conf;
-	byte drive_pci = 0, mate_pci = 0;
-	byte			test1, test2, mode = -1;
-	byte			AP;
-	unsigned short		EP;
+	byte drive_pci = 0, AP, tmp, mode = -1;
 	byte CLKSPD		= 0;
 	/* primary - second bit, secondary - fourth bit */
 	byte mask		= hwif->unit ? 0x08 : 0x02;
-	unsigned short c_mask	= hwif->unit ? (1<<11) : (1<<10);
 	int map;
 
 	byte needs_80w = ((id->dma_ultra & 0x0008) ||
@@ -504,29 +450,19 @@
 			  (id->dma_ultra & 0x0040));
 
 	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-		case PCI_DEVICE_ID_PROMISE_20268:
-			OUT_BYTE(0x0b, indexreg);
-			cable = ((IN_BYTE(datareg) & 0x04));
-			jumpbit = 1;
-			break;
 		case PCI_DEVICE_ID_PROMISE_20267:
 		case PCI_DEVICE_ID_PROMISE_20265:
 		case PCI_DEVICE_ID_PROMISE_20262:
-			pci_read_config_word(dev, 0x50, &EP);
-			cable = (EP & c_mask);
+		case PCI_DEVICE_ID_PROMISE_20246:
 			jumpbit = 0;
 			break;
-		default:
-			cable = 1; jumpbit = 0;
+		default: /* chipsets newer then 20268 */
+			jumpbit = 1;
 			break;
 	}
 
 	if (!jumpbit)
-		CLKSPD = IN_BYTE(high_16 + 0x11);
+		CLKSPD = PDC_CLOCK(high_16);
 	/*
 	 * Set the control register to use the 66Mhz system
 	 * clock for UDMA 3/4 mode operation. If one drive on
@@ -541,7 +477,7 @@
 	 */
 	if (needs_80w) {
 		/* FIXME: this check is wrong for 20246 --bkz */
-		if (cable) {
+		if (!hwif->udma_four) {
 			printk(KERN_WARNING "%s: channel requires an 80-pin cable.\n", hwif->name);
 			printk(KERN_WARNING "%s: reduced to UDMA(33) mode.\n", drive->name);
 			if (!jumpbit)
@@ -563,37 +499,30 @@
 		}
 	}
 
-	if (jumpbit) {
-		if (drive->type != ATA_DISK)
-			return 0;
-		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
-			set_2regs(iordy, (IN_BYTE(datareg)|0x03));
-		}
-		goto jumpbit_is_set;
-	}
+	if (jumpbit)
+		goto chipset_is_set;
 
-	switch(drive->dn) {
-		case 0:	drive_pci = 0x60;
-		case 2:	drive_pci = 0x68;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, drive_pci, &test1);
-			if (!(test1 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, drive_pci, test1|SYNC_ERRDY_EN);
-			break;
-		case 1:	drive_pci = 0x64; mate_pci = 0x60;
-		case 3:	drive_pci = 0x6c; mate_pci = 0x68;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, mate_pci, &test1);
-			pci_read_config_byte(dev, drive_pci, &test2);
-			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, drive_pci, test2|SYNC_ERRDY_EN);
-			break;
-		default:
-			return 0;
+	if (drive->dn > 3)	/* FIXME: remove this --bkz */
+		return 0;
+
+	drive_pci = 0x60 + (drive->dn << 2);
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+		goto chipset_is_set;
+
+	/* FIXME: what if SYNC_ERRDY is enabled for slave
+		  and disabled for master? --bkz */
+	pci_read_config_byte(dev, drive_pci, &AP);
+	if (!(AP & SYNC_ERRDY_EN)) {
+		if (drive->dn == 0 || drive->dn == 2) {
+			/* enable SYNC_ERRDY for master */
+			pci_write_config_byte(dev, drive_pci, AP|SYNC_ERRDY_EN);
+		} else {
+			/* enable SYNC_ERRDY for slave if enabled for master */
+			pci_read_config_byte(dev, drive_pci - 4, &tmp);
+			if (tmp & SYNC_ERRDY_EN)
+				pci_write_config_byte(dev, drive_pci, AP|SYNC_ERRDY_EN);
+		}
 	}
 
 chipset_is_set:
@@ -601,14 +530,18 @@
 	if (drive->type != ATA_DISK)
 		return 0;
 
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	if (id->capability & 4)	/* IORDY_EN */
-		pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	if (drive->type == ATA_DISK)	/* PREFETCH_EN */
-		pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
-
-jumpbit_is_set:
+	if (jumpbit) {
+		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
+			set_2regs(0x13, (IN_BYTE(datareg)|0x03));
+		}
+	} else {
+		pci_read_config_byte(dev, drive_pci, &AP);
+		if (id->capability & 4)		/* IORDY_EN */
+			pci_write_config_byte(dev, drive_pci, AP|IORDY_EN);
+		pci_read_config_byte(dev, drive_pci, &AP);
+		if (drive->type == ATA_DISK)	/* PREFETCH_EN */
+			pci_write_config_byte(dev, drive_pci, AP|PREFETCH_EN);
+	}
 
 	if (udma) {
 		map = pdc202xx_ratemask(drive);
@@ -639,12 +572,9 @@
 
 	if (id && (id->capability & 1) && hwif->autodma) {
 		/* Consult the list of known "bad" drives */
-		if (udma_black_list(drive)) {
-			on = 0;
-			goto fast_ata_pio;
-		}
-		on = 0;
 		verbose = 0;
+		if (udma_black_list(drive))
+			goto no_dma_set;
 		if (id->field_valid & 4) {
 			if (id->dma_ultra & 0x007F) {
 				/* Force if Capable UltraDMA */
@@ -670,13 +600,8 @@
 			on = config_chipset_for_dma(drive, 0);
 			if (!on)
 				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
+		} else goto no_dma_set;
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		on = 0;
-		verbose = 0;
 no_dma_set:
 		config_chipset_for_pio(drive, 5);
 	}
@@ -688,24 +613,13 @@
 
 static int pdc202xx_udma_start(struct ata_device *drive, struct request *rq)
 {
-	u8 lba48hack = 0, clock = 0;
 	struct ata_channel *ch = drive->channel;
-	struct pci_dev *dev	= ch->pci_dev;
-	unsigned long high_16	= pci_resource_start(dev, 4);
-	unsigned long atapi_reg	= high_16 + (ch->unit ? 0x24 : 0x00);
+	unsigned long high_16 = init_high_16(ch->pci_dev);
+	unsigned long atapi_reg = high_16 + (ch->unit ? 0x24 : 0x00);
 
-	switch (dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			lba48hack = 1;
-			clock = IN_BYTE(high_16 + 0x11);
-		default:
-			break;
-	}
-
-	if (drive->addressing && lba48hack) {
+	if (drive->addressing) {
 		unsigned long word_count = 0;
+		u8 clock = PDC_CLOCK(high_16);
 
 		outb(clock|(ch->unit ? 0x08 : 0x02), high_16 + 0x11);
 		word_count = (rq->nr_sectors << 8);
@@ -725,28 +639,15 @@
 
 int pdc202xx_udma_stop(struct ata_device *drive)
 {
-	u8 lba48hack = 0, clock = 0;
 	struct ata_channel *ch = drive->channel;
-	struct pci_dev *dev	= ch->pci_dev;
-	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long high_16 = init_high_16(ch->pci_dev);
 	unsigned long atapi_reg	= high_16 + (ch->unit ? 0x24 : 0x00);
 	unsigned long dma_base = ch->dma_base;
-	u8 dma_stat;
-
-	switch (dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			lba48hack = 1;
-			/* FIXME: why do we need this here --bkz */
-			clock = IN_BYTE(high_16 + 0x11);
- 		default:
-			break;
-	}
+	u8 dma_stat, clock;
 
-	if (drive->addressing && lba48hack) {
+	if (drive->addressing) {
 		outl(0, atapi_reg);	/* zero out extra */
-		clock = IN_BYTE(high_16 + 0x11);
+		clock = PDC_CLOCK(high_16);
 		OUT_BYTE(clock & ~(ch->unit ? 0x08:0x02), high_16 + 0x11);
 	}
 
@@ -762,46 +663,10 @@
 static int pdc202xx_udma_irq_status(struct ata_device *drive)
 {
 	struct ata_channel *ch = drive->channel;
-	u8 dma_stat = 0;
-	u8 sc1d	= 0;
-	u8 newchip = 0;
-	u8 clock = 0;
-	struct pci_dev *dev = ch->pci_dev;
-	unsigned long high_16 = pci_resource_start(dev, 4);
-	unsigned long dma_base = ch->dma_base;
-
-	switch (dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-		case PCI_DEVICE_ID_PROMISE_20268:
-			newchip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			/* FIXME: why do we need this here --bkz */
-			clock = IN_BYTE(high_16 + 0x11);
-		default:
-			break;
-	}
+	u8 dma_stat;
 
-	dma_stat = IN_BYTE(dma_base + 2);
-	if (newchip)
-		return (dma_stat & 4) == 4;
+	dma_stat = IN_BYTE(ch->dma_base + 2);
 
-	sc1d = IN_BYTE(high_16 + 0x001d);
-	if (ch->unit) {
-		if ((sc1d & 0x50) == 0x50) goto somebody_else;
-		else if ((sc1d & 0x40) == 0x40)
-			return (dma_stat & 4) == 4;
-	} else {
-		if ((sc1d & 0x05) == 0x05) goto somebody_else;
-		else if ((sc1d & 0x04) == 0x04)
-			return (dma_stat & 4) == 4;
-	}
-somebody_else:
 	return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
 }
 
@@ -829,8 +694,8 @@
 
 void pdc202xx_reset(struct ata_device *drive)
 {
-	unsigned long high_16	= pci_resource_start(drive->channel->pci_dev, 4);
-	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
+	unsigned long high_16	= init_high_16(drive->channel->pci_dev);
+	byte udma_speed_flag	= UDMA_SPEED_FLAG(high_16);
 
 	set_reg_and_wait(udma_speed_flag | 0x10, high_16 + 0x001f, 100);
 	set_reg_and_wait(udma_speed_flag & ~0x10, high_16 + 0x001f, 2000);		/* 2 seconds ?! */
@@ -838,10 +703,11 @@
 		drive->channel->unit ? "Secondary" : "Primary");
 }
 
+/* FIXME: should be splited for old & new chipsets --bkz */
 static unsigned int __init pdc202xx_init_chipset(struct pci_dev *dev)
 {
-	unsigned long high_16	= pci_resource_start(dev, 4);
-	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
+	unsigned long high_16	= init_high_16(dev);
+	byte udma_speed_flag	= UDMA_SPEED_FLAG(high_16);
 	byte primary_mode	= IN_BYTE(high_16 + 0x001a);
 	byte secondary_mode	= IN_BYTE(high_16 + 0x001b);
 	byte newchip		= 0;
@@ -877,6 +743,8 @@
 			set_reg_and_wait(udma_speed_flag & ~0x10, high_16 + 0x001f, 2000);   /* 2 seconds ?! */
 			break;
 		default:
+		/* FIXME: only checked for 20246 - is this right?,
+			  if it is needed it should go to ide-pci --bkz */
 			if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
 				byte irq = 0, irq2 = 0;
 				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
@@ -904,7 +772,7 @@
 	if (!(udma_speed_flag & 1)) {
 		printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", dev->name, udma_speed_flag, (udma_speed_flag|1));
 		OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f);
-		printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA");
+		printk("%sCTIVE\n", (UDMA_SPEED_FLAG(high_16) & 1) ? "A" : "INA");
 	}
 #endif /* CONFIG_PDC202XX_BURST */
 
@@ -949,6 +817,15 @@
 		case PCI_DEVICE_ID_PROMISE_20265:
 		case PCI_DEVICE_ID_PROMISE_20262:
 			hwif->resetproc	= &pdc202xx_reset;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+			/* we need special functions for lba48 */
+			if (hwif->dma_base) {
+				hwif->udma_start = pdc202xx_udma_start;
+				hwif->udma_stop = pdc202xx_udma_stop;
+				hwif->udma_irq_status = pdc202xx_udma_irq_status;
+			}
+#endif
+		/* FIXME: check whether 20246 works with lba48 --bkz */
 		case PCI_DEVICE_ID_PROMISE_20246:
 			hwif->speedproc = &pdc202xx_tune_chipset;
 		default:
@@ -957,25 +834,19 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
-		hwif->udma_start = pdc202xx_udma_start;
-		hwif->udma_stop = pdc202xx_udma_stop;
-		hwif->udma_irq_status = pdc202xx_udma_irq_status;
 		hwif->udma_irq_lost = pdc202xx_bug;
 		hwif->udma_timeout = pdc202xx_bug;
 		hwif->XXX_udma = pdc202xx_dmaproc;
 		hwif->highmem = 1;
 		if (!noautodma)
 			hwif->autodma = 1;
-	} else {
+	} else
+#endif
+	{
 		hwif->drives[0].autotune = 1;
 		hwif->drives[1].autotune = 1;
 		hwif->autodma = 0;
 	}
-#else
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif
 }
 
 
@@ -1090,9 +961,8 @@
 {
 	unsigned int i;
 
-	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i)
 		ata_register_chipset(&chipsets[i]);
-	}
 
         return 0;
 }
diff -Nru a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c
--- a/drivers/ide/pdc4030.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/pdc4030.c	Wed May 29 11:43:02 2002
@@ -342,7 +342,7 @@
 	outb(0x14, IDE_SELECT_REG);
 	outb(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
 
-	ide_delay_50ms();
+	mdelay(50);
 
 	if (inb(IDE_ERROR_REG) == 'P' &&
 	    inb(IDE_NSECTOR_REG) == 'T' &&
diff -Nru a/drivers/ide/piix.c b/drivers/ide/piix.c
--- a/drivers/ide/piix.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/piix.c	Wed May 29 11:43:02 2002
@@ -351,8 +351,6 @@
 
 	piix_set_speed(drive->channel->pci_dev, drive->dn, &t, umul);
 
-	if (!drive->init_speed)	
-		drive->init_speed = speed;
 	drive->current_speed = speed;
 
 	return 0;
diff -Nru a/drivers/ide/probe.c b/drivers/ide/probe.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/probe.c	Wed May 29 11:43:01 2002
@@ -0,0 +1,1247 @@
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
+ *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
+ *
+ *  Mostly written by Mark Lord <mlord@pobox.com>
+ *                and Gadi Oxman <gadio@netvision.net.il>
+ *                and Andre Hedrick <andre@linux-ide.org>
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
+ *
+ */
+
+/*
+ * This is roughly the code related to device detection and
+ * device id handling.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+
+extern struct ata_device * get_info_ptr(kdev_t);
+
+
+/*
+ * This is called from the partition-table code in pt/msdos.c.
+ *
+ * It has two tasks:
+ *
+ * (I) to handle Ontrack DiskManager by offsetting everything by 63 sectors,
+ *  or to handle EZdrive by remapping sector 0 to sector 1.
+ *
+ * (II) to invent a translated geometry.
+ *
+ * Part (I) is suppressed if the user specifies the "noremap" option
+ * on the command line.
+ *
+ * Part (II) is suppressed if the user specifies an explicit geometry.
+ *
+ * The ptheads parameter is either 0 or tells about the number of
+ * heads shown by the end of the first nonempty partition.
+ * If this is either 16, 32, 64, 128, 240 or 255 we'll believe it.
+ *
+ * The xparm parameter has the following meaning:
+ *	 0 = convert to CHS with fewer than 1024 cyls
+ *	     using the same method as Ontrack DiskManager.
+ *	 1 = same as "0", plus offset everything by 63 sectors.
+ *	-1 = similar to "0", plus redirect sector 0 to sector 1.
+ *	 2 = convert to a CHS geometry with "ptheads" heads.
+ *
+ * Returns 0 if the translation was not possible, if the device was not
+ * an IDE disk drive, or if a geometry was "forced" on the commandline.
+ * Returns 1 if the geometry translation was successful.
+ */
+int ide_xlate_1024(kdev_t i_rdev, int xparm, int ptheads, const char *msg)
+{
+	struct ata_device *drive;
+	const char *msg1 = "";
+	int heads = 0;
+	int c, h, s;
+	int transl = 1;		/* try translation */
+	int ret = 0;
+
+	drive = get_info_ptr(i_rdev);
+	if (!drive)
+		return 0;
+
+	/* remap? */
+	if (drive->remap_0_to_1 != 2) {
+		if (xparm == 1) {		/* DM */
+			drive->sect0 = 63;
+			msg1 = " [remap +63]";
+			ret = 1;
+		} else if (xparm == -1) {	/* EZ-Drive */
+			if (drive->remap_0_to_1 == 0) {
+				drive->remap_0_to_1 = 1;
+				msg1 = " [remap 0->1]";
+				ret = 1;
+			}
+		}
+	}
+
+	/* There used to be code here that assigned drive->id->CHS
+	   to drive->CHS and that to drive->bios_CHS. However, some disks have
+	   id->C/H/S = 4092/16/63 but are larger than 2.1 GB.  In such cases
+	   that code was wrong.  Moreover, there seems to be no reason to do
+	   any of these things. */
+
+	/* translate? */
+	if (drive->forced_geom)
+		transl = 0;
+
+	/* does ptheads look reasonable? */
+	if (ptheads == 32 || ptheads == 64 || ptheads == 128 ||
+	    ptheads == 240 || ptheads == 255)
+		heads = ptheads;
+
+	if (xparm == 2) {
+		if (!heads ||
+		   (drive->bios_head >= heads && drive->bios_sect == 63))
+			transl = 0;
+	}
+	if (xparm == -1) {
+		if (drive->bios_head > 16)
+			transl = 0;     /* we already have a translation */
+	}
+
+	if (transl) {
+		static const u8 dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
+		const u8 *headp = dm_head_vals;
+		unsigned long total;
+
+		/*
+		 * If heads is nonzero: find a translation with this many heads
+		 * and S=63.  Otherwise: find out how OnTrack Disk Manager
+		 * would translate the disk.
+		 *
+		 * The specs say: take geometry as obtained from Identify,
+		 * compute total capacity C*H*S from that, and truncate to
+		 * 1024*255*63. Now take S=63, H the first in the sequence 4,
+		 * 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
+		 * [Please tell aeb@cwi.nl in case this computes a geometry
+		 * different from what OnTrack uses.]
+		 */
+
+		total = ata_capacity(drive);
+
+		s = 63;
+
+		if (heads) {
+			h = heads;
+			c = total / (63 * heads);
+		} else {
+			while (63 * headp[0] * 1024 < total && headp[1] != 0)
+				headp++;
+			h = headp[0];
+			c = total / (63 * headp[0]);
+		}
+
+		drive->bios_cyl = c;
+		drive->bios_head = h;
+		drive->bios_sect = s;
+		ret = 1;
+	}
+
+	drive->part[0].nr_sects = ata_capacity(drive);
+
+	if (ret)
+		printk("%s%s [%d/%d/%d]", msg, msg1,
+		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	return ret;
+}
+
+/*
+ * hd_driveid data come as little endian, it needs to be converted on big
+ * endian machines.
+ */
+void ata_fix_driveid(struct hd_driveid *id)
+{
+#ifndef __LITTLE_ENDIAN
+# ifdef __BIG_ENDIAN
+	int i;
+	u16 *stringcast;
+
+	id->config         = __le16_to_cpu(id->config);
+	id->cyls           = __le16_to_cpu(id->cyls);
+	id->reserved2      = __le16_to_cpu(id->reserved2);
+	id->heads          = __le16_to_cpu(id->heads);
+	id->track_bytes    = __le16_to_cpu(id->track_bytes);
+	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
+	id->sectors        = __le16_to_cpu(id->sectors);
+	id->vendor0        = __le16_to_cpu(id->vendor0);
+	id->vendor1        = __le16_to_cpu(id->vendor1);
+	id->vendor2        = __le16_to_cpu(id->vendor2);
+	stringcast = (u16 *)&id->serial_no[0];
+	for (i = 0; i < (20/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->buf_type       = __le16_to_cpu(id->buf_type);
+	id->buf_size       = __le16_to_cpu(id->buf_size);
+	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
+	stringcast = (u16 *)&id->fw_rev[0];
+	for (i = 0; i < (8/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	stringcast = (u16 *)&id->model[0];
+	for (i = 0; i < (40/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->dword_io       = __le16_to_cpu(id->dword_io);
+	id->reserved50     = __le16_to_cpu(id->reserved50);
+	id->field_valid    = __le16_to_cpu(id->field_valid);
+	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
+	id->cur_heads      = __le16_to_cpu(id->cur_heads);
+	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
+	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
+	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
+	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
+	id->dma_1word      = __le16_to_cpu(id->dma_1word);
+	id->dma_mword      = __le16_to_cpu(id->dma_mword);
+	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
+	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
+	id->eide_pio       = __le16_to_cpu(id->eide_pio);
+	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+	for (i = 0; i < 2; ++i)
+		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
+	for (i = 0; i < 4; ++i)
+		id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
+	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
+	for (i = 0; i < 4; ++i)
+		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
+	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
+	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
+	id->command_set_1  = __le16_to_cpu(id->command_set_1);
+	id->command_set_2  = __le16_to_cpu(id->command_set_2);
+	id->cfsse          = __le16_to_cpu(id->cfsse);
+	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
+	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
+	id->csf_default    = __le16_to_cpu(id->csf_default);
+	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
+	id->word89         = __le16_to_cpu(id->word89);
+	id->word90         = __le16_to_cpu(id->word90);
+	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
+	id->word92         = __le16_to_cpu(id->word92);
+	id->hw_config      = __le16_to_cpu(id->hw_config);
+	id->acoustic       = __le16_to_cpu(id->acoustic);
+	for (i = 0; i < 5; i++)
+		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
+	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+	for (i = 0; i < 22; i++)
+		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
+	id->last_lun       = __le16_to_cpu(id->last_lun);
+	id->word127        = __le16_to_cpu(id->word127);
+	id->dlf            = __le16_to_cpu(id->dlf);
+	id->csfo           = __le16_to_cpu(id->csfo);
+	for (i = 0; i < 26; i++)
+		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
+	id->word156        = __le16_to_cpu(id->word156);
+	for (i = 0; i < 3; i++)
+		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
+	id->cfa_power      = __le16_to_cpu(id->cfa_power);
+	for (i = 0; i < 14; i++)
+		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+	for (i = 0; i < 31; i++)
+		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+	for (i = 0; i < 48; i++)
+		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+	id->integrity_word  = __le16_to_cpu(id->integrity_word);
+# else
+#  error "Please fix <asm/byteorder.h>"
+# endif
+#endif
+}
+
+/*
+ *  All hosts that use the 80c ribbon must use this!
+ */
+byte eighty_ninty_three(struct ata_device *drive)
+{
+	return ((u8) ((drive->channel->udma_four) &&
+#ifndef CONFIG_IDEDMA_IVB
+		(drive->id->hw_config & 0x4000) &&
+#endif
+		(drive->id->hw_config & 0x6000)) ? 1 : 0);
+}
+
+/*
+ * Similar to ide_wait_stat(), except it never calls ide_error internally.
+ * This is a kludge to handle the new ide_config_drive_speed() function,
+ * and should not otherwise be used anywhere.  Eventually, the tuneproc's
+ * should be updated to return ide_startstop_t, in which case we can get
+ * rid of this abomination again.  :)   -ml
+ *
+ * It is gone..........
+ *
+ * const char *msg == consider adding for verbose errors.
+ */
+int ide_config_drive_speed(struct ata_device *drive, byte speed)
+{
+	struct ata_channel *hwif = drive->channel;
+	int i;
+	int error = 1;
+	u8 stat;
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(__CRIS__)
+	u8 unit = (drive->select.b.unit & 0x01);
+	outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
+#endif
+
+	/*
+	 * Don't use ide_wait_cmd here - it will attempt to set_geometry and
+	 * recalibrate, but for some reason these don't work at this point
+	 * (lost interrupt).
+	 */
+        /*
+         * Select the drive, and issue the SETFEATURES command
+         */
+	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
+	udelay(1);
+	SELECT_DRIVE(drive->channel, drive);
+	SELECT_MASK(drive->channel, drive, 0);
+	udelay(1);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
+	OUT_BYTE(speed, IDE_NSECTOR_REG);
+	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
+	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+	udelay(1);
+
+	/*
+	 * Wait for drive to become non-BUSY
+	 */
+	if ((stat = GET_STAT()) & BUSY_STAT) {
+		unsigned long flags, timeout;
+		__save_flags(flags);	/* local CPU only */
+		ide__sti();		/* local CPU only -- for jiffies */
+		timeout = jiffies + WAIT_CMD;
+		while ((stat = GET_STAT()) & BUSY_STAT) {
+			if (time_after(jiffies, timeout))
+				break;
+		}
+		__restore_flags(flags); /* local CPU only */
+	}
+
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
+			error = 0;
+			break;
+		}
+	}
+
+	SELECT_MASK(drive->channel, drive, 0);
+
+	enable_irq(hwif->irq);
+
+	if (error) {
+		ide_dump_status(drive, NULL, "set_drive_speed_status", stat);
+		return error;
+	}
+
+	drive->id->dma_ultra &= ~0xFF00;
+	drive->id->dma_mword &= ~0x0F00;
+	drive->id->dma_1word &= ~0x0F00;
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(__CRIS__)
+	if (speed > XFER_PIO_4) {
+		outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
+	} else {
+		outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
+	}
+#endif
+
+	switch(speed) {
+		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
+		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
+		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
+		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
+		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
+		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
+		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
+		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
+		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
+		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
+		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
+		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
+		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
+		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
+		default: break;
+	}
+	return error;
+}
+
+static inline void do_identify(struct ata_device *drive, u8 cmd)
+{
+	int bswap = 1;
+	struct hd_driveid *id;
+
+	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);	/* called with interrupts disabled! */
+	if (!id) {
+		printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
+		goto err_kmalloc;
+	}
+
+	/* Read 512 bytes of id info.
+	 *
+	 * Please note that it is well known that some *very* old drives are
+	 * able to provide only 256 of them, since this was the amount read by
+	 * DOS.
+	 *
+	 * However let's try to get away with this...
+	 */
+
+	ata_read(drive, id, SECTOR_WORDS);
+	ide__sti();	/* local CPU only */
+	ata_fix_driveid(id);
+
+	if (id->word156 == 0x4d42) {
+		printk("%s: drive->id->word156 == 0x%04x \n", drive->name, drive->id->word156);
+	}
+
+	if (!drive->forced_lun)
+		drive->last_lun = id->last_lun & 0x7;
+#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
+	/*
+	 * EATA SCSI controllers do a hardware ATA emulation:
+	 * Ignore them if there is a driver for them available.
+	 */
+	if ((id->model[0] == 'P' && id->model[1] == 'M')
+	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
+		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
+		goto err_misc;
+	}
+#endif
+
+	/*
+	 *  WIN_IDENTIFY returns little-endian info,
+	 *  WIN_PIDENTIFY *usually* returns little-endian info.
+	 */
+	if (cmd == WIN_PIDENTIFY) {
+		if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
+		 || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
+		 || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
+			bswap ^= 1;	/* Vertos drives may still be weird */
+	}
+	ide_fixstring (id->model,     sizeof(id->model),     bswap);
+	ide_fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
+	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
+
+	if (strstr(id->model, "E X A B Y T E N E S T"))
+		goto err_misc;
+
+	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
+	printk("%s: %s, ", drive->name, id->model);
+	drive->present = 1;
+
+	/*
+	 * Check for an ATAPI device:
+	 */
+	if (cmd == WIN_PIDENTIFY) {
+		u8 type = (id->config >> 8) & 0x1f;
+		printk("ATAPI ");
+#ifdef CONFIG_BLK_DEV_PDC4030
+		if (drive->channel->unit == 1 && drive->channel->chipset == ide_pdc4030) {
+			printk(" -- not supported on 2nd Promise port\n");
+			goto err_misc;
+		}
+#endif
+		switch (type) {
+			case ATA_FLOPPY:
+				if (!strstr(id->model, "CD-ROM")) {
+					if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP"))
+						printk("cdrom or floppy?, assuming ");
+					if (drive->type != ATA_ROM) {
+						printk ("FLOPPY");
+						break;
+					}
+				}
+				type = ATA_ROM;	/* Early cdrom models used zero */
+			case ATA_ROM:
+				drive->removable = 1;
+#ifdef CONFIG_PPC
+				/* kludge for Apple PowerBook internal zip */
+				if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) {
+					printk ("FLOPPY");
+					type = ATA_FLOPPY;
+					break;
+				}
+#endif
+				printk ("CD/DVD-ROM");
+				break;
+			case ATA_TAPE:
+				printk ("TAPE");
+				break;
+			case ATA_MOD:
+				printk ("OPTICAL");
+				drive->removable = 1;
+				break;
+			default:
+				printk("UNKNOWN (type %d)", type);
+				break;
+		}
+		printk (" drive\n");
+		drive->type = type;
+		return;
+	}
+
+	/*
+	 * Not an ATAPI device: looks like a "regular" hard disk:
+	 */
+	if (id->config & (1<<7))
+		drive->removable = 1;
+
+	/*
+	 * FIXME: This is just plain ugly or plain unnecessary.
+	 *
+	 * Prevent long system lockup probing later for non-existant slave
+	 * drive if the hwif is actually a flash memory card of some variety:
+	 */
+
+	if (drive_is_flashcard(drive)) {
+		struct ata_device *mate = &drive->channel->drives[1 ^ drive->select.b.unit];
+		if (!mate->ata_flash) {
+			mate->present = 0;
+			mate->noprobe = 1;
+		}
+	}
+	drive->type = ATA_DISK;
+	printk("ATA DISK drive\n");
+
+	/* Initialize our quirk list. */
+	if (drive->channel->quirkproc)
+		drive->quirk_list = drive->channel->quirkproc(drive);
+
+	/* Initialize queue depth settings */
+	drive->queue_depth = 1;
+#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEPTH
+	drive->queue_depth = CONFIG_BLK_DEV_IDE_TCQ_DEPTH;
+#else
+	drive->queue_depth = drive->id->queue_depth + 1;
+#endif
+	if (drive->queue_depth < 1 || drive->queue_depth > IDE_MAX_TAG)
+		drive->queue_depth = IDE_MAX_TAG;
+
+	return;
+
+err_misc:
+	kfree(id);
+err_kmalloc:
+	drive->present = 0;
+
+	return;
+}
+
+/*
+ * Sends an ATA(PI) IDENTIFY request to a drive and wait for a response.  It
+ * also monitor irqs while this is happening, in hope of automatically
+ * determining which one is being used by the interface.
+ *
+ * Returns:	0  device was identified
+ *		1  device timed-out (no response to identify request)
+ *		2  device aborted the command (refused to identify itself)
+ */
+static int identify(struct ata_device *drive, u8 cmd)
+{
+	int rc;
+	int autoprobe = 0;
+	unsigned long cookie = 0;
+	ide_ioreg_t hd_status;
+	unsigned long timeout;
+	u8 s;
+	u8 a;
+
+
+	if (IDE_CONTROL_REG && !drive->channel->irq) {
+		autoprobe = 1;
+		cookie = probe_irq_on();
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
+	}
+
+	rc = 1;
+	if (IDE_CONTROL_REG) {
+		/* take a deep breath */
+		mdelay(50);
+		a = IN_BYTE(IDE_ALTSTATUS_REG);
+		s = IN_BYTE(IDE_STATUS_REG);
+		if ((a ^ s) & ~INDEX_STAT) {
+			printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
+			hd_status = IDE_STATUS_REG;	/* ancient Seagate drives, broken interfaces */
+		} else {
+			hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
+		}
+	} else {
+		mdelay(50);
+		hd_status = IDE_STATUS_REG;
+	}
+
+	/* set features register for atapi identify command to be sure of reply */
+	if ((cmd == WIN_PIDENTIFY))
+		OUT_BYTE(0,IDE_FEATURE_REG);	/* disable dma & overlap */
+
+#if CONFIG_BLK_DEV_PDC4030
+	if (drive->channel->chipset == ide_pdc4030) {
+		/* DC4030 hosted drives need their own identify... */
+		extern int pdc4030_identify(struct ata_device *);
+
+		if (pdc4030_identify(drive))
+			goto out;
+	} else
+#endif
+		OUT_BYTE(cmd,IDE_COMMAND_REG);		/* ask drive for ID */
+	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
+	timeout += jiffies;
+	do {
+		if (time_after(jiffies, timeout))
+			goto out;	/* drive timed-out */
+		mdelay(50);		/* give drive a breather */
+	} while (IN_BYTE(hd_status) & BUSY_STAT);
+
+	mdelay(50);		/* wait for IRQ and DRQ_STAT */
+
+	if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
+		unsigned long flags;
+		__save_flags(flags);	/* local CPU only */
+		__cli();		/* local CPU only; some systems need this */
+		do_identify(drive, cmd); /* drive returned ID */
+		rc = 0;			/* drive responded with ID */
+		(void) GET_STAT();	/* clear drive IRQ */
+		__restore_flags(flags);	/* local CPU only */
+	} else
+		rc = 2;			/* drive refused ID */
+
+out:
+	if (autoprobe) {
+		int irq;
+		OUT_BYTE(drive->ctl | 0x02, IDE_CONTROL_REG);	/* mask device irq */
+		GET_STAT();			/* clear drive IRQ */
+		udelay(5);
+		irq = probe_irq_off(cookie);
+		if (!drive->channel->irq) {
+			if (irq > 0)
+				drive->channel->irq = irq;
+			else	/* Mmmm.. multiple IRQs.. don't know which was ours */
+				printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
+		}
+	}
+
+	return rc;
+}
+
+
+/*
+ * This has the difficult job of finding a drive if it exists, without getting
+ * hung up if it doesn't exist, without trampling on ethernet cards, and
+ * without leaving any IRQs dangling to haunt us later.
+ *
+ * If a drive is "known" to exist (from CMOS or kernel parameters), but does
+ * not respond right away, the probe will "hang in there" for the maximum wait
+ * time (about 30 seconds), otherwise it will exit much more quickly.
+ *
+ * Returns:	0  device was identified
+ *		1  device timed-out (no response to identify request)
+ *		2  device aborted the command (refused to identify itself)
+ *		3  bad status from device (possible for ATAPI drives)
+ *		4  probe was not attempted because failure was obvious
+ */
+static int do_probe(struct ata_device *drive, u8 cmd)
+{
+	int rc;
+	struct ata_channel *hwif = drive->channel;
+
+	if (drive->present) {	/* avoid waiting for inappropriate probes */
+		if ((drive->type != ATA_DISK) && (cmd == WIN_IDENTIFY))
+			return 4;
+	}
+#ifdef DEBUG
+	printk("probing for %s: present=%d, type=%d, probetype=%s\n",
+		drive->name, drive->present, drive->type,
+		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
+#endif
+	mdelay(50);	/* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */
+	SELECT_DRIVE(hwif,drive);
+	mdelay(50);
+	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
+		if (drive->select.b.unit != 0) {
+			SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
+			mdelay(50);		/* allow BUSY_STAT to assert & clear */
+		}
+		return 3;    /* no i/f present: mmm.. this should be a 4 -ml */
+	}
+
+	if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) || drive->present || cmd == WIN_PIDENTIFY)
+	{
+		if ((rc = identify(drive,cmd)))   /* send cmd and wait */
+			rc = identify(drive,cmd); /* failed: try again */
+		if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {
+			unsigned long timeout;
+			printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT());
+			mdelay(50);
+			OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+			mdelay(50);
+			OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
+			timeout = jiffies;
+			while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE))
+				mdelay(50);
+			rc = identify(drive, cmd);
+		}
+		if (rc == 1)
+			printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT());
+		(void) GET_STAT();		/* ensure drive irq is clear */
+	} else
+		rc = 3;				/* not present or maybe ATAPI */
+
+	if (drive->select.b.unit != 0) {
+		SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
+		mdelay(50);
+		GET_STAT();		/* ensure drive irq is clear */
+	}
+
+	return rc;
+}
+
+/*
+ * Probe for drivers on a channel.
+ *
+ * This routine only knows how to look for drive units 0 and 1 on an interface,
+ * so any setting of MAX_DRIVES > 2 won't work here.
+ */
+static void channel_probe(struct ata_channel *ch)
+{
+	unsigned int i;
+	unsigned long flags;
+	int error;
+
+	if (ch->noprobe)
+		return;
+
+	ch->straight8 = 0;
+
+	__save_flags(flags);	/* local CPU only */
+	__sti();		/* local CPU only; needed for jiffies and irq probing */
+
+	/*
+	 * Check for the presence of a channel by probing for drives on it.
+	 */
+	for (i = 0; i < MAX_DRIVES; ++i) {
+		struct ata_device *drive = &ch->drives[i];
+
+		if (drive->noprobe)	/* don't look for this one */
+			continue;
+
+		if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
+			do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
+		}
+
+		/* Special handling of EXABYTE controller cards. */
+		if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T")) {
+			unsigned long timeout;
+
+			printk("%s: enabling %s -- ", drive->channel->name, drive->id->model);
+			SELECT_DRIVE(drive->channel, drive);
+			mdelay(50);
+			OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
+			timeout = jiffies + WAIT_WORSTCASE;
+			do {
+				if (time_after(jiffies, timeout)) {
+					printk("failed (timeout)\n");
+					return;
+				}
+				mdelay(50);
+			} while (GET_STAT() & BUSY_STAT);
+			mdelay(50);
+			if (!OK_STAT(GET_STAT(), 0, BAD_STAT))
+				printk("failed (status = 0x%02x)\n", GET_STAT());
+			else
+				printk("success\n");
+
+			if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
+				do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
+		}
+		}
+
+		if (!drive->present)
+			continue;	/* drive not found */
+
+		if (!drive->id) {	/* identification failed? */
+			if (drive->type == ATA_DISK)
+				printk ("%s: pre-ATA drive, CHS=%d/%d/%d\n",
+						drive->name, drive->cyl, drive->head, drive->sect);
+			else if (drive->type == ATA_ROM)
+				printk("%s: ATAPI cdrom (?)\n", drive->name);
+			else
+				drive->present = 0;	/* nuke it */
+		}
+
+		/* drive found, there is a channel it is attached too. */
+		if (drive->present)
+			ch->present = 1;
+	}
+
+	if (!ch->present)
+		goto not_found;
+
+	error = 0;
+
+	if (((unsigned long)ch->io_ports[IDE_DATA_OFFSET] | 7) ==
+			((unsigned long)ch->io_ports[IDE_STATUS_OFFSET])) {
+		error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 8, ch->name);
+		ch->straight8 = 1;
+	} else {
+		for (i = 0; i < 8; i++)
+			error += !request_region(ch->io_ports[i], 1, ch->name);
+	}
+	if (ch->io_ports[IDE_CONTROL_OFFSET])
+		error += !request_region(ch->io_ports[IDE_CONTROL_OFFSET], 1, ch->name);
+#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
+	if (ch->io_ports[IDE_IRQ_OFFSET])
+		error += !request_region(ch->io_ports[IDE_IRQ_OFFSET], 1, ch->name);
+#endif
+
+	/* Some neccessary register area was already used. Skip this device.
+	 */
+
+	if (
+#if CONFIG_BLK_DEV_PDC4030
+			(ch->chipset != ide_pdc4030 || ch->unit == 0) &&
+#endif
+			error) {
+
+		/* FIXME: We should be dealing properly with partial IO region
+		 * allocations here.
+		 */
+
+		ch->present = 0;
+		printk("%s: error: ports already in use!\n", ch->name);
+	}
+
+	if (!ch->present)
+		goto not_found;
+
+	/* Register this hardware interface within the global device tree.
+	 */
+	sprintf(ch->dev.bus_id, "%04x", ch->io_ports[IDE_DATA_OFFSET]);
+	sprintf(ch->dev.name, "ide");
+	ch->dev.driver_data = ch;
+#ifdef CONFIG_PCI
+	if (ch->pci_dev)
+		ch->dev.parent = &ch->pci_dev->dev;
+	else
+#endif
+		ch->dev.parent = NULL; /* Would like to do = &device_legacy */
+
+	device_register(&ch->dev);
+
+	if (ch->reset && ch->io_ports[IDE_CONTROL_OFFSET]) {
+		unsigned long timeout = jiffies + WAIT_WORSTCASE;
+		u8 stat;
+
+		printk("%s: reset\n", ch->name);
+		OUT_BYTE(12, ch->io_ports[IDE_CONTROL_OFFSET]);
+		udelay(10);
+		OUT_BYTE(8, ch->io_ports[IDE_CONTROL_OFFSET]);
+		do {
+			mdelay(50);
+			stat = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]);
+		} while ((stat & BUSY_STAT) && time_before(jiffies, timeout));
+	}
+
+	__restore_flags(flags);	/* local CPU only */
+
+	/*
+	 * Now setup the PIO transfer modes of the drives on this channel.
+	 */
+	for (i = 0; i < MAX_DRIVES; ++i) {
+		struct ata_device *drive = &ch->drives[i];
+
+		if (drive->present && (drive->autotune == 1)) {
+			if (drive->channel->tuneproc)
+				drive->channel->tuneproc(drive, 255);	/* auto-tune PIO mode */
+		}
+	}
+
+	return;
+
+not_found:
+	__restore_flags(flags);
+}
+
+/*
+ * This routine sets up the irq for an ide interface, and creates a new hwgroup
+ * for the irq/channel if none was previously assigned.
+ *
+ * Much of the code is for correctly detecting/handling irq sharing and irq
+ * serialization situations.  This is somewhat complex because it handles
+ * static as well as dynamic (PCMCIA) IDE interfaces.
+ *
+ * The SA_INTERRUPT in sa_flags means ata_irq_request() is always entered with
+ * interrupts completely disabled.  This can be bad for interrupt latency, but
+ * anything else has led to problems on some machines.  We re-enable interrupts
+ * as much as we can safely do in most places.
+ */
+static int init_irq(struct ata_channel *ch)
+{
+	unsigned long flags;
+	int i;
+	spinlock_t *lock;
+	spinlock_t *new_lock;
+	unsigned long *active;
+	unsigned long *new_active;
+	struct ata_channel *match = NULL;
+
+	/* Spare allocation before sleep. */
+	new_lock = kmalloc(sizeof(*lock), GFP_KERNEL);
+	new_active = kmalloc(sizeof(*active), GFP_KERNEL);
+	*new_active = 0L;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	ch->lock = NULL;
+
+#if MAX_HWIFS > 1
+	/*
+	 * Group up with any other channels that share our irq(s).
+	 */
+	for (i = 0; i < MAX_HWIFS; ++i) {
+		struct ata_channel *h = &ide_hwifs[i];
+
+		/* scan only initialized channels */
+		if (!h->lock)
+			continue;
+
+		if (ch->irq != h->irq)
+		        continue;
+
+		ch->sharing_irq = h->sharing_irq = 1;
+
+		if (ch->chipset != ide_pci || h->chipset != ide_pci ||
+		     ch->serialized || h->serialized) {
+			if (match && match->lock && match->lock != h->lock)
+				printk("%s: potential irq problem with %s and %s\n", ch->name, h->name, match->name);
+			/* don't undo a prior perfect match */
+			if (!match || match->irq != ch->irq)
+				match = h;
+		}
+	}
+#endif
+	/*
+	 * If we are still without a lock group, then form a new one
+	 */
+	if (!match) {
+		lock = new_lock;
+		active = new_active;
+		if (!lock) {
+			spin_unlock_irqrestore(&ide_lock, flags);
+
+			return 1;
+		}
+		spin_lock_init(lock);
+	} else {
+		lock = match->lock;
+		active = match->active;
+		if(new_lock)
+			kfree(new_lock);
+	}
+
+	/*
+	 * Allocate the irq, if not already obtained for another channel
+	 */
+	if (!match || match->irq != ch->irq) {
+#ifdef CONFIG_IDEPCI_SHARE_IRQ
+		int sa = IDE_CHIPSET_IS_PCI(ch->chipset) ? SA_SHIRQ : SA_INTERRUPT;
+#else
+		int sa = IDE_CHIPSET_IS_PCI(ch->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
+#endif
+
+		if (ch->io_ports[IDE_CONTROL_OFFSET])
+			OUT_BYTE(0x08, ch->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */
+
+		if (request_irq(ch->irq, &ata_irq_request, sa, ch->name, ch)) {
+			if (!match) {
+				kfree(lock);
+				kfree(active);
+			}
+
+			spin_unlock_irqrestore(&ide_lock, flags);
+
+			return 1;
+		}
+	}
+
+	/*
+	 * Everything is okay. Tag us as member of this lock group.
+	 */
+	ch->lock = lock;
+	ch->active = active;
+
+	init_timer(&ch->timer);
+	ch->timer.function = &ide_timer_expiry;
+	ch->timer.data = (unsigned long) ch;
+
+	for (i = 0; i < MAX_DRIVES; ++i) {
+		struct ata_device *drive = &ch->drives[i];
+		request_queue_t *q;
+		int max_sectors = 255;
+
+		if (!drive->present)
+			continue;
+
+		if (!ch->drive)
+			ch->drive = drive;
+
+		/*
+		 * Init the per device request queue
+		 */
+
+		q = &drive->queue;
+		q->queuedata = drive->channel;
+		blk_init_queue(q, do_ide_request, drive->channel->lock);
+		blk_queue_segment_boundary(q, 0xffff);
+
+		/* ATA can do up to 128K per request, pdc4030 needs smaller limit */
+#ifdef CONFIG_BLK_DEV_PDC4030
+		if (drive->channel->chipset == ide_pdc4030)
+			max_sectors = 127;
+#endif
+		blk_queue_max_sectors(q, max_sectors);
+
+		/* IDE DMA can do PRD_ENTRIES number of segments. */
+		blk_queue_max_hw_segments(q, PRD_ENTRIES);
+
+		/* FIXME: This is a driver limit and could be eliminated. */
+		blk_queue_max_phys_segments(q, PRD_ENTRIES);
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+#if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
+	printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", ch->name,
+		ch->io_ports[IDE_DATA_OFFSET],
+		ch->io_ports[IDE_DATA_OFFSET]+7,
+		ch->io_ports[IDE_CONTROL_OFFSET], ch->irq);
+#elif defined(__sparc__)
+	printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %s", ch->name,
+		ch->io_ports[IDE_DATA_OFFSET],
+		ch->io_ports[IDE_DATA_OFFSET]+7,
+		ch->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(ch->irq));
+#else
+	printk("%s at %p on irq 0x%08x", ch->name,
+		ch->io_ports[IDE_DATA_OFFSET], ch->irq);
+#endif
+	if (match)
+		printk(" (%sed with %s)",
+			ch->sharing_irq ? "shar" : "serializ", match->name);
+	printk("\n");
+
+	return 0;
+}
+
+/*
+ * Returns the queue which corresponds to a given device.
+ *
+ * FIXME: this should take struct block_device * as argument in future.
+ */
+static request_queue_t *ata_get_queue(kdev_t dev)
+{
+	struct ata_channel *ch = (struct ata_channel *)blk_dev[major(dev)].data;
+
+	/* FIXME: ALLERT: This discriminates between master and slave! */
+	return &ch->drives[DEVICE_NR(dev) & 1].queue;
+}
+
+/* Number of minor numbers we consume par channel. */
+#define ATA_MINORS	(MAX_DRIVES * (1 << PARTN_BITS))
+
+static void channel_init(struct ata_channel *ch)
+{
+	struct gendisk *gd;
+	unsigned int unit;
+	extern devfs_handle_t ide_devfs_handle;
+
+	if (!ch->present)
+		return;
+
+	/* we set it back to 1 if all is ok below */
+	ch->present = 0;
+
+	if (!ch->irq) {
+		if (!(ch->irq = ide_default_irq(ch->io_ports[IDE_DATA_OFFSET]))) {
+			printk("%s: DISABLED, NO IRQ\n", ch->name);
+
+			return;
+		}
+	}
+#ifdef CONFIG_BLK_DEV_HD
+	if (ch->irq == HD_IRQ && ch->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
+		printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", ch->name);
+
+		return;
+	}
+#endif
+
+	if (devfs_register_blkdev(ch->major, ch->name, ide_fops)) {
+		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", ch->name, ch->major);
+
+		return;
+	}
+
+	if (init_irq(ch)) {
+		int irq = ch->irq;
+		/*
+		 * It failed to initialise. Find the default IRQ for
+		 * this port and try that.
+		 */
+		if (!(ch->irq = ide_default_irq(ch->io_ports[IDE_DATA_OFFSET]))) {
+			printk(KERN_INFO "%s: disabled; unable to get IRQ %d.\n", ch->name, irq);
+			(void) unregister_blkdev (ch->major, ch->name);
+
+			return;
+		}
+		if (init_irq(ch)) {
+			printk(KERN_INFO "%s: probed IRQ %d and default IRQ %d failed.\n",
+				ch->name, irq, ch->irq);
+			(void) unregister_blkdev(ch->major, ch->name);
+
+			return;
+		}
+		printk(KERN_INFO "%s: probed IRQ %d failed, using default.\n", ch->name, ch->irq);
+	}
+
+	/* Initialize partition and global device data.
+	 */
+
+	gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+	if (!gd)
+		goto err_kmalloc_gd;
+
+	gd->sizes = kmalloc(ATA_MINORS * sizeof(int), GFP_KERNEL);
+	if (!gd->sizes)
+		goto err_kmalloc_gd_sizes;
+
+	gd->part = kmalloc(ATA_MINORS * sizeof(struct hd_struct), GFP_KERNEL);
+	if (!gd->part)
+		goto err_kmalloc_gd_part;
+	memset(gd->part, 0, ATA_MINORS * sizeof(struct hd_struct));
+
+	gd->de_arr = kmalloc (sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL);
+	if (!gd->de_arr)
+		goto err_kmalloc_gd_de_arr;
+	memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES);
+
+	gd->flags = kmalloc (sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL);
+	if (!gd->flags)
+		goto err_kmalloc_gd_flags;
+	memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES);
+
+	for (unit = 0; unit < MAX_DRIVES; ++unit)
+		ch->drives[unit].part = &gd->part[unit << PARTN_BITS];
+
+	gd->major	= ch->major;		/* our major device number */
+	gd->major_name	= IDE_MAJOR_NAME;	/* treated special in genhd.c */
+	gd->minor_shift	= PARTN_BITS;		/* num bits for partitions */
+	gd->nr_real	= MAX_DRIVES;		/* current num real drives */
+	gd->next	= NULL;			/* linked list of major devs */
+	gd->fops        = ide_fops;             /* file operations */
+
+	gd->de_arr	= kmalloc(sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL);
+	if (gd->de_arr)
+		memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES);
+	else
+	    goto err_kmalloc_gd_de_arr;
+
+	gd->flags	= kmalloc(sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL);
+	if (gd->flags)
+		memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES);
+	else
+	    goto err_kmalloc_gd_flags;
+
+	ch->gd = gd;
+	add_gendisk(gd);
+
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		char name[80];
+
+		ch->drives[unit].dn = ((ch->unit ? 2 : 0) + unit);
+		sprintf(name, "host%d/bus%d/target%d/lun%d",
+			ch->index, ch->unit, unit, ch->drives[unit].lun);
+		if (ch->drives[unit].present)
+			ch->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
+	}
+
+	blk_dev[ch->major].data = ch;
+	blk_dev[ch->major].queue = ata_get_queue;
+
+	/* All went well, flag this channel entry as valid again. */
+	ch->present = 1;
+
+	return;
+
+err_kmalloc_gd_flags:
+	kfree(gd->de_arr);
+err_kmalloc_gd_de_arr:
+	kfree(gd->part);
+err_kmalloc_gd_part:
+	kfree(gd->sizes);
+err_kmalloc_gd_sizes:
+	kfree(gd);
+err_kmalloc_gd:
+	printk(KERN_CRIT "(%s) Out of memory\n", __FUNCTION__);
+}
+
+/*
+ * FIXME: consider moving this to main.c, since this is the only place where
+ * it's used.
+ *
+ * Probe only for drives on channes which are not already present.
+ */
+int ideprobe_init(void)
+{
+	unsigned int i;
+	int probe[MAX_HWIFS];
+
+	for (i = 0; i < MAX_HWIFS; ++i)
+		probe[i] = !ide_hwifs[i].present;
+
+	/*
+	 * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
+	 */
+	for (i = 0; i < MAX_HWIFS; ++i) {
+		if (!probe[i])
+			continue;
+		channel_probe(&ide_hwifs[i]);
+	}
+	for (i = 0; i < MAX_HWIFS; ++i) {
+		if (!probe[i])
+			continue;
+		channel_init(&ide_hwifs[i]);
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(ata_fix_driveid);
+EXPORT_SYMBOL(eighty_ninty_three);
+EXPORT_SYMBOL(ide_config_drive_speed);
diff -Nru a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c
--- a/drivers/ide/q40ide.c	Wed May 29 11:43:03 2002
+++ b/drivers/ide/q40ide.c	Wed May 29 11:43:03 2002
@@ -82,10 +82,10 @@
     for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
 	hw_regs_t hw;
 
-	ide_setup_ports(&hw,(ide_ioreg_t) pcide_bases[i], (int *)pcide_offsets, 
-			pcide_bases[i]+0x206, 
+	ide_setup_ports(&hw,(ide_ioreg_t) pcide_bases[i], (int *)pcide_offsets,
+			pcide_bases[i] + 0x206,
 			0, NULL, q40ide_default_irq(pcide_bases[i]));
-	ide_register_hw(&hw, NULL);
+	ide_register_hw(&hw);
     }
 }
 
diff -Nru a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
--- a/drivers/ide/qd65xx.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/qd65xx.c	Wed May 29 11:43:02 2002
@@ -21,6 +21,7 @@
  * Samuel Thibault <samuel.thibault@fnac.net>
  */
 
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -84,7 +85,7 @@
 
 static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
 
-static void qd_write_reg (byte content, byte reg)
+static void qd_write_reg(byte content, byte reg)
 {
 	unsigned long flags;
 
@@ -94,7 +95,7 @@
 	restore_flags(flags);	/* all CPUs */
 }
 
-byte __init qd_read_reg (byte reg)
+byte __init qd_read_reg(byte reg)
 {
 	unsigned long flags;
 	byte read;
@@ -114,7 +115,7 @@
 
 static void qd_select(struct ata_device *drive)
 {
-	byte index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) |
+	byte index = ((	(QD_TIMREG(drive)) & 0x80 ) >> 7) |
 			(QD_TIMREG(drive) & 0x02);
 
 	if (timings[index] != QD_TIMING(drive))
@@ -150,10 +151,10 @@
  * idem for qd6580
  */
 
-static byte qd6580_compute_timing (int active_time, int recovery_time)
+static byte qd6580_compute_timing(int active_time, int recovery_time)
 {
-	byte active_cycle   = 17-IDE_IN(active_time   * system_bus_speed / 1000000 + 1, 2, 17);
-	byte recovery_cycle = 15-IDE_IN(recovery_time * system_bus_speed / 1000000 + 1, 2, 15);
+	byte active_cycle   = 17 - IDE_IN(active_time   * system_bus_speed / 1000000 + 1, 2, 17);
+	byte recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_speed / 1000000 + 1, 2, 15);
 
 	return((recovery_cycle<<4) | active_cycle);
 }
@@ -176,8 +177,8 @@
 	ide_fixstring(model,40,1); /* byte-swap */
 
 	for (p = qd65xx_timing ; p->offset != -1 ; p++) {
-		if (!strncmp(p->model, model+p->offset,4)) {
-			printk(KERN_DEBUG "%s: listed !\n",drive->name);
+		if (!strncmp(p->model, model+p->offset, 4)) {
+			printk(KERN_DEBUG "%s: listed !\n", drive->name);
 			*active_time = p->active;
 			*recovery_time = p->recovery;
 			return 1;
@@ -218,7 +219,7 @@
 	} else
 		hwif->selectproc = &qd_select;
 
-	printk(KERN_DEBUG "%s: %#x\n",drive->name,timing);
+	printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
 }
 
 /*
@@ -230,17 +231,16 @@
 	int active_time   = 175;
 	int recovery_time = 415; /* worst case values from the dos driver */
 
-	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)
+	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)
 		&& drive->id->tPIO && (drive->id->field_valid & 0x02)
 		&& drive->id->eide_pio >= 240) {
 
-		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
-				drive->id->tPIO);
+		printk(KERN_INFO "%s: PIO mode%d\n", drive->name, drive->id->tPIO);
 		active_time = 110;
 		recovery_time = drive->id->eide_pio - 120;
 	}
 
-	qd_set_timing(drive,qd6500_compute_timing(drive->channel, active_time,recovery_time));
+	qd_set_timing(drive, qd6500_compute_timing(drive->channel, active_time, recovery_time));
 }
 
 /*
@@ -254,7 +254,7 @@
 	int active_time   = 175;
 	int recovery_time = 415; /* worst case values from the dos driver */
 
-	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)) {
+	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
 
 		if (pio == 255)
 			pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
@@ -268,14 +268,14 @@
 			case 3:
 				if (t->cycle >= 110) {
 					active_time = 86;
-					recovery_time = t->cycle-102;
+					recovery_time = t->cycle - 102;
 				} else
 					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
 				break;
 			case 4:
 				if (t->cycle >= 69) {
 					active_time = 70;
-					recovery_time = t->cycle-61;
+					recovery_time = t->cycle - 61;
 				} else
 					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
 				break;
@@ -292,11 +292,11 @@
 	}
 
 	if (!drive->channel->unit && drive->type != ATA_DISK) {
-		qd_write_reg(0x5f,QD_CONTROL_PORT);
-		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name, drive->channel->name);
+		qd_write_reg(0x5f, QD_CONTROL_PORT);
+		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n", drive->name, drive->channel->name);
 	}
 
-	qd_set_timing(drive,qd6580_compute_timing(active_time,recovery_time));
+	qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
 }
 
 /*
@@ -314,9 +314,9 @@
 	save_flags(flags);	/* all CPUs */
 	cli();			/* all CPUs */
 	savereg = inb_p(port);
-	outb_p(QD_TESTVAL,port);	/* safe value */
+	outb_p(QD_TESTVAL, port);	/* safe value */
 	readreg = inb_p(port);
-	outb(savereg,port);
+	outb(savereg, port);
 	restore_flags(flags);	/* all CPUs */
 
 	if (savereg == QD_TESTVAL) {
@@ -330,109 +330,121 @@
 }
 
 /*
- * probe:
+ * qd_setup:
+ *
+ * called to setup an ata channel : adjusts attributes & links for tuning
+ */
+
+void __init qd_setup(int unit, int base, int config, unsigned int data0, unsigned int data1, void (*tuneproc) (struct ata_device *, byte pio))
+{
+	struct ata_channel *hwif = &ide_hwifs[unit];
+
+	hwif->chipset = ide_qd65xx;
+	hwif->unit = unit;
+	hwif->select_data = base;
+	hwif->config_data = config;
+	hwif->drives[0].drive_data = data0;
+	hwif->drives[1].drive_data = data1;
+	hwif->io_32bit = 1;
+	hwif->tuneproc = tuneproc;
+}
+
+/*
+ * qd_unsetup:
+ *
+ * called to unsetup an ata channel : back to default values, unlinks tuning
+ */
+void __init qd_unsetup(int unit) {
+	struct ata_channel *hwif = &ide_hwifs[unit];
+	byte config = hwif->config_data;
+	int base = hwif->select_data;
+	void *tuneproc = (void *) hwif->tuneproc;
+
+	if (!(hwif->chipset == ide_qd65xx)) return;
+
+	printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
+
+	hwif->selectproc = NULL;
+	hwif->tuneproc = NULL;
+
+	if (tuneproc == (void *) qd6500_tune_drive) {
+		// will do it for both
+		qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+	} else if (tuneproc == (void *) qd6580_tune_drive) {
+		if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
+			qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+			qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
+		} else {
+			qd_write_reg(unit?QD6580_DEF_DATA2:QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+		}
+	} else {
+		printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n");
+		printk(KERN_WARNING "keeping settings !\n");
+	}
+}
+
+/*
+ * qd_probe:
  *
  * looks at the specified baseport, and if qd found, registers & initialises it
  * return 1 if another qd may be probed
  */
 
-int __init probe (int base)
+int __init qd_probe(int base)
 {
 	byte config;
-	byte index;
+	int unit;
 
 	config = qd_read_reg(QD_CONFIG_PORT);
 
 	if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) return 1;
 
-	index = ! (config & QD_CONFIG_IDE_BASEPORT);
+	unit = ! (config & QD_CONFIG_IDE_BASEPORT);
 
 	if ((config & 0xf0) == QD_CONFIG_QD6500) {
-		struct ata_channel *hwif = &ide_hwifs[index];
-
 		if (qd_testreg(base)) return 1;		/* bad register */
 
-			/* qd6500 found */
+		/* qd6500 found */
+
+		printk(KERN_NOTICE "%s: qd6500 at %#x\n", ide_hwifs[unit].name, base);
+		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n", config, QD_ID3);
 
-		printk(KERN_NOTICE "%s: qd6500 at %#x\n",
-			ide_hwifs[index].name, base);
-		
-		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
-			config, QD_ID3);
-		
 		if (config & QD_CONFIG_DISABLED) {
 			printk(KERN_WARNING "qd6500 is disabled !\n");
 			return 1;
 		}
 
-		hwif->chipset = ide_qd65xx;
-		hwif->select_data = base;
-		hwif->config_data = config;
-		hwif->drives[0].drive_data =
-		hwif->drives[1].drive_data = QD6500_DEF_DATA;
-		hwif->io_32bit = 1;
-		hwif->tuneproc = &qd6500_tune_drive;
+		qd_setup(unit, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA, &qd6500_tune_drive);
 		return 1;
 	}
 
 	if (((config & 0xf0) == QD_CONFIG_QD6580_A) || ((config & 0xf0) == QD_CONFIG_QD6580_B)) {
-
 		byte control;
 
 		if (qd_testreg(base) || qd_testreg(base+0x02)) return 1;
 			/* bad registers */
 
-			/* qd6580 found */
+		/* qd6580 found */
 
 		control = qd_read_reg(QD_CONTROL_PORT);
 
 		printk(KERN_NOTICE "qd6580 at %#x\n", base);
-		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
-			config, control, QD_ID3);
+		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n", config, control, QD_ID3);
 
 		if (control & QD_CONTR_SEC_DISABLED) {
-			struct ata_channel *hwif = &ide_hwifs[index];
-
 			/* secondary disabled */
-			printk(KERN_INFO "%s: qd6580: single IDE board\n",
-					ide_hwifs[index].name);
-
-			hwif->chipset = ide_qd65xx;
-			hwif->select_data = base;
-			hwif->config_data = config | (control <<8);
-			hwif->drives[0].drive_data =
-			hwif->drives[1].drive_data = QD6580_DEF_DATA;
-			hwif->io_32bit = 1;
-			hwif->tuneproc = &qd6580_tune_drive;
-
-			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+			printk(KERN_INFO "%s: qd6580: single IDE board\n", ide_hwifs[unit].name);
+			qd_setup(unit, base, config | (control << 8), QD6580_DEF_DATA, QD6580_DEF_DATA2, &qd6580_tune_drive);
+			qd_write_reg(QD_DEF_CONTR, QD_CONTROL_PORT);
 
 			return 1;
 		} else {
-			int i;
-
 			/* secondary enabled */
-			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
-					ide_hwifs[0].name,ide_hwifs[1].name);
-
-			for (i = 0; i < 2; i++) {
-				int j;
-
-				ide_hwifs[i].chipset = ide_qd65xx;
-				ide_hwifs[i].unit = i;
-
-				ide_hwifs[i].select_data = base;
-				ide_hwifs[i].config_data = config | (control <<8);
-				ide_hwifs[i].tuneproc = &qd6580_tune_drive;
-				ide_hwifs[i].io_32bit = 1;
-
-				for (j = 0; j < 2; j++) {
-					ide_hwifs[i].drives[j].drive_data =
-					       i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
-				}
-			}
+			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n", ide_hwifs[0].name, ide_hwifs[1].name);
 
-			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+			qd_setup(ATA_PRIMARY, base, config | (control << 8), QD6580_DEF_DATA, QD6580_DEF_DATA, &qd6580_tune_drive);
+			qd_setup(ATA_SECONDARY, base, config | (control << 8), QD6580_DEF_DATA2, QD6580_DEF_DATA2, &qd6580_tune_drive);
+			qd_write_reg(QD_DEF_CONTR, QD_CONTROL_PORT);
 
 			return 0; /* no other qd65xx possible */
 		}
@@ -441,13 +453,36 @@
 	return 1;
 }
 
+#ifndef MODULE
 /*
  * init_qd65xx:
  *
- * called at the very beginning of initialization ; should just probe and link
+ * called by ide.c when parsing command line
  */
 
-void __init init_qd65xx (void)
+void __init init_qd65xx(void)
+{
+	if (qd_probe(0x30)) qd_probe(0xb0);
+}
+
+#else
+
+MODULE_AUTHOR("Samuel Thibault");
+MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
+MODULE_LICENSE("GPL");
+
+int __init qd65xx_mod_init(void)
+{
+	if (qd_probe(0x30)) qd_probe(0xb0);
+	if (ide_hwifs[0].chipset != ide_qd65xx && ide_hwifs[1].chipset != ide_qd65xx) return -ENODEV;
+	return 0;
+}
+module_init(qd65xx_mod_init);
+
+void __init qd65xx_mod_exit(void)
 {
-	if (probe(0x30)) probe(0xb0);
+	qd_unsetup(ATA_PRIMARY);
+	qd_unsetup(ATA_SECONDARY);
 }
+module_exit(qd65xx_mod_exit);
+#endif
diff -Nru a/drivers/ide/rapide.c b/drivers/ide/rapide.c
--- a/drivers/ide/rapide.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/rapide.c	Wed May 29 11:43:02 2002
@@ -41,7 +41,7 @@
 	hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
 	hw.irq = ec->irq;
 
-	return ide_register_hw(&hw, NULL);
+	return ide_register_hw(&hw);
 }
 
 int __init rapide_init(void)
diff -Nru a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
--- a/drivers/ide/serverworks.c	Wed May 29 11:43:03 2002
+++ b/drivers/ide/serverworks.c	Wed May 29 11:43:03 2002
@@ -98,7 +98,7 @@
 #undef DISPLAY_SVWKS_TIMINGS
 #undef SVWKS_DEBUG_DRIVE_INFO
 
-static u8 svwks_revision = 0;
+static u8 svwks_revision;
 
 #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
@@ -230,13 +230,12 @@
 				((reg40&0x005D0000)==0x005D0000)?"0":"?");
 	return p-buffer;	 /* => must be less than 4k! */
 }
-#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
+static byte svwks_proc;
 
-byte svwks_proc = 0;
+#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-extern char *ide_xfer_verbose (byte xfer_rate);
+#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
 
 static struct pci_dev *isa_dev;
 
@@ -262,7 +261,6 @@
 
 static int svwks_tune_chipset(struct ata_device *drive, byte speed)
 {
-	static u8 udma_modes[]	= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
 	static u8 dma_modes[]	= { 0x77, 0x21, 0x20 };
 	static u8 pio_modes[]	= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
 
@@ -271,26 +269,23 @@
 	byte unit		= (drive->select.b.unit & 0x01);
 	byte csb5		= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
 
-	byte drive_pci		= 0x00;
-	byte drive_pci2		= 0x00;
-	byte drive_pci3		= hwif->unit ? 0x57 : 0x56;
-
-	byte ultra_enable	= 0x00;
-	byte ultra_timing	= 0x00;
-	byte dma_timing		= 0x00;
-	byte pio_timing		= 0x00;
-	unsigned short csb5_pio	= 0x00;
+	byte drive_pci, drive_pci2;
+	byte drive_pci3	= hwif->unit ? 0x57 : 0x56;
+
+	byte ultra_enable, ultra_timing, dma_timing, pio_timing;
+	unsigned short csb5_pio;
 
 	byte pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
 
         switch (drive->dn) {
-		case 0: drive_pci = 0x41; drive_pci2 = 0x45; break;
-		case 1: drive_pci = 0x40; drive_pci2 = 0x44; break;
-		case 2: drive_pci = 0x43; drive_pci2 = 0x47; break;
-		case 3: drive_pci = 0x42; drive_pci2 = 0x46; break;
+		case 0: drive_pci = 0x41; break;
+		case 1: drive_pci = 0x40; break;
+		case 2: drive_pci = 0x43; break;
+		case 3: drive_pci = 0x42; break;
 		default:
 			return -1;
 	}
+	drive_pci2 = drive_pci + 4;
 
 	pci_read_config_byte(dev, drive_pci, &pio_timing);
 	pci_read_config_byte(dev, drive_pci2, &dma_timing);
@@ -337,7 +332,7 @@
 			pio_timing   |= pio_modes[pio];
 			csb5_pio     |= (pio << (4*drive->dn));
 			dma_timing   |= dma_modes[2];
-			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
+			ultra_timing |= ((speed - XFER_UDMA_0) << (4*unit));
 			ultra_enable |= (0x01 << drive->dn);
 #endif
 		default:
@@ -350,8 +345,8 @@
 #endif
 
 #if SVWKS_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* SVWKS_DEBUG_DRIVE_INFO */
+	printk("%s: %02x drive%d\n", drive->name, speed, drive->dn);
+#endif
 
 	pci_write_config_byte(dev, drive_pci, pio_timing);
 	if (csb5)
@@ -362,8 +357,6 @@
 	pci_write_config_byte(dev, drive_pci3, ultra_timing);
 	pci_write_config_byte(dev, 0x54, ultra_enable);
 #endif
-	if (!drive->init_speed)
-		drive->init_speed = speed;
 	drive->current_speed = speed;
 
 	return ide_config_drive_speed(drive, speed);
@@ -684,7 +677,8 @@
 		init_chipset: svwks_init_chipset,
 		ata66_check: svwks_ata66_check,
 		init_channel: ide_init_svwks,
-		bootable: ON_BOARD
+		bootable: ON_BOARD,
+		flags: ATA_F_SIMPLEX
 	},
 };
 
diff -Nru a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
--- a/drivers/ide/sis5513.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/sis5513.c	Wed May 29 11:43:02 2002
@@ -403,11 +403,11 @@
 
 	return p-buffer;
 }
-#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
-
 
 byte sis_proc = 0;
-extern char *ide_xfer_verbose (byte xfer_rate);
+
+#endif
+
 
 static int sis5513_ratemask(struct ata_device *drive)
 {
diff -Nru a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
--- a/drivers/ide/sl82c105.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/sl82c105.c	Wed May 29 11:43:02 2002
@@ -29,8 +29,6 @@
 #include "ata-timing.h"
 #include "pcihost.h"
 
-extern char *ide_xfer_verbose (byte xfer_rate);
-
 /*
  * SL82C105 PCI config register 0x40 bits.
  */
@@ -100,8 +98,9 @@
 		pci_read_config_word(dev, reg, &drv_ctrl);
 
 		if (report) {
-			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
-			       ide_xfer_verbose(xfer_mode), t->cycle, drv_ctrl);
+			printk("%s: selected %02x (%dns) (%04X)\n",
+					drive->name, xfer_mode,
+					t->cycle, drv_ctrl);
 		}
 	}
 }
diff -Nru a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
--- a/drivers/ide/via82cxxx.c	Wed May 29 11:43:02 2002
+++ b/drivers/ide/via82cxxx.c	Wed May 29 11:43:02 2002
@@ -332,8 +332,6 @@
 
 	via_set_speed(drive->channel->pci_dev, drive->dn, &t);
 
-	if (!drive->init_speed)
-		drive->init_speed = speed;
 	drive->current_speed = speed;
 
 	return 0;
diff -Nru a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
--- a/drivers/ieee1394/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/ieee1394/Makefile	Wed May 29 11:43:03 2002
@@ -2,8 +2,6 @@
 # Makefile for the Linux IEEE 1394 implementation
 #
 
-O_TARGET := ieee1394drv.o
-
 export-objs := ieee1394_core.o ohci1394.o cmp.o
 
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
diff -Nru a/drivers/input/Makefile b/drivers/input/Makefile
--- a/drivers/input/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/input/Makefile	Wed May 29 11:43:03 2002
@@ -2,10 +2,6 @@
 # Makefile for the input core drivers.
 #
 
-# The target object and module list name.
-
-O_TARGET	:= inputdrv.o
-
 # Objects that export symbols.
 
 mod-subdirs	:= joystick
diff -Nru a/drivers/input/gameport/Makefile b/drivers/input/gameport/Makefile
--- a/drivers/input/gameport/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/input/gameport/Makefile	Wed May 29 11:43:01 2002
@@ -2,10 +2,6 @@
 # Makefile for the gameport drivers.
 #
 
-# The target object and module list name.
-
-O_TARGET	:= gamedrv.o
-
 # Objects that export symbols.
 
 export-objs	:= gameport.o
diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
--- a/drivers/input/serio/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/input/serio/Makefile	Wed May 29 11:43:01 2002
@@ -2,10 +2,6 @@
 # Makefile for the input core drivers.
 #
 
-# The target object and module list name.
-
-O_TARGET	:= seriodrv.o
-
 # Objects that export symbols.
 
 export-objs	:= serio.o
diff -Nru a/drivers/isdn/Makefile b/drivers/isdn/Makefile
--- a/drivers/isdn/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/isdn/Makefile	Wed May 29 11:43:03 2002
@@ -1,9 +1,5 @@
 # Makefile for the kernel ISDN subsystem and device drivers.
 
-# The target object and module list name.
-
-O_TARGET	:= vmlinux-obj.o
-
 # Object files in subdirectories
 
 mod-subdirs				:= i4l hisax capi eicon
diff -Nru a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile
--- a/drivers/isdn/capi/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/isdn/capi/Makefile	Wed May 29 11:43:03 2002
@@ -15,7 +15,9 @@
 
 # Multipart objects.
 
-kernelcapi-objs	:= kcapi.o capiutil.o capilib.o
+kernelcapi-y				:= kcapi.o capiutil.o capilib.o
+kernelcapi-$(CONFIG_PROC_FS)		+= kcapi_proc.o
+kernelcapi-objs				:= $(kernelcapi-y)
 
 # The global Rules.make.
 
diff -Nru a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
--- a/drivers/isdn/capi/kcapi.c	Wed May 29 11:43:03 2002
+++ b/drivers/isdn/capi/kcapi.c	Wed May 29 11:43:03 2002
@@ -3,25 +3,22 @@
  * Kernel CAPI 2.0 Module
  * 
  * Copyright 1999 by Carsten Paeth <calle@calle.de>
+ * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
  * 
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
  *
  */
 
-#define DBG(format, arg...) do { \
-printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg); \
-} while (0)
-
 #define CONFIG_AVMB1_COMPAT
 
-#include <linux/config.h>
+#include "kcapi.h"
 #include <linux/module.h>
-#include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/skbuff.h>
 #include <linux/tqueue.h>
 #include <linux/capi.h>
@@ -30,7 +27,6 @@
 #include <asm/uaccess.h>
 #include <linux/isdn/capicmd.h>
 #include <linux/isdn/capiutil.h>
-#include <linux/isdn/capilli.h>
 #ifdef CONFIG_AVMB1_COMPAT
 #include <linux/b1lli.h>
 #endif
@@ -39,12 +35,6 @@
 
 /* ------------------------------------------------------------- */
 
-#define CARD_DETECTED	1
-#define CARD_LOADING	2
-#define CARD_RUNNING	3
-
-/* ------------------------------------------------------------- */
-
 static int showcapimsgs = 0;
 
 MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");
@@ -70,14 +60,15 @@
 
 #define NCCI2CTRL(ncci)    (((ncci) >> 24) & 0x7f)
 
-static struct capi20_appl *applications[CAPI_MAXAPPL];
-static struct capi_ctr *cards[CAPI_MAXCONTR];
+LIST_HEAD(capi_drivers);
+spinlock_t capi_drivers_lock = SPIN_LOCK_UNLOCKED;
+
+struct capi20_appl *capi_applications[CAPI_MAXAPPL];
+struct capi_ctr *capi_cards[CAPI_MAXCONTR];
+
 static int ncards;
 static struct sk_buff_head recv_queue;
 
-static LIST_HEAD(drivers);
-static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;
-
 static struct tq_struct tq_state_notify;
 static struct tq_struct tq_recv_notify;
 
@@ -86,8 +77,8 @@
 static inline struct capi_ctr *
 capi_ctr_get(struct capi_ctr *card)
 {
-	if (card->driver->owner) {
-		if (try_inc_mod_count(card->driver->owner)) {
+	if (card->owner) {
+		if (try_inc_mod_count(card->owner)) {
 			DBG("MOD_COUNT INC");
 			return card;
 		} else
@@ -100,8 +91,8 @@
 static inline void
 capi_ctr_put(struct capi_ctr *card)
 {
-	if (card->driver->owner)
-		__MOD_DEC_USE_COUNT(card->driver->owner);
+	if (card->owner)
+		__MOD_DEC_USE_COUNT(card->owner);
 	DBG("MOD_COUNT DEC");
 }
 
@@ -112,7 +103,7 @@
 	if (contr - 1 >= CAPI_MAXCONTR)
 		return NULL;
 
-	return cards[contr - 1];
+	return capi_cards[contr - 1];
 }
 
 static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
@@ -120,21 +111,11 @@
 	if (applid - 1 >= CAPI_MAXAPPL)
 		return NULL;
 
-	return applications[applid - 1];
+	return capi_applications[applid - 1];
 }
 
 /* -------- util functions ------------------------------------ */
 
-static char *cardstate2str(unsigned short cardstate)
-{
-	switch (cardstate) {
-	case CARD_DETECTED:	return "detected";
-	case CARD_LOADING:	return "loading";
-	case CARD_RUNNING:	return "running";
-	default:	        return "???";
-	}
-}
-
 static inline int capi_cmd_valid(u8 cmd)
 {
 	switch (cmd) {
@@ -170,244 +151,13 @@
 	return 0;
 }
 
-/* -------- /proc functions ----------------------------------- */
-/*
- * /proc/capi/applications:
- *      applid l3cnt dblkcnt dblklen #ncci recvqueuelen
- */
-static int proc_applications_read_proc(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data)
-{
-	struct capi20_appl *ap;
-	int i;
-	int len = 0;
-
-	for (i=1; i <= CAPI_MAXAPPL; i++) {
-		ap = get_capi_appl_by_nr(i);
-		if (!ap) continue;
-		len += sprintf(page+len, "%u %d %d %d\n",
-			       ap->applid,
-			       ap->rparam.level3cnt,
-			       ap->rparam.datablkcnt,
-			       ap->rparam.datablklen);
-		if (len <= off) {
-			off -= len;
-			len = 0;
-		} else {
-			if (len-off > count)
-				goto endloop;
-		}
-	}
-endloop:
-	*start = page+off;
-	if (len < count)
-		*eof = 1;
-	if (len>count) len = count;
-	if (len<0) len = 0;
-	return len;
-}
-
-/*
- * /proc/capi/driver:
- *	driver ncontroller
- */
-static int proc_driver_read_proc(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data)
-{
-	struct list_head *l;
-	struct capi_driver *driver;
-	int len = 0;
-
-	spin_lock(&drivers_lock);
-	list_for_each(l, &drivers) {
-		driver = list_entry(l, struct capi_driver, driver_list);
-
-		len += sprintf(page+len, "%-32s %d %s\n",
-					driver->name,
-					driver->ncontroller,
-					driver->revision);
-		if (len <= off) {
-			off -= len;
-			len = 0;
-		} else {
-			if (len-off > count)
-				goto endloop;
-		}
-	}
-endloop:
-	spin_unlock(&drivers_lock);
-	*start = page+off;
-	if (len < count)
-		*eof = 1;
-	if (len>count) len = count;
-	if (len<0) len = 0;
-	return len;
-}
-
-/*
- * /proc/capi/controller:
- *	cnr driver cardstate name driverinfo
- */
-static int proc_controller_read_proc(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data)
-{
-	struct capi_ctr *cp;
-	int i;
-	int len = 0;
-
-	for (i=0; i < CAPI_MAXCONTR; i++) {
-		cp = cards[i];
-		if (!cp)
-			continue;
-
-		len += sprintf(page+len, "%d %-10s %-8s %-16s %s\n",
-			cp->cnr, cp->driver->name, 
-			cardstate2str(cp->cardstate),
-			cp->name,
-			cp->driver->procinfo ?  cp->driver->procinfo(cp) : ""
-			);
-		if (len <= off) {
-			off -= len;
-			len = 0;
-		} else {
-			if (len-off > count)
-				goto endloop;
-		}
-	}
-endloop:
-	*start = page+off;
-	if (len < count)
-		*eof = 1;
-	if (len>count) len = count;
-	if (len<0) len = 0;
-	return len;
-}
-
-/*
- * /proc/capi/applstats:
- *	applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
- */
-static int proc_applstats_read_proc(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data)
-{
-	struct capi20_appl *ap;
-	int i;
-	int len = 0;
-
-	for (i=1; i <= CAPI_MAXAPPL; i++) {
-		ap = get_capi_appl_by_nr(i);
-		if (!ap) continue;
-		len += sprintf(page+len, "%u %lu %lu %lu %lu\n",
-			ap->applid,
-			ap->nrecvctlpkt,
-			ap->nrecvdatapkt,
-			ap->nsentctlpkt,
-			ap->nsentdatapkt);
-		if (len <= off) {
-			off -= len;
-			len = 0;
-		} else {
-			if (len-off > count)
-				goto endloop;
-		}
-	}
-endloop:
-	*start = page+off;
-	if (len < count)
-		*eof = 1;
-	if (len>count) len = count;
-	if (len<0) len = 0;
-	return len;
-}
-
-/*
- * /proc/capi/contrstats:
- *	cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
- */
-static int proc_contrstats_read_proc(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data)
-{
-	struct capi_ctr *cp;
-	int i;
-	int len = 0;
-
-	for (i=0; i < CAPI_MAXCONTR; i++) {
-		cp = cards[i];
-		if (!cp)
-			continue;
-		len += sprintf(page+len, "%d %lu %lu %lu %lu\n",
-			cp->cnr, 
-			cp->nrecvctlpkt,
-			cp->nrecvdatapkt,
-			cp->nsentctlpkt,
-			cp->nsentdatapkt);
-		if (len <= off) {
-			off -= len;
-			len = 0;
-		} else {
-			if (len-off > count)
-				goto endloop;
-		}
-	}
-endloop:
-	*start = page+off;
-	if (len < count)
-		*eof = 1;
-	if (len>count) len = count;
-	if (len<0) len = 0;
-	return len;
-}
-
-static struct procfsentries {
-  char *name;
-  mode_t mode;
-  int (*read_proc)(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data);
-  struct proc_dir_entry *procent;
-} procfsentries[] = {
-   { "capi",		  S_IFDIR, 0 },
-   { "capi/applications", 0	 , proc_applications_read_proc },
-   { "capi/driver",       0	 , proc_driver_read_proc },
-   { "capi/controller",   0	 , proc_controller_read_proc },
-   { "capi/applstats",    0	 , proc_applstats_read_proc },
-   { "capi/contrstats",   0	 , proc_contrstats_read_proc },
-   { "capi/drivers",	  S_IFDIR, 0 },
-   { "capi/controllers",  S_IFDIR, 0 },
-};
-
-static void proc_capi_init(void)
-{
-    int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
-    int i;
-
-    for (i=0; i < nelem; i++) {
-        struct procfsentries *p = procfsentries + i;
-	p->procent = create_proc_entry(p->name, p->mode, 0);
-	if (p->procent) p->procent->read_proc = p->read_proc;
-    }
-}
-
-static void proc_capi_exit(void)
-{
-    int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
-    int i;
-
-    for (i=nelem-1; i >= 0; i--) {
-        struct procfsentries *p = procfsentries + i;
-	if (p->procent) {
-	   remove_proc_entry(p->name, 0);
-	   p->procent = 0;
-	}
-    }
-}
-
 /* ------------------------------------------------------------ */
 
 static void register_appl(struct capi_ctr *card, u16 applid, capi_register_params *rparam)
 {
 	card = capi_ctr_get(card);
 
-	card->driver->register_appl(card, applid, rparam);
+	card->register_appl(card, applid, rparam);
 }
 
 
@@ -415,7 +165,7 @@
 {
 	DBG("applid %#x", applid);
 	
-	card->driver->release_appl(card, applid);
+	card->release_appl(card, applid);
 	capi_ctr_put(card);
 }
 
@@ -574,8 +324,7 @@
 	}
 }
 
-static void controllercb_handle_capimsg(struct capi_ctr * card,
-				u16 appl, struct sk_buff *skb)
+void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb)
 {
 	int showctl = 0;
 	u8 cmd, subcmd;
@@ -618,7 +367,9 @@
 	kfree_skb(skb);
 }
 
-static void controllercb_ready(struct capi_ctr * card)
+EXPORT_SYMBOL(capi_ctr_handle_message);
+
+void capi_ctr_ready(struct capi_ctr * card)
 {
 	u16 appl;
 	struct capi20_appl *ap;
@@ -637,7 +388,9 @@
 	notify_push(KCI_CONTRUP, card->cnr, 0, 0);
 }
 
-static void controllercb_reseted(struct capi_ctr * card)
+EXPORT_SYMBOL(capi_ctr_ready);
+
+void capi_ctr_reseted(struct capi_ctr * card)
 {
 	u16 appl;
 
@@ -666,7 +419,9 @@
 	notify_push(KCI_CONTRDOWN, card->cnr, 0, 0);
 }
 
-static void controllercb_suspend_output(struct capi_ctr *card)
+EXPORT_SYMBOL(capi_ctr_reseted);
+
+void capi_ctr_suspend_output(struct capi_ctr *card)
 {
 	if (!card->blocked) {
 		printk(KERN_DEBUG "kcapi: card %d suspend\n", card->cnr);
@@ -674,7 +429,9 @@
 	}
 }
 
-static void controllercb_resume_output(struct capi_ctr *card)
+EXPORT_SYMBOL(capi_ctr_suspend_output);
+
+void capi_ctr_resume_output(struct capi_ctr *card)
 {
 	if (card->blocked) {
 		printk(KERN_DEBUG "kcapi: card %d resume\n", card->cnr);
@@ -682,81 +439,65 @@
 	}
 }
 
-/* ------------------------------------------------------------- */
+EXPORT_SYMBOL(capi_ctr_resume_output);
 
+/* ------------------------------------------------------------- */
 
-struct capi_ctr *
-attach_capi_ctr(struct capi_driver *driver, char *name, void *driverdata)
+int
+attach_capi_ctr(struct capi_ctr *card)
 {
-	struct capi_ctr *card;
 	int i;
 
-	for (i=0; i < CAPI_MAXCONTR; i++) {
-		if (cards[i] == NULL)
+	for (i = 0; i < CAPI_MAXCONTR; i++) {
+		if (capi_cards[i] == NULL)
 			break;
 	}
 	if (i == CAPI_MAXCONTR) {
 		printk(KERN_ERR "kcapi: out of controller slots\n");
-	   	return NULL;
+	   	return -EBUSY;
 	}
-	card = kmalloc(sizeof(*card), GFP_KERNEL);
-	if (!card)
-		return NULL;
+	capi_cards[i] = card;
 
-	cards[i] = card;
-	memset(card, 0, sizeof(struct capi_ctr));
-	card->driver = driver;
+	card->nrecvctlpkt = 0;
+	card->nrecvdatapkt = 0;
+	card->nsentctlpkt = 0;
+	card->nsentdatapkt = 0;
 	card->cnr = i + 1;
-	strncpy(card->name, name, sizeof(card->name));
 	card->cardstate = CARD_DETECTED;
 	card->blocked = 0;
-	card->driverdata = driverdata;
 	card->traceflag = showcapimsgs;
 
-        card->ready = controllercb_ready; 
-        card->reseted = controllercb_reseted; 
-        card->suspend_output = controllercb_suspend_output;
-        card->resume_output = controllercb_resume_output;
-        card->handle_capimsg = controllercb_handle_capimsg;
-
-	list_add_tail(&card->driver_list, &driver->contr_head);
-	driver->ncontroller++;
 	sprintf(card->procfn, "capi/controllers/%d", card->cnr);
 	card->procent = create_proc_entry(card->procfn, 0, 0);
 	if (card->procent) {
 	   card->procent->read_proc = 
 		(int (*)(char *,char **,off_t,int,int *,void *))
-			driver->ctr_read_proc;
+			card->ctr_read_proc;
 	   card->procent->data = card;
 	}
 
 	ncards++;
 	printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n",
 			card->cnr, card->name);
-	return card;
+	return 0;
 }
 
 EXPORT_SYMBOL(attach_capi_ctr);
 
 int detach_capi_ctr(struct capi_ctr *card)
 {
-	struct capi_driver *driver = card->driver;
-
         if (card->cardstate != CARD_DETECTED)
-		controllercb_reseted(card);
+		capi_ctr_reseted(card);
 
-	list_del(&card->driver_list);
-	driver->ncontroller--;
 	ncards--;
 
 	if (card->procent) {
 	   remove_proc_entry(card->procfn, 0);
 	   card->procent = 0;
 	}
-	cards[card->cnr - 1] = NULL;
+	capi_cards[card->cnr - 1] = NULL;
 	printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n",
 			card->cnr, card->name);
-	kfree(card);
 
 	return 0;
 }
@@ -764,68 +505,6 @@
 EXPORT_SYMBOL(detach_capi_ctr);
 
 /* ------------------------------------------------------------- */
-
-/* fallback if no driver read_proc function defined by driver */
-
-static int driver_read_proc(char *page, char **start, off_t off,
-        		int count, int *eof, void *data)
-{
-	struct capi_driver *driver = (struct capi_driver *)data;
-	int len = 0;
-
-	len += sprintf(page+len, "%-16s %s\n", "name", driver->name);
-	len += sprintf(page+len, "%-16s %s\n", "revision", driver->revision);
-
-	if (len < off) 
-           return 0;
-	*eof = 1;
-	*start = page + off;
-	return ((count < len-off) ? count : len-off);
-}
-
-/* ------------------------------------------------------------- */
-
-void attach_capi_driver(struct capi_driver *driver)
-{
-	INIT_LIST_HEAD(&driver->contr_head);
-
-	spin_lock(&drivers_lock);
-	list_add_tail(&driver->driver_list, &drivers);
-	spin_unlock(&drivers_lock);
-
-	printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name);
-	sprintf(driver->procfn, "capi/drivers/%s", driver->name);
-	driver->procent = create_proc_entry(driver->procfn, 0, 0);
-	if (driver->procent) {
-	   if (driver->driver_read_proc) {
-		   driver->procent->read_proc = 
-	       		(int (*)(char *,char **,off_t,int,int *,void *))
-					driver->driver_read_proc;
-	   } else {
-		   driver->procent->read_proc = driver_read_proc;
-	   }
-	   driver->procent->data = driver;
-	}
-}
-
-EXPORT_SYMBOL(attach_capi_driver);
-
-void detach_capi_driver(struct capi_driver *driver)
-{
-	spin_lock(&drivers_lock);
-	list_del(&driver->driver_list);
-	spin_unlock(&drivers_lock);
-
-	printk(KERN_NOTICE "kcapi: driver %s detached\n", driver->name);
-	if (driver->procent) {
-	   remove_proc_entry(driver->procfn, 0);
-	   driver->procent = 0;
-	}
-}
-
-EXPORT_SYMBOL(detach_capi_driver);
-
-/* ------------------------------------------------------------- */
 /* -------- CAPI2.0 Interface ---------------------------------- */
 /* ------------------------------------------------------------- */
 
@@ -833,7 +512,7 @@
 {
 	int i;
 	for (i = 0; i < CAPI_MAXCONTR; i++) {
-		if (cards[i] && cards[i]->cardstate == CARD_RUNNING)
+		if (capi_cards[i] && capi_cards[i]->cardstate == CARD_RUNNING)
 			return CAPI_NOERROR;
 	}
 	return CAPI_REGNOTINSTALLED;
@@ -852,14 +531,14 @@
 		return CAPI_LOGBLKSIZETOSMALL;
 
 	for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
-		if (applications[applid - 1] == NULL)
+		if (capi_applications[applid - 1] == NULL)
 			break;
 	}
 	if (applid > CAPI_MAXAPPL)
 		return CAPI_TOOMANYAPPLS;
 
 	ap->applid = applid;
-	applications[applid - 1] = ap;
+	capi_applications[applid - 1] = ap;
 
 	ap->nrecvctlpkt = 0;
 	ap->nrecvdatapkt = 0;
@@ -868,9 +547,9 @@
 	ap->callback = 0;
 	
 	for (i = 0; i < CAPI_MAXCONTR; i++) {
-		if (!cards[i] || cards[i]->cardstate != CARD_RUNNING)
+		if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
 			continue;
-		register_appl(cards[i], applid, &ap->rparam);
+		register_appl(capi_cards[i], applid, &ap->rparam);
 	}
 	printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
 
@@ -886,11 +565,11 @@
 	DBG("applid %#x", ap->applid);
 
 	for (i = 0; i < CAPI_MAXCONTR; i++) {
-		if (!cards[i] || cards[i]->cardstate != CARD_RUNNING)
+		if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
 			continue;
-		release_appl(cards[i], ap->applid);
+		release_appl(capi_cards[i], ap->applid);
 	}
-	applications[ap->applid - 1] = NULL;
+	capi_applications[ap->applid - 1] = NULL;
 	printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
 
 	return CAPI_NOERROR;
@@ -950,7 +629,7 @@
 		}
 
 	}
-	return card->driver->send_message(card, skb);
+	return card->send_message(card, skb);
 }
 
 EXPORT_SYMBOL(capi20_put_message);
@@ -1028,28 +707,11 @@
 
 EXPORT_SYMBOL(capi20_get_profile);
 
-static struct capi_driver *find_driver(char *name)
-{
-	struct list_head *l;
-	struct capi_driver *dp;
-	spin_lock(&drivers_lock);
-	list_for_each(l, &drivers) {
-		dp = list_entry(l, struct capi_driver, driver_list);
-		if (strcmp(dp->name, name) == 0)
-			goto found;
-	}
-	dp = NULL;
- found:
-	spin_unlock(&drivers_lock);
-	return dp;
-}
-
 #ifdef CONFIG_AVMB1_COMPAT
 static int old_capi_manufacturer(unsigned int cmd, void *data)
 {
 	avmb1_loadandconfigdef ldef;
 	avmb1_resetdef rdef;
-	avmb1_getdef gdef;
 	struct capi_ctr *card;
 	capiloaddata ldata;
 	int retval;
@@ -1073,8 +735,8 @@
 		card = capi_ctr_get(card);
 		if (!card)
 			return -ESRCH;
-		if (card->driver->load_firmware == 0) {
-			printk(KERN_DEBUG "kcapi: load: driver \%s\" has no load function\n", card->driver->name);
+		if (card->load_firmware == 0) {
+			printk(KERN_DEBUG "kcapi: load: no load function\n");
 			return -ESRCH;
 		}
 
@@ -1100,7 +762,7 @@
 		}
 		card->cardstate = CARD_LOADING;
 
-		retval = card->driver->load_firmware(card, &ldata);
+		retval = card->load_firmware(card, &ldata);
 
 		if (retval) {
 			card->cardstate = CARD_DETECTED;
@@ -1131,7 +793,7 @@
 		if (card->cardstate == CARD_DETECTED)
 			return 0;
 
-		card->driver->reset_ctr(card);
+		card->reset_ctr(card);
 
 		while (card->cardstate > CARD_DETECTED) {
 
@@ -1143,23 +805,6 @@
 		}
 		return 0;
 
-	case AVMB1_GET_CARDINFO:
-		if (copy_from_user((void *)&gdef, data, sizeof(avmb1_getdef)))
-			return -EFAULT;
-
-		card = get_capi_ctr_by_nr(gdef.contr);
-		if (!card)
-			return -ESRCH;
-
-		gdef.cardstate = card->cardstate;
-		if (card->driver == find_driver("t1isa"))
-			gdef.cardtype = AVM_CARDTYPE_T1;
-		else gdef.cardtype = AVM_CARDTYPE_B1;
-
-		if (copy_to_user(data, (void *)&gdef, sizeof(avmb1_getdef)))
-			return -EFAULT;
-
-		return 0;
 	}
 	return -EINVAL;
 }
@@ -1228,8 +873,6 @@
 	char *p;
 	char rev[32];
 
-	MOD_INC_USE_COUNT;
-
 	skb_queue_head_init(&recv_queue);
 
 	tq_state_notify.routine = notify_handler;
@@ -1238,7 +881,7 @@
 	tq_recv_notify.routine = recv_handler;
 	tq_recv_notify.data = 0;
 
-        proc_capi_init();
+        kcapi_proc_init();
 
 	if ((p = strchr(revision, ':')) != 0 && p[1]) {
 		strncpy(rev, p + 2, sizeof(rev));
@@ -1248,30 +891,14 @@
 	} else
 		strcpy(rev, "1.0");
 
-#ifdef MODULE
-        printk(KERN_NOTICE "CAPI-driver Rev %s: loaded\n", rev);
-#else
-	printk(KERN_NOTICE "CAPI-driver Rev %s: started\n", rev);
-#endif
-	MOD_DEC_USE_COUNT;
+        printk(KERN_NOTICE "CAPI Subsystem Rev %s\n", rev);
+
 	return 0;
 }
 
 static void __exit kcapi_exit(void)
 {
-	char rev[10];
-	char *p;
-
-	if ((p = strchr(revision, ':'))) {
-		strcpy(rev, p + 1);
-		p = strchr(rev, '$');
-		*p = 0;
-	} else {
-		strcpy(rev, "1.0");
-	}
-
-        proc_capi_exit();
-	printk(KERN_NOTICE "CAPI-driver Rev%s: unloaded\n", rev);
+        kcapi_proc_exit();
 }
 
 module_init(kcapi_init);
diff -Nru a/drivers/isdn/capi/kcapi.h b/drivers/isdn/capi/kcapi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/capi/kcapi.h	Wed May 29 11:43:03 2002
@@ -0,0 +1,46 @@
+/*
+ * Kernel CAPI 2.0 Module
+ * 
+ * Copyright 1999 by Carsten Paeth <calle@calle.de>
+ * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/isdn/capilli.h>
+
+#define DBG(format, arg...) do { \
+printk(KERN_INFO __FUNCTION__ ": " format "\n" , ## arg); \
+} while (0)
+
+
+enum {
+	CARD_DETECTED = 1,
+	CARD_LOADING  =	2,
+	CARD_RUNNING  = 3,
+};
+
+extern struct list_head capi_drivers;
+extern spinlock_t capi_drivers_lock;
+
+extern struct capi20_appl *capi_applications[CAPI_MAXAPPL];
+extern struct capi_ctr *capi_cards[CAPI_MAXCONTR];
+
+#ifdef CONFIG_PROC_FS
+
+void kcapi_proc_init(void);
+void kcapi_proc_exit(void);
+
+#else
+
+static inline void kcapi_proc_init(void) { };
+static inline void kcapi_proc_exit(void) { };
+
+#endif
+
diff -Nru a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/capi/kcapi_proc.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,269 @@
+/*
+ * Kernel CAPI 2.0 Module - /proc/capi handling
+ * 
+ * Copyright 1999 by Carsten Paeth <calle@calle.de>
+ * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+
+#include "kcapi.h"
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+
+static char *
+cardstate2str(unsigned short cardstate)
+{
+	switch (cardstate) {
+	case CARD_DETECTED:	return "detected";
+	case CARD_LOADING:	return "loading";
+	case CARD_RUNNING:	return "running";
+	default:	        return "???";
+	}
+}
+
+// /proc/capi
+// ===========================================================================
+
+// /proc/capi/controller: 
+//      cnr driver cardstate name driverinfo
+// /proc/capi/contrstats:
+//      cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
+// ---------------------------------------------------------------------------
+
+static void *controller_start(struct seq_file *seq, loff_t *pos)
+{
+	if (*pos < CAPI_MAXCONTR)
+		return &capi_cards[*pos];
+
+	return NULL;
+}
+
+static void *controller_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	++*pos;
+	if (*pos < CAPI_MAXCONTR)
+		return &capi_cards[*pos];
+
+	return NULL;
+}
+
+static void controller_stop(struct seq_file *seq, void *v)
+{
+}
+
+static int controller_show(struct seq_file *seq, void *v)
+{
+	struct capi_ctr *ctr = *(struct capi_ctr **) v;
+
+	if (!ctr)
+		return 0;
+
+	seq_printf(seq, "%d %-10s %-8s %-16s %s\n",
+		   ctr->cnr, ctr->driver_name,
+		   cardstate2str(ctr->cardstate),
+		   ctr->name,
+		   ctr->procinfo ?  ctr->procinfo(ctr) : "");
+
+	return 0;
+}
+
+static int contrstats_show(struct seq_file *seq, void *v)
+{
+	struct capi_ctr *ctr = *(struct capi_ctr **) v;
+
+	if (!ctr)
+		return 0;
+
+	seq_printf(seq, "%d %lu %lu %lu %lu\n",
+		   ctr->cnr, 
+		   ctr->nrecvctlpkt,
+		   ctr->nrecvdatapkt,
+		   ctr->nsentctlpkt,
+		   ctr->nsentdatapkt);
+
+	return 0;
+}
+
+struct seq_operations seq_controller_ops = {
+	start:	controller_start,
+	next:	controller_next,
+	stop:	controller_stop,
+	show:	controller_show,
+};
+
+struct seq_operations seq_contrstats_ops = {
+	start:	controller_start,
+	next:	controller_next,
+	stop:	controller_stop,
+	show:	contrstats_show,
+};
+
+static int seq_controller_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &seq_controller_ops);
+}
+
+static int seq_contrstats_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &seq_contrstats_ops);
+}
+
+static struct file_operations proc_controller_ops = {
+	open:		seq_controller_open,
+	read:		seq_read,
+	llseek:		seq_lseek,
+	release:	seq_release,
+};
+
+static struct file_operations proc_contrstats_ops = {
+	open:		seq_contrstats_open,
+	read:		seq_read,
+	llseek:		seq_lseek,
+	release:	seq_release,
+};
+
+// /proc/capi/applications: 
+//      applid l3cnt dblkcnt dblklen #ncci recvqueuelen
+// /proc/capi/applstats: 
+//      applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
+// ---------------------------------------------------------------------------
+
+static void *
+applications_start(struct seq_file *seq, loff_t *pos)
+{
+	if (*pos < CAPI_MAXAPPL)
+		return &capi_applications[*pos];
+
+	return NULL;
+}
+
+static void *
+applications_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	++*pos;
+	if (*pos < CAPI_MAXAPPL)
+		return &capi_applications[*pos];
+
+	return NULL;
+}
+
+static void
+applications_stop(struct seq_file *seq, void *v)
+{
+}
+
+static int
+applications_show(struct seq_file *seq, void *v)
+{
+	struct capi20_appl *ap = *(struct capi20_appl **) v;
+
+	if (!ap)
+		return 0;
+
+	seq_printf(seq, "%u %d %d %d\n",
+		   ap->applid,
+		   ap->rparam.level3cnt,
+		   ap->rparam.datablkcnt,
+		   ap->rparam.datablklen);
+
+	return 0;
+}
+
+static int
+applstats_show(struct seq_file *seq, void *v)
+{
+	struct capi20_appl *ap = *(struct capi20_appl **) v;
+
+	if (!ap)
+		return 0;
+
+	seq_printf(seq, "%u %lu %lu %lu %lu\n",
+		   ap->applid,
+		   ap->nrecvctlpkt,
+		   ap->nrecvdatapkt,
+		   ap->nsentctlpkt,
+		   ap->nsentdatapkt);
+
+	return 0;
+}
+
+struct seq_operations seq_applications_ops = {
+	start:	applications_start,
+	next:	applications_next,
+	stop:	applications_stop,
+	show:	applications_show,
+};
+
+struct seq_operations seq_applstats_ops = {
+	start:	applications_start,
+	next:	applications_next,
+	stop:	applications_stop,
+	show:	applstats_show,
+};
+
+static int
+seq_applications_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &seq_applications_ops);
+}
+
+static int
+seq_applstats_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &seq_applstats_ops);
+}
+
+static struct file_operations proc_applications_ops = {
+	open:		seq_applications_open,
+	read:		seq_read,
+	llseek:		seq_lseek,
+	release:	seq_release,
+};
+
+static struct file_operations proc_applstats_ops = {
+	open:		seq_applstats_open,
+	read:		seq_read,
+	llseek:		seq_lseek,
+	release:	seq_release,
+};
+
+static void
+create_seq_entry(char *name, mode_t mode, struct file_operations *f)
+{
+	struct proc_dir_entry *entry;
+	entry = create_proc_entry(name, mode, NULL);
+	if (entry)
+		entry->proc_fops = f;
+}
+
+// ---------------------------------------------------------------------------
+
+void __init 
+kcapi_proc_init(void)
+{
+	proc_mkdir("capi",             NULL);
+	proc_mkdir("capi/controllers", NULL);
+	proc_mkdir("capi/drivers",     NULL);
+	create_seq_entry("capi/controller",   0, &proc_controller_ops);
+	create_seq_entry("capi/contrstats",   0, &proc_contrstats_ops);
+	create_seq_entry("capi/applications", 0, &proc_applications_ops);
+	create_seq_entry("capi/applstats",    0, &proc_applstats_ops);
+}
+
+void __exit
+kcapi_proc_exit(void)
+{
+	remove_proc_entry("capi/driver",       NULL);
+	remove_proc_entry("capi/controller",   NULL);
+	remove_proc_entry("capi/contrstats",   NULL);
+	remove_proc_entry("capi/applications", NULL);
+	remove_proc_entry("capi/applstats",    NULL);
+	remove_proc_entry("capi/drivers",      NULL);
+	remove_proc_entry("capi/controllers",  NULL);
+	remove_proc_entry("capi",              NULL);
+}
diff -Nru a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h
--- a/drivers/isdn/hardware/avm/avmcard.h	Wed May 29 11:43:02 2002
+++ b/drivers/isdn/hardware/avm/avmcard.h	Wed May 29 11:43:02 2002
@@ -11,6 +11,7 @@
 #define _AVMCARD_H_
 
 #include <linux/spinlock.h>
+#include <linux/list.h>
 
 #define	AVMB1_PORTLEN		0x1f
 #define AVM_MAXVERSION		8
@@ -67,7 +68,7 @@
 	char infobuf[128];	/* for function procinfo */
 	
 	struct avmcard  *card;
-	struct capi_ctr *capi_ctrl;
+	struct capi_ctr  capi_ctrl;
 	
 	struct list_head ncci_head;
 } avmctrl_info;
@@ -93,7 +94,9 @@
 
 	struct avmctrl_info *ctrlinfo;
 
+	int nr_controllers;
 	int nlogcontr;
+	struct list_head list;
 } avmcard;
 
 extern int b1_irq_table[16];
@@ -537,7 +540,6 @@
 }
 
 /* b1.c */
-void b1_set_revision(struct capi_driver *driver, char *rev);
 avmcard *b1_alloc_card(int nr_controllers);
 void b1_free_card(avmcard *card);
 int b1_detect(unsigned int base, enum avmcardtype cardtype);
diff -Nru a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
--- a/drivers/isdn/hardware/avm/b1.c	Wed May 29 11:43:02 2002
+++ b/drivers/isdn/hardware/avm/b1.c	Wed May 29 11:43:02 2002
@@ -59,21 +59,6 @@
 
 /* ------------------------------------------------------------- */	
 
-void b1_set_revision(struct capi_driver *driver, char *rev)
-{
-	char *p;
-
-	if ((p = strchr(rev, ':')) != 0 && p[1]) {
-		strncpy(driver->revision, p + 2, sizeof(driver->revision));
-		driver->revision[sizeof(driver->revision)-1] = 0;
-		if ((p = strchr(driver->revision, '$')) != 0 && p > driver->revision)
-			*(p-1) = 0;
-	}
-	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
-}
-
-/* ------------------------------------------------------------- */	
-
 avmcard *b1_alloc_card(int nr_controllers)
 {
 	avmcard *card;
@@ -99,6 +84,7 @@
 		cinfo[i].card = card;
 	}
 	spin_lock_init(&card->lock);
+	card->nr_controllers = nr_controllers;
 
 	return card;
 }
@@ -344,7 +330,7 @@
 
 	memset(cinfo->version, 0, sizeof(cinfo->version));
 	capilib_release(&cinfo->ncci_head);
-	ctrl->reseted(ctrl);
+	capi_ctr_reseted(ctrl);
 }
 
 void b1_register_appl(struct capi_ctr *ctrl,
@@ -433,7 +419,7 @@
 
 void b1_parse_version(avmctrl_info *cinfo)
 {
-	struct capi_ctr *ctrl = cinfo->capi_ctrl;
+	struct capi_ctr *ctrl = &cinfo->capi_ctrl;
 	avmcard *card = cinfo->card;
 	capi_profile *profp;
 	u8 *dversion;
@@ -509,7 +495,7 @@
 {
 	avmcard *card = devptr;
 	avmctrl_info *cinfo = &card->ctrlinfo[0];
-	struct capi_ctr *ctrl = cinfo->capi_ctrl;
+	struct capi_ctr *ctrl = &cinfo->capi_ctrl;
 	unsigned char b1cmd;
 	struct sk_buff *skb;
 
@@ -543,7 +529,7 @@
 		} else {
 			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
 			memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
-			ctrl->handle_capimsg(ctrl, ApplId, skb);
+			capi_ctr_handle_message(ctrl, ApplId, skb);
 		}
 		break;
 
@@ -561,7 +547,7 @@
 						     CAPIMSG_NCCI(skb->data),
 						     CAPIMSG_MSGID(skb->data));
 
-			ctrl->handle_capimsg(ctrl, ApplId, skb);
+			capi_ctr_handle_message(ctrl, ApplId, skb);
 		}
 		break;
 
@@ -587,11 +573,11 @@
 
 	case RECEIVE_START:
 	   	/* b1_put_byte(card->port, SEND_POLLACK); */
-		ctrl->resume_output(ctrl);
+		capi_ctr_resume_output(ctrl);
 		break;
 
 	case RECEIVE_STOP:
-		ctrl->suspend_output(ctrl);
+		capi_ctr_suspend_output(ctrl);
 		break;
 
 	case RECEIVE_INIT:
@@ -602,7 +588,7 @@
 		       card->name,
 		       cinfo->version[VER_CARDTYPE],
 		       cinfo->version[VER_DRIVER]);
-		ctrl->ready(ctrl);
+		capi_ctr_ready(ctrl);
 		break;
 
 	case RECEIVE_TASK_READY:
@@ -774,7 +760,6 @@
 
 EXPORT_SYMBOL(b1_irq_table);
 
-EXPORT_SYMBOL(b1_set_revision);
 EXPORT_SYMBOL(b1_alloc_card);
 EXPORT_SYMBOL(b1_free_card);
 EXPORT_SYMBOL(b1_detect);
diff -Nru a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
--- a/drivers/isdn/hardware/avm/b1dma.c	Wed May 29 11:43:03 2002
+++ b/drivers/isdn/hardware/avm/b1dma.c	Wed May 29 11:43:03 2002
@@ -447,7 +447,7 @@
 {
 	avmctrl_info *cinfo = &card->ctrlinfo[0];
 	avmcard_dmainfo *dma = card->dma;
-	struct capi_ctr *ctrl = cinfo->capi_ctrl;
+	struct capi_ctr *ctrl = &cinfo->capi_ctrl;
 	struct sk_buff *skb;
 	void *p = dma->recvbuf.dmabuf+4;
 	u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
@@ -475,7 +475,7 @@
 		} else {
 			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
 			memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
-			ctrl->handle_capimsg(ctrl, ApplId, skb);
+			capi_ctr_handle_message(ctrl, ApplId, skb);
 		}
 		break;
 
@@ -493,7 +493,7 @@
 						     CAPIMSG_NCCI(skb->data),
 						     CAPIMSG_MSGID(skb->data));
 
-			ctrl->handle_capimsg(ctrl, ApplId, skb);
+			capi_ctr_handle_message(ctrl, ApplId, skb);
 		}
 		break;
 
@@ -523,11 +523,11 @@
 #endif
 		if (!suppress_pollack)
 			queue_pollack(card);
-		ctrl->resume_output(ctrl);
+		capi_ctr_resume_output(ctrl);
 		break;
 
 	case RECEIVE_STOP:
-		ctrl->suspend_output(ctrl);
+		capi_ctr_suspend_output(ctrl);
 		break;
 
 	case RECEIVE_INIT:
@@ -538,7 +538,7 @@
 		       card->name,
 		       cinfo->version[VER_CARDTYPE],
 		       cinfo->version[VER_DRIVER]);
-		ctrl->ready(ctrl);
+		capi_ctr_ready(ctrl);
 		break;
 
 	case RECEIVE_TASK_READY:
@@ -740,7 +740,7 @@
 
 	memset(cinfo->version, 0, sizeof(cinfo->version));
 	capilib_release(&cinfo->ncci_head);
-	ctrl->reseted(ctrl);
+	capi_ctr_reseted(ctrl);
 }
 
 
diff -Nru a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c
--- a/drivers/isdn/hardware/avm/b1isa.c	Wed May 29 11:43:02 2002
+++ b/drivers/isdn/hardware/avm/b1isa.c	Wed May 29 11:43:02 2002
@@ -25,8 +25,6 @@
 #include <linux/isdn/capilli.h>
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.10.6.6 $";
-
 /* ------------------------------------------------------------- */
 
 MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 ISA card");
@@ -35,18 +33,20 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver b1isa_driver;
-
 static void b1isa_remove(struct pci_dev *pdev)
 {
 	avmctrl_info *cinfo = pci_get_drvdata(pdev);
-	avmcard *card = cinfo->card;
-	unsigned int port = cinfo->card->port;
+	avmcard *card;
 
-	b1_reset(port);
-	b1_reset(port);
+	if (!cinfo)
+		return;
+
+	card = cinfo->card;
 
-	detach_capi_ctr(cinfo->capi_ctrl);
+	b1_reset(card->port);
+	b1_reset(card->port);
+
+	detach_capi_ctr(&cinfo->capi_ctrl);
 	free_irq(card->irq, card);
 	release_region(card->port, AVMB1_PORTLEN);
 	b1_free_card(card);
@@ -54,6 +54,8 @@
 
 /* ------------------------------------------------------------- */
 
+static char *b1isa_procinfo(struct capi_ctr *ctrl);
+
 static int __init b1isa_probe(struct pci_dev *pdev)
 {
 	avmctrl_info *cinfo;
@@ -106,16 +108,26 @@
 	b1_reset(card->port);
 	b1_getrevision(card);
 
-	cinfo->capi_ctrl = attach_capi_ctr(&b1isa_driver, card->name, cinfo);
-	if (!cinfo->capi_ctrl) {
+	cinfo->capi_ctrl.driver_name   = "b1isa";
+	cinfo->capi_ctrl.driverdata    = cinfo;
+	cinfo->capi_ctrl.register_appl = b1_register_appl;
+	cinfo->capi_ctrl.release_appl  = b1_release_appl;
+	cinfo->capi_ctrl.send_message  = b1_send_message;
+	cinfo->capi_ctrl.load_firmware = b1_load_firmware;
+	cinfo->capi_ctrl.reset_ctr     = b1_reset_ctr;
+	cinfo->capi_ctrl.procinfo      = b1isa_procinfo;
+	cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+	strcpy(cinfo->capi_ctrl.name, card->name);
+	SET_MODULE_OWNER(&cinfo->capi_ctrl);
+
+	retval = attach_capi_ctr(&cinfo->capi_ctrl);
+	if (retval) {
 		printk(KERN_ERR "b1isa: attach controller failed.\n");
-		retval = -EBUSY;
 		goto err_free_irq;
 	}
 
-	printk(KERN_INFO
-		"%s: AVM B1 ISA at i/o %#x, irq %d, revision %d\n",
-		b1isa_driver.name, card->port, card->irq, card->revision);
+	printk(KERN_INFO "b1isa: AVM B1 ISA at i/o %#x, irq %d, revision %d\n",
+	       card->port, card->irq, card->revision);
 
 	pci_set_drvdata(pdev, cinfo);
 	return 0;
@@ -148,21 +160,6 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver b1isa_driver = {
-	owner: THIS_MODULE,
-	name: "b1isa",
-	revision: "0.0",
-	load_firmware: b1_load_firmware,
-	reset_ctr: b1_reset_ctr,
-	register_appl: b1_register_appl,
-	release_appl: b1_release_appl,
-	send_message: b1_send_message,
-	
-	procinfo: b1isa_procinfo,
-	ctr_read_proc: b1ctl_read_proc,
-	driver_read_proc: 0,	/* use standard driver_read_proc */
-};
-
 #define MAX_CARDS 4
 static struct pci_dev isa_dev[MAX_CARDS];
 static int io[MAX_CARDS];
@@ -175,12 +172,9 @@
 
 static int __init b1isa_init(void)
 {
-	int i, retval;
+	int i;
 	int found = 0;
 
-	b1_set_revision(&b1isa_driver, revision);
-        attach_capi_driver(&b1isa_driver);
-
 	for (i = 0; i < MAX_CARDS; i++) {
 		if (!io[i])
 			break;
@@ -191,17 +185,10 @@
 		if (b1isa_probe(&isa_dev[i]) == 0)
 			found++;
 	}
-	if (found == 0) {
-		retval = -ENODEV;
-		goto err;
-	}
-	retval = 0;
-	goto out;
+	if (found == 0)
+		return -ENODEV;
 
- err:
-	detach_capi_driver(&b1isa_driver);
- out:
-	return retval;
+	return 0;
 }
 
 static void __exit b1isa_exit(void)
@@ -214,7 +201,6 @@
 
 		b1isa_remove(&isa_dev[i]);
 	}
-	detach_capi_driver(&b1isa_driver);
 }
 
 module_init(b1isa_init);
diff -Nru a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c
--- a/drivers/isdn/hardware/avm/b1pci.c	Wed May 29 11:43:01 2002
+++ b/drivers/isdn/hardware/avm/b1pci.c	Wed May 29 11:43:01 2002
@@ -26,8 +26,6 @@
 #include <linux/isdn/capilli.h>
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.1.4.1.2.1 $";
-
 /* ------------------------------------------------------------- */
 
 static struct pci_device_id b1pci_pci_tbl[] __devinitdata = {
@@ -60,9 +58,7 @@
 
 /* ------------------------------------------------------------- */
 
-static int b1pci_probe(struct capi_driver *driver,
-		       struct capicardparams *p,
-		       struct pci_dev *pdev)
+static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev)
 {
 	avmcard *card;
 	avmctrl_info *cinfo;
@@ -70,7 +66,7 @@
 
 	card = b1_alloc_card(1);
 	if (!card) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		printk(KERN_WARNING "b1pci: no memory.\n");
 		retval = -ENOMEM;
 		goto err;
 	}
@@ -82,17 +78,16 @@
 	card->cardtype = avm_b1pci;
 	
 	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
-		printk(KERN_WARNING
-		       "%s: ports 0x%03x-0x%03x in use.\n",
-		       driver->name, card->port, card->port + AVMB1_PORTLEN);
+		printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n",
+		       card->port, card->port + AVMB1_PORTLEN);
 		retval = -EBUSY;
 		goto err_free;
 	}
 	b1_reset(card->port);
 	retval = b1_detect(card->port, card->cardtype);
 	if (retval) {
-		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
-		       driver->name, card->port, retval);
+		printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
+		       card->port, retval);
 		retval = -ENODEV;
 		goto err_release_region;
 	}
@@ -101,28 +96,35 @@
 	
 	retval = request_irq(card->irq, b1_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
-		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
-		       driver->name, card->irq);
+		printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq);
 		retval = -EBUSY;
 		goto err_release_region;
 	}
 	
-	cinfo->capi_ctrl = attach_capi_ctr(driver, card->name, cinfo);
-	if (!cinfo->capi_ctrl) {
-		printk(KERN_ERR "%s: attach controller failed.\n",
-		       driver->name);
-		retval = -EBUSY;
+	cinfo->capi_ctrl.driver_name   = "b1pci";
+	cinfo->capi_ctrl.driverdata    = cinfo;
+	cinfo->capi_ctrl.register_appl = b1_register_appl;
+	cinfo->capi_ctrl.release_appl  = b1_release_appl;
+	cinfo->capi_ctrl.send_message  = b1_send_message;
+	cinfo->capi_ctrl.load_firmware = b1_load_firmware;
+	cinfo->capi_ctrl.reset_ctr     = b1_reset_ctr;
+	cinfo->capi_ctrl.procinfo      = b1pci_procinfo;
+	cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+	strcpy(cinfo->capi_ctrl.name, card->name);
+	SET_MODULE_OWNER(&cinfo->capi_ctrl);
+
+	retval = attach_capi_ctr(&cinfo->capi_ctrl);
+	if (retval) {
+		printk(KERN_ERR "b1pci: attach controller failed.\n");
 		goto err_free_irq;
 	}
 
 	if (card->revision >= 4) {
-		printk(KERN_INFO
-			"%s: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n",
-			driver->name, card->port, card->irq, card->revision);
+		printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n",
+		       card->port, card->irq, card->revision);
 	} else {
-		printk(KERN_INFO
-			"%s: AVM B1 PCI at i/o %#x, irq %d, revision %d\n",
-			driver->name, card->port, card->irq, card->revision);
+		printk(KERN_INFO "b1pci: AVM B1 PCI at i/o %#x, irq %d, revision %d\n",
+		       card->port, card->irq, card->revision);
 	}
 
 	pci_set_drvdata(pdev, card);
@@ -147,29 +149,12 @@
 	b1_reset(port);
 	b1_reset(port);
 
-	detach_capi_ctr(cinfo->capi_ctrl);
+	detach_capi_ctr(&cinfo->capi_ctrl);
 	free_irq(card->irq, card);
 	release_region(card->port, AVMB1_PORTLEN);
 	b1_free_card(card);
 }
 
-/* ------------------------------------------------------------- */
-
-static struct capi_driver b1pci_driver = {
-	owner: THIS_MODULE,
-	name: "b1pci",
-	revision: "0.0",
-	load_firmware: b1_load_firmware,
-	reset_ctr: b1_reset_ctr,
-	register_appl: b1_register_appl,
-	release_appl: b1_release_appl,
-	send_message: b1_send_message,
-	
-	procinfo: b1pci_procinfo,
-	ctr_read_proc: b1ctl_read_proc,
-	driver_read_proc: 0,	/* use standard driver_read_proc */
-};
-
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
 /* ------------------------------------------------------------- */
 
@@ -192,9 +177,7 @@
 
 /* ------------------------------------------------------------- */
 
-static int b1pciv4_probe(struct capi_driver *driver,
-			 struct capicardparams *p,
-			 struct pci_dev *pdev)
+static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev)
 {
 	avmcard *card;
 	avmctrl_info *cinfo;
@@ -202,14 +185,14 @@
 
 	card = b1_alloc_card(1);
 	if (!card) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		printk(KERN_WARNING "b1pci: no memory.\n");
 		retval = -ENOMEM;
 		goto err;
 	}
 
-        card->dma = avmcard_dma_alloc(driver->name, pdev, 2048+128, 2048+128);
+        card->dma = avmcard_dma_alloc("b1pci", pdev, 2048+128, 2048+128);
 	if (!card->dma) {
-		printk(KERN_WARNING "%s: dma alloc.\n", driver->name);
+		printk(KERN_WARNING "b1pci: dma alloc.\n");
 		retval = -ENOMEM;
 		goto err_free;
 	}
@@ -222,17 +205,16 @@
 	card->cardtype = avm_b1pci;
 
 	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
-		printk(KERN_WARNING
-		       "%s: ports 0x%03x-0x%03x in use.\n",
-		       driver->name, card->port, card->port + AVMB1_PORTLEN);
+		printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n",
+		       card->port, card->port + AVMB1_PORTLEN);
 		retval = -EBUSY;
 		goto err_free_dma;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 64);
 	if (!card->mbase) {
-		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
-					driver->name, card->membase);
+		printk(KERN_NOTICE "b1pci: can't remap memory at 0x%lx\n",
+		       card->membase);
 		retval = -ENOMEM;
 		goto err_release_region;
 	}
@@ -241,8 +223,8 @@
 
 	retval = b1pciv4_detect(card);
 	if (retval) {
-		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
-					driver->name, card->port, retval);
+		printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
+		       card->port, retval);
 		retval = -ENODEV;
 		goto err_unmap;
 	}
@@ -251,24 +233,33 @@
 
 	retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
-		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
-				driver->name, card->irq);
+		printk(KERN_ERR "b1pci: unable to get IRQ %d.\n",
+		       card->irq);
 		retval = -EBUSY;
 		goto err_unmap;
 	}
 
-	cinfo->capi_ctrl = attach_capi_ctr(driver, card->name, cinfo);
-	if (!cinfo->capi_ctrl) {
-		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
-		retval = -EBUSY;
+	cinfo->capi_ctrl.driver_name   = "b1pciv4";
+	cinfo->capi_ctrl.driverdata    = cinfo;
+	cinfo->capi_ctrl.register_appl = b1dma_register_appl;
+	cinfo->capi_ctrl.release_appl  = b1dma_release_appl;
+	cinfo->capi_ctrl.send_message  = b1dma_send_message;
+	cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
+	cinfo->capi_ctrl.reset_ctr     = b1dma_reset_ctr;
+	cinfo->capi_ctrl.procinfo      = b1pciv4_procinfo;
+	cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc;
+	strcpy(cinfo->capi_ctrl.name, card->name);
+	SET_MODULE_OWNER(&cinfo->capi_ctrl);
+
+	retval = attach_capi_ctr(&cinfo->capi_ctrl);
+	if (retval) {
+		printk(KERN_ERR "b1pci: attach controller failed.\n");
 		goto err_free_irq;
 	}
-	card->cardnr = cinfo->capi_ctrl->cnr;
+	card->cardnr = cinfo->capi_ctrl.cnr;
 
-	printk(KERN_INFO
-		"%s: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n",
-		driver->name, card->port, card->irq,
-		card->membase, card->revision);
+	printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n",
+	       card->port, card->irq, card->membase, card->revision);
 
 	pci_set_drvdata(pdev, card);
 	return 0;
@@ -295,7 +286,7 @@
 
  	b1dma_reset(card);
 
-	detach_capi_ctr(cinfo->capi_ctrl);
+	detach_capi_ctr(&cinfo->capi_ctrl);
 	free_irq(card->irq, card);
 	iounmap(card->mbase);
 	release_region(card->port, AVMB1_PORTLEN);
@@ -303,74 +294,48 @@
 	b1_free_card(card);
 }
 
-/* ------------------------------------------------------------- */
-
-
-static struct capi_driver b1pciv4_driver = {
-	owner: THIS_MODULE,
-	name: "b1pciv4",
-	revision: "0.0",
-	load_firmware: b1dma_load_firmware,
-	reset_ctr: b1dma_reset_ctr,
-	register_appl: b1dma_register_appl,
-	release_appl: b1dma_release_appl,
-	send_message: b1dma_send_message,
-	
-	procinfo: b1pciv4_procinfo,
-	ctr_read_proc: b1dmactl_read_proc,
-	driver_read_proc: 0,	/* use standard driver_read_proc */
-};
-
 #endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
 
 static int __devinit b1pci_pci_probe(struct pci_dev *pdev,
 				     const struct pci_device_id *ent)
 {
-	struct capi_driver *driver = &b1pci_driver;
 	struct capicardparams param;
 	int retval;
 
 	if (pci_enable_device(pdev) < 0) {
-		printk(KERN_ERR "%s: failed to enable AVM-B1\n",
-		       driver->name);
+		printk(KERN_ERR "b1pci: failed to enable AVM-B1\n");
 		return -ENODEV;
 	}
 	param.irq = pdev->irq;
 
 	if (pci_resource_start(pdev, 2)) { /* B1 PCI V4 */
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
-		driver = &b1pciv4_driver;
-
 		pci_set_master(pdev);
 #endif
 		param.membase = pci_resource_start(pdev, 0);
 		param.port = pci_resource_start(pdev, 2);
 
-		printk(KERN_INFO
-		"%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
-		driver->name, param.port, param.irq, param.membase);
+		printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
+		       param.port, param.irq, param.membase);
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
-		retval = b1pciv4_probe(driver, &param, pdev);
+		retval = b1pciv4_probe(&param, pdev);
 #else
-		retval = b1pci_probe(driver, &param, pdev);
+		retval = b1pci_probe(&param, pdev);
 #endif
 		if (retval != 0) {
-		        printk(KERN_ERR
-			"%s: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n",
-			driver->name, param.port, param.irq, param.membase);
+		        printk(KERN_ERR "b1pci: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n",
+			       param.port, param.irq, param.membase);
 		}
 	} else {
 		param.membase = 0;
 		param.port = pci_resource_start(pdev, 1);
 
-		printk(KERN_INFO
-		"%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
-		driver->name, param.port, param.irq);
-		retval = b1pci_probe(driver, &param, pdev);
+		printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
+		       param.port, param.irq);
+		retval = b1pci_probe(&param, pdev);
 		if (retval != 0) {
-		        printk(KERN_ERR
-			"%s: no AVM-B1 at i/o %#x, irq %d detected\n",
-			driver->name, param.port, param.irq);
+		        printk(KERN_ERR "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n",
+			       param.port, param.irq);
 		}
 	}
 	return retval;
@@ -395,42 +360,12 @@
 
 static int __init b1pci_init(void)
 {
-	int retval;
-
-	b1_set_revision(&b1pci_driver, revision);
-        attach_capi_driver(&b1pci_driver);
-
-#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
-	b1_set_revision(&b1pciv4_driver, revision);
-        attach_capi_driver(&b1pciv4_driver);
-#endif
-
-	retval = pci_module_init(&b1pci_pci_driver);
-	if (retval < 0) 
-		goto err;
-
-	printk(KERN_INFO "%s: %d B1-PCI card(s) detected\n",
-	       b1pci_driver.name, retval);
-	retval = 0;
-	goto out;
-
- err:
-	detach_capi_driver(&b1pci_driver);
-#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
-	detach_capi_driver(&b1pciv4_driver);
-#endif
- out:
-	return retval;
+	return pci_module_init(&b1pci_pci_driver);
 }
 
 static void __exit b1pci_exit(void)
 {
 	pci_unregister_driver(&b1pci_pci_driver);
-
-	detach_capi_driver(&b1pci_driver);
-#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
-	detach_capi_driver(&b1pciv4_driver);
-#endif
 }
 
 module_init(b1pci_init);
diff -Nru a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c
--- a/drivers/isdn/hardware/avm/b1pcmcia.c	Wed May 29 11:43:01 2002
+++ b/drivers/isdn/hardware/avm/b1pcmcia.c	Wed May 29 11:43:01 2002
@@ -25,8 +25,6 @@
 #include <linux/isdn/capilli.h>
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.12.6.5 $";
-
 /* ------------------------------------------------------------- */
 
 MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM PCMCIA cards");
@@ -51,10 +49,12 @@
 
 /* ------------------------------------------------------------- */
 
-static int b1pcmcia_add_card(struct capi_driver *driver,
-				unsigned int port,
-				unsigned irq,
-				enum avmcardtype cardtype)
+static LIST_HEAD(cards);
+
+static char *b1pcmcia_procinfo(struct capi_ctr *ctrl);
+
+static int b1pcmcia_add_card(unsigned int port, unsigned irq,
+			     enum avmcardtype cardtype)
 {
 	avmctrl_info *cinfo;
 	avmcard *card;
@@ -63,7 +63,7 @@
 
 	card = b1_alloc_card(1);
 	if (!card) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		printk(KERN_WARNING "b1pcmcia: no memory.\n");
 		retval = -ENOMEM;
 		goto err;
 	}
@@ -80,26 +80,36 @@
 
 	retval = request_irq(card->irq, b1_interrupt, 0, card->name, card);
 	if (retval) {
-		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
-				driver->name, card->irq);
+		printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n",
+		       card->irq);
 		retval = -EBUSY;
 		goto err_free;
 	}
 	b1_reset(card->port);
 	if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
-		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
-					driver->name, card->port, retval);
+		printk(KERN_NOTICE "b1pcmcia: NO card at 0x%x (%d)\n",
+		       card->port, retval);
 		retval = -ENODEV;
 		goto err_free_irq;
 	}
 	b1_reset(card->port);
 	b1_getrevision(card);
 
-	cinfo->capi_ctrl = attach_capi_ctr(driver, card->name, cinfo);
-	if (!cinfo->capi_ctrl) {
-		printk(KERN_ERR "%s: attach controller failed.\n",
-				driver->name);
-		retval = -EBUSY;
+	cinfo->capi_ctrl.driver_name   = "b1pcmcia";
+	cinfo->capi_ctrl.driverdata    = cinfo;
+	cinfo->capi_ctrl.register_appl = b1_register_appl;
+	cinfo->capi_ctrl.release_appl  = b1_release_appl;
+	cinfo->capi_ctrl.send_message  = b1_send_message;
+	cinfo->capi_ctrl.load_firmware = b1_load_firmware;
+	cinfo->capi_ctrl.reset_ctr     = b1_reset_ctr;
+	cinfo->capi_ctrl.procinfo      = b1pcmcia_procinfo;
+	cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+	strcpy(cinfo->capi_ctrl.name, card->name);
+	SET_MODULE_OWNER(&cinfo->capi_ctrl);
+
+	retval = attach_capi_ctr(&cinfo->capi_ctrl);
+	if (retval) {
+		printk(KERN_ERR "b1pcmcia: attach controller failed.\n");
 		goto err_free_irq;
 	}
 	switch (cardtype) {
@@ -108,11 +118,11 @@
 		default    : cardname = "B1 PCMCIA"; break;
 	}
 
-	printk(KERN_INFO
-		"%s: AVM %s at i/o %#x, irq %d, revision %d\n",
-		driver->name, cardname, card->port, card->irq, card->revision);
+	printk(KERN_INFO "b1pcmcia: AVM %s at i/o %#x, irq %d, revision %d\n",
+	       cardname, card->port, card->irq, card->revision);
 
-	return cinfo->capi_ctrl->cnr;
+	list_add(&card->list, &cards);
+	return cinfo->capi_ctrl.cnr;
 
  err_free_irq:
 	free_irq(card->irq, card);
@@ -142,49 +152,30 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver b1pcmcia_driver = {
-	owner: THIS_MODULE,
-	name: "b1pcmcia",
-	revision: "0.0",
-	load_firmware: b1_load_firmware,
-	reset_ctr: b1_reset_ctr,
-	register_appl: b1_register_appl,
-	release_appl: b1_release_appl,
-	send_message: b1_send_message,
-	
-	procinfo: b1pcmcia_procinfo,
-	ctr_read_proc: b1ctl_read_proc,
-	driver_read_proc: 0,	/* use standard driver_read_proc */
-};
-
-/* ------------------------------------------------------------- */
-
 int b1pcmcia_addcard_b1(unsigned int port, unsigned irq)
 {
-	return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_b1pcmcia);
+	return b1pcmcia_add_card(port, irq, avm_b1pcmcia);
 }
 
 int b1pcmcia_addcard_m1(unsigned int port, unsigned irq)
 {
-	return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_m1);
+	return b1pcmcia_add_card(port, irq, avm_m1);
 }
 
 int b1pcmcia_addcard_m2(unsigned int port, unsigned irq)
 {
-	return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_m2);
+	return b1pcmcia_add_card(port, irq, avm_m2);
 }
 
 int b1pcmcia_delcard(unsigned int port, unsigned irq)
 {
 	struct list_head *l;
-	struct capi_ctr *ctrl;
 	avmcard *card;
 	
-	list_for_each(l, &b1pcmcia_driver.contr_head) {
-		ctrl = list_entry(l, struct capi_ctr, driver_list);
-		card = ((avmctrl_info *)(ctrl->driverdata))->card;
+	list_for_each(l, &cards) {
+		card = list_entry(l, avmcard, list);
 		if (card->port == port && card->irq == irq) {
-			b1pcmcia_remove_ctr(ctrl);
+			b1pcmcia_remove_ctr(&card->ctrlinfo[0].capi_ctrl);
 			return 0;
 		}
 	}
@@ -195,21 +186,3 @@
 EXPORT_SYMBOL(b1pcmcia_addcard_m1);
 EXPORT_SYMBOL(b1pcmcia_addcard_m2);
 EXPORT_SYMBOL(b1pcmcia_delcard);
-
-/* ------------------------------------------------------------- */
-
-static int __init b1pcmcia_init(void)
-{
-	b1_set_revision(&b1pcmcia_driver, revision);
-        attach_capi_driver(&b1pcmcia_driver);
-
-	return 0;
-}
-
-static void __exit b1pcmcia_exit(void)
-{
-	detach_capi_driver(&b1pcmcia_driver);
-}
-
-module_init(b1pcmcia_init);
-module_exit(b1pcmcia_exit);
diff -Nru a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
--- a/drivers/isdn/hardware/avm/c4.c	Wed May 29 11:43:01 2002
+++ b/drivers/isdn/hardware/avm/c4.c	Wed May 29 11:43:01 2002
@@ -29,8 +29,6 @@
 #include <linux/isdn/capilli.h>
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.1.4.1.2.1 $";
-
 #undef CONFIG_C4_DEBUG
 #undef CONFIG_C4_POLLDEBUG
 
@@ -523,7 +521,7 @@
 		DataB3Len = _get_slice(&p, card->databuf);
 		cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
 		if (cidx >= card->nlogcontr) cidx = 0;
-		ctrl = card->ctrlinfo[cidx].capi_ctrl;
+		ctrl = &card->ctrlinfo[cidx].capi_ctrl;
 
 		if (MsgLen < 30) { /* not CAPI 64Bit */
 			memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
@@ -536,7 +534,7 @@
 		} else {
 			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
 			memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
-			ctrl->handle_capimsg(ctrl, ApplId, skb);
+			capi_ctr_handle_message(ctrl, ApplId, skb);
 		}
 		break;
 
@@ -547,7 +545,7 @@
 		cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
 		if (cidx >= card->nlogcontr) cidx = 0;
 		cinfo = &card->ctrlinfo[cidx];
-		ctrl = card->ctrlinfo[cidx].capi_ctrl;
+		ctrl = &card->ctrlinfo[cidx].capi_ctrl;
 
 		if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
 			printk(KERN_ERR "%s: incoming packet dropped\n",
@@ -559,7 +557,7 @@
 						     CAPIMSG_NCCI(skb->data),
 						     CAPIMSG_MSGID(skb->data));
 
-			ctrl->handle_capimsg(ctrl, ApplId, skb);
+			capi_ctr_handle_message(ctrl, ApplId, skb);
 		}
 		break;
 
@@ -593,39 +591,37 @@
 #endif
 		if (!suppress_pollack)
 			queue_pollack(card);
-		for (cidx=0; cidx < 4; cidx++) {
-			ctrl = card->ctrlinfo[cidx].capi_ctrl;
-			if (ctrl)
-				ctrl->resume_output(ctrl);
+		for (cidx=0; cidx < card->nr_controllers; cidx++) {
+			ctrl = &card->ctrlinfo[cidx].capi_ctrl;
+			capi_ctr_resume_output(ctrl);
 		}
 		break;
 
 	case RECEIVE_STOP:
-		for (cidx=0; cidx < 4; cidx++) {
-			ctrl = card->ctrlinfo[cidx].capi_ctrl;
-			if (ctrl)
-				ctrl->suspend_output(ctrl);
+		for (cidx=0; cidx < card->nr_controllers; cidx++) {
+			ctrl = &card->ctrlinfo[cidx].capi_ctrl;
+			capi_ctr_suspend_output(ctrl);
 		}
 		break;
 
 	case RECEIVE_INIT:
 
 	        cidx = card->nlogcontr;
-		if (cidx >= 4 || !card->ctrlinfo[cidx].capi_ctrl) {
+		if (cidx >= card->nr_controllers) {
 			printk(KERN_ERR "%s: card with %d controllers ??\n",
 					card->name, cidx+1);
 			break;
 		}
 	        card->nlogcontr++;
 	        cinfo = &card->ctrlinfo[cidx];
-		ctrl = cinfo->capi_ctrl;
+		ctrl = &cinfo->capi_ctrl;
 		cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
 		b1_parse_version(cinfo);
 		printk(KERN_INFO "%s: %s-card (%s) now active\n",
 		       card->name,
 		       cinfo->version[VER_CARDTYPE],
 		       cinfo->version[VER_DRIVER]);
-		ctrl->ready(cinfo->capi_ctrl);
+		capi_ctr_ready(&cinfo->capi_ctrl);
 		break;
 
 	case RECEIVE_TASK_READY:
@@ -673,12 +669,11 @@
 		if (card->nlogcontr == 0)
 			return;
 		printk(KERN_ERR "%s: unexpected reset\n", card->name);
-                for (i=0; i < 4; i++) {
+                for (i=0; i < card->nr_controllers; i++) {
 			avmctrl_info *cinfo = &card->ctrlinfo[i];
 			memset(cinfo->version, 0, sizeof(cinfo->version));
 			capilib_release(&cinfo->ncci_head);
-			if (cinfo->capi_ctrl)
-				cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
+			capi_ctr_reseted(&cinfo->capi_ctrl);
 		}
 		card->nlogcontr = 0;
 		return;
@@ -888,11 +883,10 @@
 
  	c4_reset(card);
 
-        for (i=0; i < 4; i++) {
+        for (i=0; i < card->nr_controllers; i++) {
 		cinfo = &card->ctrlinfo[i];
 		memset(cinfo->version, 0, sizeof(cinfo->version));
-		if (cinfo->capi_ctrl)
-			cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
+		capi_ctr_reseted(&cinfo->capi_ctrl);
 	}
 	card->nlogcontr = 0;
 }
@@ -905,12 +899,9 @@
 
  	c4_reset(card);
 
-        for (i=0; i < 4; i++) {
+        for (i=0; i < card->nr_controllers; i++) {
 		cinfo = &card->ctrlinfo[i];
-		if (cinfo->capi_ctrl) {
-			detach_capi_ctr(cinfo->capi_ctrl);
-			cinfo->capi_ctrl = NULL;
-		}
+		detach_capi_ctr(&cinfo->capi_ctrl);
 	}
 
 	free_irq(card->irq, card);
@@ -1104,9 +1095,7 @@
 
 /* ------------------------------------------------------------- */
 
-static int c4_add_card(struct capi_driver *driver,
-		       struct capicardparams *p,
-                       struct pci_dev *dev,
+static int c4_add_card(struct capicardparams *p, struct pci_dev *dev,
 		       int nr_controllers)
 {
 	avmcard *card;
@@ -1116,43 +1105,42 @@
 
 	card = b1_alloc_card(nr_controllers);
 	if (!card) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		printk(KERN_WARNING "c4: no memory.\n");
 		retval = -ENOMEM;
 		goto err;
 	}
-        card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
+        card->dma = avmcard_dma_alloc("c4", dev, 2048+128, 2048+128);
 	if (!card->dma) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		printk(KERN_WARNING "c4: no memory.\n");
 		retval = -ENOMEM;
 		goto err_free;
 	}
 
-	sprintf(card->name, "%s-%x", driver->name, p->port);
+	sprintf(card->name, "c%d-%x", nr_controllers, p->port);
 	card->port = p->port;
 	card->irq = p->irq;
 	card->membase = p->membase;
 	card->cardtype = (nr_controllers == 4) ? avm_c4 : avm_c2;
 
 	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
-		printk(KERN_WARNING
-		       "%s: ports 0x%03x-0x%03x in use.\n",
-		       driver->name, card->port, card->port + AVMB1_PORTLEN);
+		printk(KERN_WARNING "c4: ports 0x%03x-0x%03x in use.\n",
+		       card->port, card->port + AVMB1_PORTLEN);
 		retval = -EBUSY;
 		goto err_free_dma;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 128);
 	if (card->mbase == 0) {
-		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
-					driver->name, card->membase);
+		printk(KERN_NOTICE "c4: can't remap memory at 0x%lx\n",
+		       card->membase);
 		retval = -EIO;
 		goto err_release_region;
 	}
 
 	retval = c4_detect(card);
 	if (retval != 0) {
-		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
-					driver->name, card->port, retval);
+		printk(KERN_NOTICE "c4: NO card at 0x%x (%d)\n",
+		       card->port, retval);
 		retval = -EIO;
 		goto err_unmap;
 	}
@@ -1160,30 +1148,40 @@
 
 	retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
-		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
-				driver->name, card->irq);
+		printk(KERN_ERR "c4: unable to get IRQ %d.\n",card->irq);
 		retval = -EBUSY;
 		goto err_unmap;
 	}
 
 	for (i=0; i < nr_controllers ; i++) {
 		cinfo = &card->ctrlinfo[i];
-		cinfo->capi_ctrl = attach_capi_ctr(driver, card->name, cinfo);
-		if (!cinfo->capi_ctrl) {
-			printk(KERN_ERR "%s: attach controller failed (%d).\n",
-					driver->name, i);
+		cinfo->capi_ctrl.driver_name   = "c4";
+		cinfo->capi_ctrl.driverdata    = cinfo;
+		cinfo->capi_ctrl.register_appl = c4_register_appl;
+		cinfo->capi_ctrl.release_appl  = c4_release_appl;
+		cinfo->capi_ctrl.send_message  = c4_send_message;
+		cinfo->capi_ctrl.load_firmware = c4_load_firmware;
+		cinfo->capi_ctrl.reset_ctr     = c4_reset_ctr;
+		cinfo->capi_ctrl.procinfo      = c4_procinfo;
+		cinfo->capi_ctrl.ctr_read_proc = c4_read_proc;
+		strcpy(cinfo->capi_ctrl.name, card->name);
+		SET_MODULE_OWNER(&cinfo->capi_ctrl);
+
+		retval = attach_capi_ctr(&cinfo->capi_ctrl);
+		if (retval) {
+			printk(KERN_ERR "c4: attach controller failed (%d).\n", i);
 			for (i--; i >= 0; i--) {
 				cinfo = &card->ctrlinfo[i];
-				detach_capi_ctr(cinfo->capi_ctrl);
+				detach_capi_ctr(&cinfo->capi_ctrl);
 			}
 			goto err_free_irq;
 		}
 		if (i == 0)
-			card->cardnr = cinfo->capi_ctrl->cnr;
+			card->cardnr = cinfo->capi_ctrl.cnr;
 	}
 
-	printk(KERN_INFO "%s: AVM C%d at i/o %#x, irq %d, mem %#lx\n",
-		driver->name, nr_controllers, card->port, card->irq,
+	printk(KERN_INFO "c4: AVM C%d at i/o %#x, irq %d, mem %#lx\n",
+	       nr_controllers, card->port, card->irq,
 	       card->membase);
 
 	return 0;
@@ -1204,47 +1202,15 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver c2_driver = {
-	owner: THIS_MODULE,
-	name: "c2",
-	revision: "0.0",
-	load_firmware: c4_load_firmware,
-	reset_ctr: c4_reset_ctr,
-	register_appl: c4_register_appl,
-	release_appl: c4_release_appl,
-	send_message: c4_send_message,
-
-	procinfo: c4_procinfo,
-	ctr_read_proc: c4_read_proc,
-	driver_read_proc: 0,	/* use standard driver_read_proc */
-};
-
-static struct capi_driver c4_driver = {
-	owner: THIS_MODULE,
-	name: "c4",
-	revision: "0.0",
-	load_firmware: c4_load_firmware,
-	reset_ctr: c4_reset_ctr,
-	register_appl: c4_register_appl,
-	release_appl: c4_release_appl,
-	send_message: c4_send_message,
-	
-	procinfo: c4_procinfo,
-	ctr_read_proc: c4_read_proc,
-	driver_read_proc: 0,	/* use standard driver_read_proc */
-};
-
 static int __devinit c4_probe(struct pci_dev *dev,
 			      const struct pci_device_id *ent)
 {
 	int nr = ent->driver_data;
-	struct capi_driver *driver = (nr == 2) ? &c2_driver : &c4_driver;
 	int retval = 0;
 	struct capicardparams param;
 
 	if (pci_enable_device(dev) < 0) {
-		printk(KERN_ERR "%s: failed to enable AVM-C%d\n",
-		       driver->name, nr);
+		printk(KERN_ERR "c4: failed to enable AVM-C%d\n", nr);
 		return -ENODEV;
 	}
 	pci_set_master(dev);
@@ -1253,15 +1219,13 @@
 	param.irq = dev->irq;
 	param.membase = pci_resource_start(dev, 0);
 	
-	printk(KERN_INFO
-	       "%s: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n",
-	       driver->name, nr, param.port, param.irq, param.membase);
+	printk(KERN_INFO "c4: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n",
+	       nr, param.port, param.irq, param.membase);
 	
-	retval = c4_add_card(driver, &param, dev, nr);
+	retval = c4_add_card(&param, dev, nr);
 	if (retval != 0) {
-		printk(KERN_ERR
-		       "%s: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n",
-		       driver->name, nr, param.port, param.irq, param.membase);
+		printk(KERN_ERR "c4: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n",
+		       nr, param.port, param.irq, param.membase);
 		return -ENODEV;
 	}
 	return 0;
@@ -1276,36 +1240,12 @@
 
 static int __init c4_init(void)
 {
-	int retval;
-
-	b1_set_revision(&c2_driver, revision);
-        attach_capi_driver(&c2_driver);
-
-	b1_set_revision(&c4_driver, revision);
-        attach_capi_driver(&c4_driver);
-
-	retval = pci_module_init(&c4_pci_driver);
-	if (retval < 0)
-		goto err;
-
-	printk(KERN_INFO "%s: %d C4/C2 card(s) detected\n",
-	       c4_driver.name, retval);
-
-	retval = 0;
-	goto out;
-
- err:
-	detach_capi_driver(&c2_driver);
-	detach_capi_driver(&c4_driver);
- out:
-	return retval;
+	return pci_module_init(&c4_pci_driver);
 }
 
 static void __exit c4_exit(void)
 {
 	pci_unregister_driver(&c4_pci_driver);
-	detach_capi_driver(&c2_driver);
-	detach_capi_driver(&c4_driver);
 }
 
 module_init(c4_init);
diff -Nru a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
--- a/drivers/isdn/hardware/avm/t1isa.c	Wed May 29 11:43:03 2002
+++ b/drivers/isdn/hardware/avm/t1isa.c	Wed May 29 11:43:03 2002
@@ -27,8 +27,6 @@
 #include <linux/isdn/capilli.h>
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.16.6.7 $";
-
 /* ------------------------------------------------------------- */
 
 MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 HEMA ISA card");
@@ -37,8 +35,6 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver t1isa_driver;
-
 static int hema_irq_table[16] =
 {0,
  0,
@@ -132,7 +128,7 @@
 {
 	avmcard *card = devptr;
 	avmctrl_info *cinfo = &card->ctrlinfo[0];
-	struct capi_ctr *ctrl = cinfo->capi_ctrl;
+	struct capi_ctr *ctrl = &cinfo->capi_ctrl;
 	unsigned char b1cmd;
 	struct sk_buff *skb;
 
@@ -165,7 +161,7 @@
 			} else {
 				memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
 				memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
-				ctrl->handle_capimsg(ctrl, ApplId, skb);
+				capi_ctr_handle_message(ctrl, ApplId, skb);
 			}
 			break;
 
@@ -183,7 +179,7 @@
 							     CAPIMSG_NCCI(skb->data),
 							     CAPIMSG_MSGID(skb->data));
 
-				ctrl->handle_capimsg(ctrl, ApplId, skb);
+				capi_ctr_handle_message(ctrl, ApplId, skb);
 			}
 			break;
 
@@ -209,11 +205,11 @@
 
 		case RECEIVE_START:
 			b1_put_byte(card->port, SEND_POLLACK);
-			ctrl->resume_output(ctrl);
+			capi_ctr_resume_output(ctrl);
 			break;
 
 		case RECEIVE_STOP:
-			ctrl->suspend_output(ctrl);
+			capi_ctr_suspend_output(ctrl);
 			break;
 
 		case RECEIVE_INIT:
@@ -224,7 +220,7 @@
 			       card->name,
 			       cinfo->version[VER_CARDTYPE],
 			       cinfo->version[VER_DRIVER]);
-			ctrl->ready(ctrl);
+			capi_ctr_ready(ctrl);
 			break;
 
 		case RECEIVE_TASK_READY:
@@ -323,21 +319,25 @@
 
 	memset(cinfo->version, 0, sizeof(cinfo->version));
 	capilib_release(&cinfo->ncci_head);
-	ctrl->reseted(ctrl);
+	capi_ctr_reseted(ctrl);
 }
 
 static void t1isa_remove(struct pci_dev *pdev)
 {
 	avmctrl_info *cinfo = pci_get_drvdata(pdev);
-	avmcard *card = cinfo->card;
-	unsigned int port = card->port;
+	avmcard *card;
+	
+	if (!cinfo)
+		return;
 
-	t1_disable_irq(port);
-	b1_reset(port);
-	b1_reset(port);
-	t1_reset(port);
+	card = cinfo->card;
 
-	detach_capi_ctr(cinfo->capi_ctrl);
+	t1_disable_irq(card->port);
+	b1_reset(card->port);
+	b1_reset(card->port);
+	t1_reset(card->port);
+
+	detach_capi_ctr(&cinfo->capi_ctrl);
 	free_irq(card->irq, card);
 	release_region(card->port, AVMB1_PORTLEN);
 	b1_free_card(card);
@@ -345,6 +345,9 @@
 
 /* ------------------------------------------------------------- */
 
+static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
+static char *t1isa_procinfo(struct capi_ctr *ctrl);
+
 static int __init t1isa_probe(struct pci_dev *pdev, int cardnr)
 {
 	avmctrl_info *cinfo;
@@ -353,7 +356,7 @@
 
 	card = b1_alloc_card(1);
 	if (!card) {
-		printk(KERN_WARNING "%s: no memory.\n", t1isa_driver.name);
+		printk(KERN_WARNING "t1isa: no memory.\n");
 		retval = -ENOMEM;
 		goto err;
 	}
@@ -366,50 +369,57 @@
 	sprintf(card->name, "t1isa-%x", card->port);
 
 	if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) {
-		printk(KERN_WARNING "%s: illegal port 0x%x.\n",
-		       t1isa_driver.name, card->port);
+		printk(KERN_WARNING "t1isa: illegal port 0x%x.\n", card->port);
 		retval = -EINVAL;
 		goto err_free;
         }
 	if (hema_irq_table[card->irq & 0xf] == 0) {
-		printk(KERN_WARNING "%s: irq %d not valid.\n",
-		       t1isa_driver.name, card->irq);
+		printk(KERN_WARNING "t1isa: irq %d not valid.\n", card->irq);
 		retval = -EINVAL;
 		goto err_free;
 	}
 	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
-		printk(KERN_INFO "%s: ports 0x%03x-0x%03x in use.\n",
-		       t1isa_driver.name, card->port, card->port + AVMB1_PORTLEN);
+		printk(KERN_INFO "t1isa: ports 0x%03x-0x%03x in use.\n",
+		       card->port, card->port + AVMB1_PORTLEN);
 		retval = -EBUSY;
 		goto err_free;
 	}
 	retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card);
 	if (retval) {
-		printk(KERN_INFO "%s: unable to get IRQ %d.\n",
-		       t1isa_driver.name, card->irq);
+		printk(KERN_INFO "t1isa: unable to get IRQ %d.\n", card->irq);
 		retval = -EBUSY;
 		goto err_release_region;
 	}
 
         if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) {
-		printk(KERN_INFO "%s: NO card at 0x%x (%d)\n",
-		       t1isa_driver.name, card->port, retval);
+		printk(KERN_INFO "t1isa: NO card at 0x%x (%d)\n",
+		       card->port, retval);
 		retval = -ENODEV;
 		goto err_free_irq;
 	}
 	t1_disable_irq(card->port);
 	b1_reset(card->port);
 
-	cinfo->capi_ctrl = attach_capi_ctr(&t1isa_driver, card->name, cinfo);
-	if (!cinfo->capi_ctrl) {
-		printk(KERN_INFO "%s: attach controller failed.\n",
-		       t1isa_driver.name);
-		retval = -EBUSY;
+	cinfo->capi_ctrl.driver_name   = "t1isa";
+	cinfo->capi_ctrl.driverdata    = cinfo;
+	cinfo->capi_ctrl.register_appl = b1_register_appl;
+	cinfo->capi_ctrl.release_appl  = b1_release_appl;
+	cinfo->capi_ctrl.send_message  = t1isa_send_message;
+	cinfo->capi_ctrl.load_firmware = t1isa_load_firmware;
+	cinfo->capi_ctrl.reset_ctr     = t1isa_reset_ctr;
+	cinfo->capi_ctrl.procinfo      = t1isa_procinfo;
+	cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+	strcpy(cinfo->capi_ctrl.name, card->name);
+	SET_MODULE_OWNER(&cinfo->capi_ctrl);
+
+	retval = attach_capi_ctr(&cinfo->capi_ctrl);
+	if (retval) {
+		printk(KERN_INFO "t1isa: attach controller failed.\n");
 		goto err_free_irq;
 	}
 
-	printk(KERN_INFO "%s: AVM T1 ISA at i/o %#x, irq %d, card %d\n",
-		t1isa_driver.name, card->port, card->irq, card->cardnr);
+	printk(KERN_INFO "t1isa: AVM T1 ISA at i/o %#x, irq %d, card %d\n",
+	       card->port, card->irq, card->cardnr);
 
 	pci_set_drvdata(pdev, cinfo);
 	return 0;
@@ -485,21 +495,6 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver t1isa_driver = {
-	owner: THIS_MODULE,
-	name: "t1isa",
-	revision: "0.0",
-	load_firmware: t1isa_load_firmware,
-	reset_ctr: t1isa_reset_ctr,
-	register_appl: b1_register_appl,
-	release_appl: b1_release_appl,
-	send_message: t1isa_send_message,
-	
-	procinfo: t1isa_procinfo,
-	ctr_read_proc: b1ctl_read_proc,
-	driver_read_proc: 0,	/* use standard driver_read_proc */
-};
-
 #define MAX_CARDS 4
 static struct pci_dev isa_dev[MAX_CARDS];
 static int io[MAX_CARDS];
@@ -515,12 +510,9 @@
 
 static int __init t1isa_init(void)
 {
-	int i, retval;
+	int i;
 	int found = 0;
 
-	b1_set_revision(&t1isa_driver, revision);
-        attach_capi_driver(&t1isa_driver);
-
 	for (i = 0; i < MAX_CARDS; i++) {
 		if (!io[i])
 			break;
@@ -531,17 +523,10 @@
 		if (t1isa_probe(&isa_dev[i], cardnr[i]) == 0)
 			found++;
 	}
-	if (found == 0) {
-		retval = -ENODEV;
-		goto err;
-	}
-	retval = 0;
-	goto out;
+	if (found == 0)
+		return -ENODEV;
 
- err:
-	detach_capi_driver(&t1isa_driver);
- out:
-	return retval;
+	return 0;
 }
 
 static void __exit t1isa_exit(void)
@@ -554,7 +539,6 @@
 
 		t1isa_remove(&isa_dev[i]);
 	}
-	detach_capi_driver(&t1isa_driver);
 }
 
 module_init(t1isa_init);
diff -Nru a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c
--- a/drivers/isdn/hardware/avm/t1pci.c	Wed May 29 11:43:01 2002
+++ b/drivers/isdn/hardware/avm/t1pci.c	Wed May 29 11:43:01 2002
@@ -26,8 +26,6 @@
 #include <linux/isdn/capilli.h>
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.1.4.1.2.1 $";
-
 #undef CONFIG_T1PCI_DEBUG
 #undef CONFIG_T1PCI_POLLDEBUG
 
@@ -45,9 +43,9 @@
 
 /* ------------------------------------------------------------- */
 
-static int t1pci_add_card(struct capi_driver *driver,
-                          struct capicardparams *p,
-	                  struct pci_dev *pdev)
+static char *t1pci_procinfo(struct capi_ctr *ctrl);
+
+static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev)
 {
 	avmcard *card;
 	avmctrl_info *cinfo;
@@ -55,14 +53,14 @@
 
 	card = b1_alloc_card(1);
 	if (!card) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		printk(KERN_WARNING "t1pci: no memory.\n");
 		retval = -ENOMEM;
 		goto err;
 	}
 
-        card->dma = avmcard_dma_alloc(driver->name, pdev, 2048+128, 2048+128);
+        card->dma = avmcard_dma_alloc("t1pci", pdev, 2048+128, 2048+128);
 	if (!card->dma) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		printk(KERN_WARNING "t1pci: no memory.\n");
 		retval = -ENOMEM;
 		goto err_free;
 	}
@@ -75,17 +73,16 @@
 	card->cardtype = avm_t1pci;
 
 	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
-		printk(KERN_WARNING
-		       "%s: ports 0x%03x-0x%03x in use.\n",
-		       driver->name, card->port, card->port + AVMB1_PORTLEN);
+		printk(KERN_WARNING "t1pci: ports 0x%03x-0x%03x in use.\n",
+		       card->port, card->port + AVMB1_PORTLEN);
 		retval = -EBUSY;
 		goto err_free_dma;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 64);
 	if (!card->mbase) {
-		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
-					driver->name, card->membase);
+		printk(KERN_NOTICE "t1pci: can't remap memory at 0x%lx\n",
+		       card->membase);
 		retval = -EIO;
 		goto err_release_region;
 	}
@@ -95,11 +92,11 @@
 	retval = t1pci_detect(card);
 	if (retval != 0) {
 		if (retval < 6)
-			printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
-					driver->name, card->port, retval);
+			printk(KERN_NOTICE "t1pci: NO card at 0x%x (%d)\n",
+			       card->port, retval);
 		else
-			printk(KERN_NOTICE "%s: card at 0x%x, but cabel not connected or T1 has no power (%d)\n",
-					driver->name, card->port, retval);
+			printk(KERN_NOTICE "t1pci: card at 0x%x, but cable not connected or T1 has no power (%d)\n",
+			       card->port, retval);
 		retval = -EIO;
 		goto err_unmap;
 	}
@@ -107,23 +104,33 @@
 
 	retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
-		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
-				driver->name, card->irq);
+		printk(KERN_ERR "t1pci: unable to get IRQ %d.\n", card->irq);
 		retval = -EBUSY;
 		goto err_unmap;
 	}
 
-	cinfo->capi_ctrl = attach_capi_ctr(driver, card->name, cinfo);
-	if (!cinfo->capi_ctrl) {
-		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
+	cinfo->capi_ctrl.driver_name   = "t1pci";
+	cinfo->capi_ctrl.driverdata    = cinfo;
+	cinfo->capi_ctrl.register_appl = b1dma_register_appl;
+	cinfo->capi_ctrl.release_appl  = b1dma_release_appl;
+	cinfo->capi_ctrl.send_message  = b1dma_send_message;
+	cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
+	cinfo->capi_ctrl.reset_ctr     = b1dma_reset_ctr;
+	cinfo->capi_ctrl.procinfo      = t1pci_procinfo;
+	cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc;
+	strcpy(cinfo->capi_ctrl.name, card->name);
+	SET_MODULE_OWNER(&cinfo->capi_ctrl);
+
+	retval = attach_capi_ctr(&cinfo->capi_ctrl);
+	if (retval) {
+		printk(KERN_ERR "t1pci: attach controller failed.\n");
 		retval = -EBUSY;
 		goto err_free_irq;
 	}
-	card->cardnr = cinfo->capi_ctrl->cnr;
+	card->cardnr = cinfo->capi_ctrl.cnr;
 
-	printk(KERN_INFO
-		"%s: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n",
-		driver->name, card->port, card->irq, card->membase);
+	printk(KERN_INFO "t1pci: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n",
+	       card->port, card->irq, card->membase);
 
 	pci_set_drvdata(pdev, card);
 	return 0;
@@ -151,7 +158,7 @@
 
  	b1dma_reset(card);
 
-	detach_capi_ctr(cinfo->capi_ctrl);
+	detach_capi_ctr(&cinfo->capi_ctrl);
 	free_irq(card->irq, card);
 	iounmap(card->mbase);
 	release_region(card->port, AVMB1_PORTLEN);
@@ -179,33 +186,14 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver t1pci_driver = {
-	owner: THIS_MODULE,
-	name: "t1pci",
-	revision: "0.0",
-	load_firmware: b1dma_load_firmware,
-	reset_ctr: b1dma_reset_ctr,
-	register_appl: b1dma_register_appl,
-	release_appl: b1dma_release_appl,
-	send_message: b1dma_send_message,
-	
-	procinfo: t1pci_procinfo,
-	ctr_read_proc: b1dmactl_read_proc,
-	driver_read_proc: 0,	/* use standard driver_read_proc */
-};
-
-/* ------------------------------------------------------------- */
-
 static int __devinit t1pci_probe(struct pci_dev *dev,
 				 const struct pci_device_id *ent)
 {
-	struct capi_driver *driver = &t1pci_driver;
 	struct capicardparams param;
 	int retval;
 
 	if (pci_enable_device(dev) < 0) {
-		printk(KERN_ERR	"%s: failed to enable AVM-T1-PCI\n",
-		       driver->name);
+		printk(KERN_ERR	"t1pci: failed to enable AVM-T1-PCI\n");
 		return -ENODEV;
 	}
 	pci_set_master(dev);
@@ -214,15 +202,13 @@
 	param.irq = dev->irq;
 	param.membase = pci_resource_start(dev, 0);
 
-	printk(KERN_INFO
-	       "%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
-	       driver->name, param.port, param.irq, param.membase);
+	printk(KERN_INFO "t1pci: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
+	       param.port, param.irq, param.membase);
 
-	retval = t1pci_add_card(driver, &param, dev);
+	retval = t1pci_add_card(&param, dev);
 	if (retval != 0) {
-		printk(KERN_ERR
-		       "%s: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n",
-		       driver->name, param.port, param.irq, param.membase);
+		printk(KERN_ERR "t1pci: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n",
+		       param.port, param.irq, param.membase);
 		return -ENODEV;
 	}
 	return 0;
@@ -237,30 +223,12 @@
 
 static int __init t1pci_init(void)
 {
-	int retval;
-
-	b1_set_revision(&t1pci_driver, revision);
-        attach_capi_driver(&t1pci_driver);
-
-	retval = pci_register_driver(&t1pci_pci_driver);
-	if (retval < 0)
-		goto err;
-
-	printk(KERN_INFO "%s: %d T1-PCI card(s) detected\n",
-	       t1pci_driver.name, retval);
-	retval = 0;
-	goto out;
-
- err:
-	detach_capi_driver(&t1pci_driver);
- out:
-	return retval;
+	return pci_module_init(&t1pci_pci_driver);
 }
 
 static void __exit t1pci_exit(void)
 {
 	pci_unregister_driver(&t1pci_pci_driver);
-	detach_capi_driver(&t1pci_driver);
 }
 
 module_init(t1pci_init);
diff -Nru a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
--- a/drivers/isdn/hysdn/hycapi.c	Wed May 29 11:43:01 2002
+++ b/drivers/isdn/hysdn/hycapi.c	Wed May 29 11:43:01 2002
@@ -53,8 +53,6 @@
 	return ((hycapi_applications[app_id-1].ctrl_mask & (1 << (ctrl_no-1))) != 0);
 }
 
-struct capi_driver_interface *hy_di = NULL;
-
 /******************************
 Kernel-Capi callback reset_ctr
 ******************************/     
@@ -68,7 +66,7 @@
 	printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n");
 #endif
 	capilib_release(&cinfo->ncci_head);
-	ctrl->reseted(ctrl);
+	capi_ctr_reseted(ctrl);
 }
 
 /******************************
@@ -94,7 +92,7 @@
 		return;
 	}    
 	card = cinfo->card;
-	ctrl->suspend_output(ctrl);
+	capi_ctr_suspend_output(ctrl);
 	for(i=0; i<CAPI_MAXAPPL;i++) {
 		if(hycapi_applications[i].listen_req[ctrl->cnr-1]) {
 			kfree_skb(hycapi_applications[i].listen_req[ctrl->cnr-1]);
@@ -133,7 +131,7 @@
 		/* inform upper layers we're full */
 		printk(KERN_ERR "HYSDN Card%d: CAPI-buffer overrun!\n",
 		       card->myid);	
-		ctrl->suspend_output(ctrl);
+		capi_ctr_suspend_output(ctrl);
 	}
 	cinfo->tx_skb = skb;
 	spin_unlock_irq(&cinfo->lock);
@@ -334,7 +332,7 @@
 	printk(KERN_NOTICE "hycapi_capi_release\n");
 #endif
 	if(cinfo) {
-		ctrl = cinfo->capi_ctrl;
+		ctrl = &cinfo->capi_ctrl;
 		hycapi_remove_ctr(ctrl);
 	}
 	return 0;
@@ -354,14 +352,9 @@
 	printk(KERN_NOTICE "hycapi_capi_stop\n");
 #endif
 	if(cinfo) {
-		if(cinfo->capi_ctrl) {
-			ctrl = cinfo->capi_ctrl;
-/*			ctrl->suspend_output(ctrl); */
-			ctrl->reseted(ctrl);
-
-		} else {
-			printk(KERN_NOTICE "hycapi_capi_stop: cinfo but no capi_ctrl\n");
-		}
+		ctrl = &cinfo->capi_ctrl;
+/*		ctrl->suspend_output(ctrl); */
+		capi_ctr_reseted(ctrl);
 	}
 	return 0;
 }
@@ -552,11 +545,7 @@
 	if(!cinfo) {
 		return;
 	}
-	ctrl = cinfo->capi_ctrl;
-	if(!ctrl)
-	{
-		return;
-	}
+	ctrl = &cinfo->capi_ctrl;
 	if(len < CAPI_MSG_BASELEN) {
 		printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, lenght %d!\n",
 		       card->myid, len);
@@ -635,7 +624,7 @@
 		default:
 			break;
 	}
-	ctrl->handle_capimsg(ctrl, ApplId, skb);
+	capi_ctr_handle_message(ctrl, ApplId, skb);
 }
 
 /******************************************************************
@@ -662,7 +651,7 @@
 		cinfo->out_idx = 0;	/* wrap around */
 
 	if (cinfo->sk_count-- == HYSDN_MAX_CAPI_SKB)	/* dec usage count */
-		cinfo->capi_ctrl->resume_output(cinfo->capi_ctrl);
+		capi_ctr_resume_output(&cinfo->capi_ctrl);
 	spin_unlock_irq(&cinfo->lock);
 }
 
@@ -687,22 +676,6 @@
 }
 
 
-static struct capi_driver hycapi_driver = {
-	owner: THIS_MODULE,
-	name: "hysdn",
-	revision: "0.0",
-	load_firmware: hycapi_load_firmware, 
-	reset_ctr: hycapi_reset_ctr,
-	register_appl: hycapi_register_appl,
-	release_appl: hycapi_release_appl,
-	send_message: hycapi_send_message,
-
-	procinfo: hycapi_procinfo,
-	ctr_read_proc: hycapi_read_proc,
-	driver_read_proc: 0,	/* use standard driver_read_proc */
-};
-
-
 /**********************************************************
 int hycapi_init()
 
@@ -712,16 +685,11 @@
 
 int hycapi_init()
 {
-	struct capi_driver *driver;
 	int i;
 	if(hy_di) {
 		printk(KERN_NOTICE "HyDI allready set\n");
 		return 0;
 	}
-	driver = &hycapi_driver;
-	printk(KERN_NOTICE "HYSDN: Attaching capi-driver\n");
-	attach_capi_driver(driver);
-
 	for(i=0;i<CAPI_MAXAPPL;i++) {
 		memset(&(hycapi_applications[i]), 0, sizeof(hycapi_appl));
 	}
@@ -738,16 +706,6 @@
 void 
 hycapi_cleanup(void)
 {
-	struct capi_driver *driver;
-	driver = &hycapi_driver;
-	if (!hy_di) {
-		printk(KERN_ERR "HYSDN: no capi-driver to detach (?)\n");
-		return;
-	}
-	printk(KERN_NOTICE "HYSDN: Detaching capi-driver\n");
-	detach_capi_driver(driver);
-	hy_di = 0;
-	return;
 }
 
 /********************************************************************
@@ -762,8 +720,7 @@
 	struct capi_ctr *ctrl = NULL;
 	cinfo = card->hyctrlinfo;
 	if(!cinfo) return;
-	ctrl = cinfo->capi_ctrl;
-	if(!ctrl) return;
+	ctrl = &cinfo->capi_ctrl;
 	strcpy(ctrl->manu, "Hypercope");	
 	ctrl->version.majorversion = 2;
 	ctrl->version.minorversion = 0;
@@ -791,6 +748,7 @@
 {
 	hycapictrl_info *cinfo = NULL;
 	struct capi_ctr *ctrl = NULL;
+	int retval;
 #ifdef HYCAPI_PRINTFNAMES
 	printk(KERN_NOTICE "hycapi_capi_create\n");        
 #endif
@@ -818,28 +776,34 @@
 			default: strcpy(cinfo->cardname,"HYSDN ???"); break;
 		}
 
-		cinfo->capi_ctrl = attach_capi_ctr(&hycapi_driver, 
-						   cinfo->cardname, cinfo);
-		ctrl = cinfo->capi_ctrl;
-		if (!ctrl) {
-			printk(KERN_ERR "%s: attach controller failed.\n",
-			       hycapi_driver.name);
+		ctrl = &cinfo->capi_ctrl;
+		ctrl->driver_name   = "hycapi";
+		ctrl->driverdata    = cinfo;
+		ctrl->register_appl = hycapi_register_appl;
+		ctrl->release_appl  = hycapi_release_appl;
+		ctrl->send_message  = hycapi_send_message;
+		ctrl->load_firmware = hycapi_load_firmware;
+		ctrl->reset_ctr     = hycapi_reset_ctr;
+		ctrl->procinfo      = hycapi_procinfo;
+		ctrl->ctr_read_proc = hycapi_read_proc;
+		strcpy(ctrl->name, cinfo->cardname);
+		SET_MODULE_OWNER(ctrl);
+
+		retval = attach_capi_ctr(ctrl);
+		if (retval) {
+			printk(KERN_ERR "hycapi: attach controller failed.\n");
 			return -EBUSY;
 		}
 		/* fill in the blanks: */
 		hycapi_fill_profile(card);
-		ctrl->ready(ctrl);
+		capi_ctr_ready(ctrl);
 	} else {
 		/* resume output on stopped ctrl */
-		ctrl = card->hyctrlinfo->capi_ctrl;
-		if(ctrl) {
-			hycapi_fill_profile(card);
-			ctrl->ready(ctrl);
-			hycapi_restart_internal(ctrl); 
-/*			ctrl->resume_output(ctrl); */
-		} else {
-			printk(KERN_WARNING "HYSDN: No ctrl???? How come?\n");
-		}
+		ctrl = &card->hyctrlinfo->capi_ctrl;
+		hycapi_fill_profile(card);
+		capi_ctr_ready(ctrl);
+		hycapi_restart_internal(ctrl); 
+/*		ctrl->resume_output(ctrl); */
 	}
 	return 0;
 }
diff -Nru a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h
--- a/drivers/isdn/hysdn/hysdn_defs.h	Wed May 29 11:43:02 2002
+++ b/drivers/isdn/hysdn/hysdn_defs.h	Wed May 29 11:43:02 2002
@@ -208,7 +208,7 @@
 		char infobuf[128];	/* for function procinfo */
 		
 		struct HYSDN_CARD  *card;
-		struct capi_ctr *capi_ctrl;
+		struct capi_ctr capi_ctrl;
 		struct sk_buff *skbs[HYSDN_MAX_CAPI_SKB];
 		int in_idx, out_idx;	/* indexes to buffer ring */
 		int sk_count;		/* number of buffers currently in ring */
diff -Nru a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
--- a/drivers/macintosh/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/macintosh/Makefile	Wed May 29 11:43:02 2002
@@ -1,17 +1,6 @@
 #
 # Makefile for the Macintosh-specific device drivers.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
-
-# The target object and module list name.
-
-O_TARGET	:= macintosh.o
 
 # Objects that export symbols.
 
diff -Nru a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
--- a/drivers/macintosh/mediabay.c	Wed May 29 11:43:02 2002
+++ b/drivers/macintosh/mediabay.c	Wed May 29 11:43:02 2002
@@ -555,17 +555,21 @@
 	    	break;
 	    
 	case mb_ide_waiting:
-	    	if (bay->cd_base == 0) {
+		if (bay->cd_base == 0) {
 			bay->timer = 0;
 			bay->state = mb_up;
 			MBDBG("mediabay%d: up before IDE init\n", i);
 			break;
-	    	} else if (MB_IDE_READY(i)) {
+		} else if (MB_IDE_READY(i)) {
 			bay->timer = 0;
 			bay->state = mb_up;
 			if (bay->cd_index < 0) {
+				hw_regs_t hw;
+
 				pmu_suspend();
-				bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
+				ide_init_hwif_ports(&hw, (ide_ioreg_t) bay->cd_base, (ide_ioreg_t) 0, NULL);
+				hw.irq = bay->cd_irq;
+				bay->cd_index = ide_register_hw(&hw);
 				pmu_resume();
 			}
 			if (bay->cd_index == -1) {
diff -Nru a/drivers/md/Makefile b/drivers/md/Makefile
--- a/drivers/md/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/md/Makefile	Wed May 29 11:43:01 2002
@@ -2,8 +2,6 @@
 # Makefile for the kernel software RAID and LVM drivers.
 #
 
-O_TARGET	:= mddev.o
-
 export-objs	:= md.o xor.o
 lvm-mod-objs	:= lvm.o lvm-snap.o lvm-fs.o
 
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Wed May 29 11:43:02 2002
+++ b/drivers/md/md.c	Wed May 29 11:43:02 2002
@@ -491,7 +491,7 @@
 	bio.bi_private = &event;
 	bio.bi_end_io = bi_complete;
 	submit_bio(rw, &bio);
-	run_task_queue(&tq_disk);
+	blk_run_queues();
 	wait_for_completion(&event);
 
 	return test_bit(BIO_UPTODATE, &bio.bi_flags);
@@ -2955,7 +2955,7 @@
 		run = thread->run;
 		if (run) {
 			run(thread->data);
-			run_task_queue(&tq_disk);
+			blk_run_queues();
 		}
 		if (signal_pending(current))
 			flush_curr_signals();
@@ -3411,7 +3411,7 @@
 
 		last_check = j;
 
-		run_task_queue(&tq_disk);
+		blk_run_queues();
 
 	repeat:
 		if (jiffies >= mark[last_mark] + SYNC_MARK_STEP ) {
diff -Nru a/drivers/media/Makefile b/drivers/media/Makefile
--- a/drivers/media/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/media/Makefile	Wed May 29 11:43:02 2002
@@ -1,18 +1,9 @@
 #
 # Makefile for the kernel multimedia device drivers.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
 
-subdir-y     := video radio
 mod-subdirs  := video radio
 
-O_TARGET     := media.o
-obj-y        := $(join $(subdir-y),$(subdir-y:%=/%.o))
+obj-y        := video/ radio/
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
--- a/drivers/media/radio/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/media/radio/Makefile	Wed May 29 11:43:01 2002
@@ -2,15 +2,6 @@
 # Makefile for the kernel character device drivers.
 #
 
-# Object file lists.
-
-obj-y		:=
-obj-m		:=
-obj-n		:=
-obj-		:=
-
-O_TARGET := radio.o
-
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
diff -Nru a/drivers/media/video/Makefile b/drivers/media/video/Makefile
--- a/drivers/media/video/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/media/video/Makefile	Wed May 29 11:43:02 2002
@@ -2,15 +2,6 @@
 # Makefile for the kernel character device drivers.
 #
 
-# Object file lists.
-
-obj-y		:=
-obj-m		:=
-obj-n		:=
-obj-		:=
-
-O_TARGET := video.o
-
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
diff -Nru a/drivers/message/Makefile b/drivers/message/Makefile
--- a/drivers/message/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/message/Makefile	Wed May 29 11:43:02 2002
@@ -2,8 +2,6 @@
 # Makefile for MPT based block devices
 #
 
-O_TARGET := message.o
-
 mod-subdirs := i2o fusion 
 
 obj-$(CONFIG_I2O)	+= i2o/
diff -Nru a/drivers/misc/Makefile b/drivers/misc/Makefile
--- a/drivers/misc/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/misc/Makefile	Wed May 29 11:43:03 2002
@@ -1,16 +1,5 @@
 #
 # Makefile for misc devices that really don't fit anywhere else.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
-
-O_TARGET := misc.o
 
 include $(TOPDIR)/Rules.make
-
-fastdep:
diff -Nru a/drivers/mtd/Makefile b/drivers/mtd/Makefile
--- a/drivers/mtd/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/mtd/Makefile	Wed May 29 11:43:02 2002
@@ -5,19 +5,11 @@
 # $Id: Makefile,v 1.63 2001/06/13 09:43:07 dwmw2 Exp $
 
 
-obj-y           += chips/chipslink.o maps/mapslink.o \
-			devices/devlink.o nand/nandlink.o
-obj-m           :=
-obj-n           :=
-obj-            :=
-
-O_TARGET	:= mtdlink.o
+mod-subdirs	:= chips maps devices nand
 
 export-objs	:= mtdcore.o mtdpart.o redboot.o bootldr.o afs.o
 
-mod-subdirs	:= 
-subdir-y	:= chips maps devices nand
-subdir-m	:= $(subdir-y)
+obj-y           += chips/ maps/	devices/ nand/
 
 #                       *** BIG UGLY NOTE ***
 #
diff -Nru a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile
--- a/drivers/mtd/chips/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/mtd/chips/Makefile	Wed May 29 11:43:02 2002
@@ -3,8 +3,6 @@
 #
 # $Id: Makefile,v 1.7 2001/10/05 06:53:51 dwmw2 Exp $
 
-O_TARGET	:= chipslink.o
-
 export-objs	:= chipreg.o gen_probe.o
 
 #                       *** BIG UGLY NOTE ***
diff -Nru a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
--- a/drivers/mtd/devices/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/mtd/devices/Makefile	Wed May 29 11:43:01 2002
@@ -3,8 +3,6 @@
 #
 # $Id: Makefile,v 1.4 2001/06/26 21:10:05 spse Exp $
 
-O_TARGET	:= devlink.o
-
 #                       *** BIG UGLY NOTE ***
 #
 # The removal of get_module_symbol() and replacement with
diff -Nru a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
--- a/drivers/mtd/maps/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/mtd/maps/Makefile	Wed May 29 11:43:01 2002
@@ -3,8 +3,6 @@
 #
 # $Id: Makefile,v 1.13 2001/08/16 15:16:58 rmk Exp $
 
-O_TARGET	:= mapslink.o
-
 # Chip mappings
 obj-$(CONFIG_MTD_CDB89712)      += cdb89712.o
 obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
--- a/drivers/mtd/mtdblock.c	Wed May 29 11:43:02 2002
+++ b/drivers/mtd/mtdblock.c	Wed May 29 11:43:02 2002
@@ -19,15 +19,6 @@
 #define DEVICE_NR(device) (device)
 #define LOCAL_END_REQUEST
 #include <linux/blk.h>
-/* for old kernels... */
-#ifndef QUEUE_EMPTY
-#define QUEUE_EMPTY  (!CURRENT)
-#endif
-#if LINUX_VERSION_CODE < 0x20300
-#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync)
-#else
-#define QUEUE_PLUGGED (blk_queue_plugged(QUEUE))
-#endif
 
 #ifdef CONFIG_DEVFS_FS
 #include <linux/devfs_fs_kernel.h>
@@ -486,7 +477,7 @@
 		add_wait_queue(&thr_wq, &wait);
 		set_current_state(TASK_INTERRUPTIBLE);
 		spin_lock_irq(QUEUE->queue_lock);
-		if (QUEUE_EMPTY || QUEUE_PLUGGED) {
+		if (blk_queue_empty(QUEUE) || blk_queue_plugged(QUEUE)) {
 			spin_unlock_irq(QUEUE->queue_lock);
 			schedule();
 			remove_wait_queue(&thr_wq, &wait); 
diff -Nru a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
--- a/drivers/mtd/mtdblock_ro.c	Wed May 29 11:43:03 2002
+++ b/drivers/mtd/mtdblock_ro.c	Wed May 29 11:43:03 2002
@@ -132,7 +132,7 @@
 
       mtd = __get_mtd_device(NULL, minor(current_request->rq_dev));
       if (!mtd) {
-	      printk("MTD device %d doesn't appear to exist any more\n", CURRENT_DEV);
+	      printk("MTD device %d doesn't appear to exist any more\n", DEVICE_NR(CURRENT->rq_dev));
 	      mtdblock_end_request(current_request, 0);
       }
 
diff -Nru a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
--- a/drivers/mtd/nand/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/mtd/nand/Makefile	Wed May 29 11:43:01 2002
@@ -3,8 +3,6 @@
 #
 # $Id: Makefile,v 1.5 2001/09/19 22:39:59 dwmw2 Exp $
 
-O_TARGET	:= nandlink.o
-
 export-objs	:= nand.o nand_ecc.o
 
 nandobjs-y			:= nand.o
diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/net/Makefile	Wed May 29 11:43:02 2002
@@ -1,17 +1,9 @@
-# File: drivers/net/Makefile
 #
 # Makefile for the Linux network (ethercard) device drivers.
 #
 
-obj-y           :=
-obj-m           :=
-obj-n           :=
-obj-            :=
-
 mod-subdirs     := appletalk arcnet fc irda tokenring tulip pcmcia wireless \
 		   wan ../acorn/net
-
-O_TARGET := net.o
 
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
diff -Nru a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
--- a/drivers/net/irda/irda-usb.c	Wed May 29 11:43:03 2002
+++ b/drivers/net/irda/irda-usb.c	Wed May 29 11:43:03 2002
@@ -690,7 +690,6 @@
  * The way I see it is that if we submit more than one Rx URB at a
  * time, the Rx URB can be automatically re-submitted after the
  * completion handler is called.
- * We make sure to disable this feature by setting urb->next to NULL
  *
  * My take is that it's a questionable feature, and quite difficult
  * to control and to make work effectively.
@@ -754,7 +753,6 @@
 	/* Note : unlink *must* be synchronous because of the code in 
 	 * irda_usb_net_close() -> free the skb - Jean II */
 	urb->status = 0;
-	urb->next = NULL;	/* Don't auto resubmit URBs */
 
 	/* Can be called from irda_usb_receive (irq handler) -> GFP_ATOMIC */
 	ret = usb_submit_urb(urb, GFP_ATOMIC);
diff -Nru a/drivers/net/tulip/Config.in b/drivers/net/tulip/Config.in
--- a/drivers/net/tulip/Config.in	Wed May 29 11:43:03 2002
+++ b/drivers/net/tulip/Config.in	Wed May 29 11:43:03 2002
@@ -3,7 +3,7 @@
 #
 
 mainmenu_option next_comment
-comment '"Tulip" family network device support'
+comment 'Tulip family network device support'
 
 bool '"Tulip" family network device support' CONFIG_NET_TULIP
 if [ "$CONFIG_NET_TULIP" = "y" ]; then
diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
--- a/drivers/net/wireless/airo.c	Wed May 29 11:43:01 2002
+++ b/drivers/net/wireless/airo.c	Wed May 29 11:43:01 2002
@@ -1146,6 +1146,8 @@
 	kfree( dev );
 }
 
+EXPORT_SYMBOL(stop_airo_card);
+
 static int add_airo_dev( struct net_device *dev );
 
 struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
@@ -1239,7 +1241,9 @@
 	return NULL;
 }
 
-int waitbusy (struct airo_info *ai) {
+EXPORT_SYMBOL(init_airo_card);
+
+static int waitbusy (struct airo_info *ai) {
 	int delay = 0;
 	while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) {
 		udelay (10);
@@ -1283,7 +1287,9 @@
 	return 0;
 }
 
-int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
+EXPORT_SYMBOL(reset_airo_card);
+
+static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
 {
 	memcpy(haddr, skb->mac.raw + 10, ETH_ALEN);
 	return ETH_ALEN;
diff -Nru a/drivers/parport/Makefile b/drivers/parport/Makefile
--- a/drivers/parport/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/parport/Makefile	Wed May 29 11:43:01 2002
@@ -1,15 +1,6 @@
 #
 # Makefile for the kernel Parallel port device drivers.
 #
-# Note! Parport is the Borg.  We have assimilated some other
-# drivers in the `char', `net' and `scsi' directories,
-# but left them there to allay suspicion.
-#
-# 7 October 2000, Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
-# Rewritten to use lists instead of if-statements.
-#
-
-O_TARGET := driver.o
 
 export-objs	:= init.o parport_pc.o
 
diff -Nru a/drivers/pci/Makefile b/drivers/pci/Makefile
--- a/drivers/pci/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/pci/Makefile	Wed May 29 11:43:03 2002
@@ -1,15 +1,6 @@
 #
 # Makefile for the PCI bus specific drivers.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now inherited from the
-# parent makefile.
-#
-
-O_TARGET := driver.o
 
 export-objs := access.o hotplug.o pci-driver.o pci.o pool.o probe.o proc.o search.o
 
diff -Nru a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
--- a/drivers/pci/hotplug.c	Wed May 29 11:43:03 2002
+++ b/drivers/pci/hotplug.c	Wed May 29 11:43:03 2002
@@ -2,7 +2,6 @@
 #include <linux/module.h>
 #include <linux/kmod.h>		/* for hotplug_path */
 
-extern struct list_head pci_drivers;
 extern int pci_announce_device(struct pci_driver *drv, struct pci_dev *dev);
 
 #ifndef FALSE
@@ -61,7 +60,7 @@
 {
 	struct list_head *ln;
 
-	for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
+	for(ln=pci_bus_type.drivers.next; ln != &pci_bus_type.drivers; ln=ln->next) {
 		struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
 		if (drv->remove && pci_announce_device(drv, dev))
 			break;
diff -Nru a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
--- a/drivers/pci/pci-driver.c	Wed May 29 11:43:03 2002
+++ b/drivers/pci/pci-driver.c	Wed May 29 11:43:03 2002
@@ -10,8 +10,6 @@
  *  Registration of PCI drivers and handling of hot-pluggable devices.
  */
 
-LIST_HEAD(pci_drivers);
-
 /**
  * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
  * @ids: array of PCI device id structures to search in
@@ -61,6 +59,57 @@
 	return ret;
 }
 
+
+static int pci_device_probe(struct device * dev)
+{
+	int error = 0;
+
+	struct pci_driver * drv = list_entry(dev->driver,struct pci_driver,driver);
+	struct pci_dev * pci_dev = list_entry(dev,struct pci_dev,dev);
+
+	if (drv->probe)
+		error = drv->probe(pci_dev,NULL);
+	printk("%s: returning %d\n",__FUNCTION__,error);
+	return error > 0 ? 0 : -ENODEV;
+}
+
+static int pci_device_remove(struct device * dev, u32 flags)
+{
+	struct pci_dev * pci_dev = list_entry(dev,struct pci_dev,dev);
+
+	if (dev->driver) {
+		struct pci_driver * drv = list_entry(dev->driver,struct pci_driver,driver);
+		if (drv->remove)
+			drv->remove(pci_dev);
+	}
+	return 0;
+}
+
+static int pci_device_suspend(struct device * dev, u32 state, u32 level)
+{
+	struct pci_dev * pci_dev = (struct pci_dev *)list_entry(dev,struct pci_dev,dev);
+	int error = 0;
+
+	if (pci_dev->driver) {
+		if (level == SUSPEND_SAVE_STATE && pci_dev->driver->save_state)
+			error = pci_dev->driver->save_state(pci_dev,state);
+		else if (level == SUSPEND_POWER_DOWN && pci_dev->driver->suspend)
+			error = pci_dev->driver->suspend(pci_dev,state);
+	}
+	return error;
+}
+
+static int pci_device_resume(struct device * dev, u32 level)
+{
+	struct pci_dev * pci_dev = (struct pci_dev *)list_entry(dev,struct pci_dev,dev);
+
+	if (pci_dev->driver) {
+		if (level == RESUME_POWER_ON && pci_dev->driver->resume)
+			pci_dev->driver->resume(pci_dev);
+	}
+	return 0;
+}
+
 /**
  * pci_register_driver - register a new pci driver
  * @drv: the driver structure to register
@@ -73,15 +122,25 @@
 int
 pci_register_driver(struct pci_driver *drv)
 {
-	struct pci_dev *dev;
 	int count = 0;
+	struct pci_dev * dev;
+
+	/* initialize common driver fields */
+	drv->driver.name = drv->name;
+	drv->driver.bus = &pci_bus_type;
+	drv->driver.probe = pci_device_probe;
+	drv->driver.resume = pci_device_resume;
+	drv->driver.suspend = pci_device_suspend;
+	drv->driver.remove = pci_device_remove;
+
+	/* register with core */
+	count = driver_register(&drv->driver);
 
-	list_add_tail(&drv->node, &pci_drivers);
 	pci_for_each_dev(dev) {
 		if (!pci_dev_driver(dev))
-			count += pci_announce_device(drv, dev);
+			pci_announce_device(drv, dev);
 	}
-	return count;
+	return count ? count : 1;
 }
 
 /**
@@ -97,16 +156,21 @@
 void
 pci_unregister_driver(struct pci_driver *drv)
 {
-	struct pci_dev *dev;
-
-	list_del(&drv->node);
-	pci_for_each_dev(dev) {
-		if (dev->driver == drv) {
-			if (drv->remove)
-				drv->remove(dev);
-			dev->driver = NULL;
-		}
+	list_t * node;
+	
+	node = drv->driver.devices.next;
+
+	while (node != &drv->driver.devices) {
+		struct device * dev = list_entry(node,struct device,driver_list);
+		struct pci_dev * pci_dev = list_entry(dev,struct pci_dev,dev);
+
+		if (drv->remove)
+			drv->remove(pci_dev);
+		pci_dev->driver = NULL;
+		dev->driver = NULL;
+		list_del_init(&dev->driver_list);
 	}
+	put_driver(&drv->driver);
 }
 
 static struct pci_driver pci_compat_driver = {
@@ -134,35 +198,16 @@
 	return NULL;
 }
 
-static int pci_device_suspend(struct device * dev, u32 state, u32 level)
-{
-	struct pci_dev * pci_dev = (struct pci_dev *)list_entry(dev,struct pci_dev,dev);
-	int error = 0;
-
-	if (pci_dev->driver) {
-		if (level == SUSPEND_SAVE_STATE && pci_dev->driver->save_state)
-			error = pci_dev->driver->save_state(pci_dev,state);
-		else if (level == SUSPEND_POWER_DOWN && pci_dev->driver->suspend)
-			error = pci_dev->driver->suspend(pci_dev,state);
-	}
-	return error;
-}
+struct bus_type pci_bus_type = {
+	name:	"pci",
+};
 
-static int pci_device_resume(struct device * dev, u32 level)
+static int __init pci_driver_init(void)
 {
-	struct pci_dev * pci_dev = (struct pci_dev *)list_entry(dev,struct pci_dev,dev);
-
-	if (pci_dev->driver) {
-		if (level == RESUME_POWER_ON && pci_dev->driver->resume)
-			pci_dev->driver->resume(pci_dev);
-	}
-	return 0;
+	return bus_register(&pci_bus_type);
 }
 
-struct device_driver pci_device_driver = {
-	suspend:	pci_device_suspend,
-	resume:		pci_device_resume,
-};
+subsys_initcall(pci_driver_init);
 
 EXPORT_SYMBOL(pci_match_device);
 EXPORT_SYMBOL(pci_register_driver);
diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c
--- a/drivers/pci/probe.c	Wed May 29 11:43:02 2002
+++ b/drivers/pci/probe.c	Wed May 29 11:43:02 2002
@@ -18,8 +18,6 @@
 LIST_HEAD(pci_root_buses);
 LIST_HEAD(pci_devices);
 
-extern struct device_driver pci_device_driver;
-
 /*
  * Translate the low bits of the PCI base
  * to the resource type
@@ -151,7 +149,6 @@
 		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
 		res->start = base;
 		res->end = limit + 0xfff;
-		res->name = child->name;
 	} else {
 		/*
 		 * Ugh. We don't know enough about this bridge. Just assume
@@ -170,7 +167,6 @@
 		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
 		res->start = base;
 		res->end = limit + 0xfffff;
-		res->name = child->name;
 	} else {
 		/* See comment above. Same thing */
 		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1);
@@ -201,7 +197,6 @@
 		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
 		res->start = base;
 		res->end = limit + 0xfffff;
-		res->name = child->name;
 	} else {
 		/* See comments above */
 		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2);
@@ -248,9 +243,11 @@
 	child->primary = parent->secondary;
 	child->subordinate = 0xff;
 
-	/* Set up default resource pointers.. */
-	for (i = 0; i < 4; i++)
+	/* Set up default resource pointers and names.. */
+	for (i = 0; i < 4; i++) {
 		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+		child->resource[i]->name = child->name;
+	}
 
 	return child;
 }
@@ -512,7 +509,7 @@
 	dev0.bus = bus;
 	dev0.sysdata = bus->sysdata;
 	dev0.dev.parent = bus->dev;
-	dev0.dev.driver = &pci_device_driver;
+	dev0.dev.bus = &pci_bus_type;
 
 	/* Go find them, Rover! */
 	for (devfn = 0; devfn < 0x100; devfn += 8) {
diff -Nru a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
--- a/drivers/pci/setup-bus.c	Wed May 29 11:43:02 2002
+++ b/drivers/pci/setup-bus.c	Wed May 29 11:43:02 2002
@@ -228,10 +228,8 @@
 			struct resource *r = &dev->resource[i];
 			unsigned long r_size;
 
-			if (!(r->flags & IORESOURCE_IO))
+			if (r->parent || !(r->flags & IORESOURCE_IO))
 				continue;
-			if (r->parent)
-				BUG();
 			r_size = r->end - r->start + 1;
 
 			if (r_size < 0x400)
@@ -283,10 +281,8 @@
 			struct resource *r = &dev->resource[i];
 			unsigned long r_size;
 
-			if ((r->flags & mask) != type)
+			if (r->parent || (r->flags & mask) != type)
 				continue;
-			if (r->parent)
-				BUG();
 			r_size = r->end - r->start + 1;
 			/* For bridges size != alignment */
 			align = (i < PCI_BRIDGE_RESOURCES) ? r_size : r->start;
diff -Nru a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
--- a/drivers/pcmcia/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/pcmcia/Makefile	Wed May 29 11:43:02 2002
@@ -2,8 +2,6 @@
 # Makefile for the kernel pcmcia subsystem (c/o David Hinds)
 #
 
-O_TARGET := pcmcia.o
-
 export-objs := ds.o cs.o yenta.o pci_socket.o
 
 obj-$(CONFIG_PCMCIA)			+= pcmcia_core.o ds.o
diff -Nru a/drivers/pnp/Makefile b/drivers/pnp/Makefile
--- a/drivers/pnp/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/pnp/Makefile	Wed May 29 11:43:01 2002
@@ -2,8 +2,6 @@
 # Makefile for the kernel Plug-and-Play device drivers.
 #
 
-O_TARGET := pnp.o
-
 export-objs := isapnp.o pnpbios_core.o
 
 isa-pnp-proc-$(CONFIG_PROC_FS) = isapnp_proc.o
diff -Nru a/drivers/s390/Makefile b/drivers/s390/Makefile
--- a/drivers/s390/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/s390/Makefile	Wed May 29 11:43:03 2002
@@ -2,14 +2,11 @@
 # Makefile for the S/390 specific device drivers
 #
 
-O_TARGET := io.o
+mod-subdirs := block char misc net
 
-subdir-y := block char misc net
-subdir-m := $(subdir-y)
-
-obj-y := s390io.o s390mach.o s390dyn.o idals.o ccwcache.o
 export-objs += ccwcache.o idals.o s390dyn.o s390io.o
 
-obj-y += $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o)
+obj-y += s390io.o s390mach.o s390dyn.o idals.o ccwcache.o
+obj-y += block/ char/ misc/ net/
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile
--- a/drivers/s390/block/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/s390/block/Makefile	Wed May 29 11:43:03 2002
@@ -2,8 +2,6 @@
 # S/390 block devices
 #
 
-O_TARGET := s390-block.o
-
 export-objs := dasd.o
 
 dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
diff -Nru a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
--- a/drivers/s390/char/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/s390/char/Makefile	Wed May 29 11:43:03 2002
@@ -2,8 +2,6 @@
 # S/390 character devices
 #
 
-O_TARGET := s390-char.o
-
 export-objs	:= hwc_rw.o
 
 tub3270-objs := tuball.o tubfs.o tubtty.o \
diff -Nru a/drivers/s390/misc/Makefile b/drivers/s390/misc/Makefile
--- a/drivers/s390/misc/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/s390/misc/Makefile	Wed May 29 11:43:03 2002
@@ -2,8 +2,6 @@
 # S/390 miscellaneous devices
 #
 
-O_TARGET := s390-misc.o
-
 obj-$(CONFIG_CHANDEV) += chandev.o
 export-objs += chandev.o
 
diff -Nru a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
--- a/drivers/s390/net/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/s390/net/Makefile	Wed May 29 11:43:02 2002
@@ -2,8 +2,6 @@
 # S/390 network devices
 #
 
-O_TARGET := s390-net.o
-
 export-objs := iucv.o fsm.o
 
 ctc-objs := ctcmain.o ctctty.o
diff -Nru a/drivers/sbus/Makefile b/drivers/sbus/Makefile
--- a/drivers/sbus/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/sbus/Makefile	Wed May 29 11:43:03 2002
@@ -1,27 +1,14 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-O_TARGET := sbus_all.o
 ifneq ($(ARCH),m68k)
 obj-y    := sbus.o dvma.o
 endif
 
-subdir-y += char
-subdir-m += char
-obj-$(CONFIG_SBUSCHAR) += char/sunchar.o
+mod-subdirs := char audio
 
-subdir-y += audio
-subdir-m += audio
-
-# This is grotty but works around some problems with modules.
-ifeq ($(CONFIG_SPARCAUDIO),y)
-obj-y += audio/sparcaudio.o
-endif
+obj-$(CONFIG_SBUSCHAR) += char/
+obj-$(CONFIG_SPARCAUDIO) += audio/
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/sbus/audio/Makefile b/drivers/sbus/audio/Makefile
--- a/drivers/sbus/audio/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/sbus/audio/Makefile	Wed May 29 11:43:02 2002
@@ -5,8 +5,6 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-O_TARGET := sparcaudio.o
-
 export-objs	:= audio.o amd7930.o dbri.o
 
 obj-$(CONFIG_SPARCAUDIO)		+= audio.o
diff -Nru a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile
--- a/drivers/sbus/char/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/sbus/char/Makefile	Wed May 29 11:43:03 2002
@@ -7,8 +7,6 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-O_TARGET := sunchar.o
-
 export-objs := su.o bbc_i2c.o
 obj-y := sunkbd.o sunkbdmap.o sunmouse.o sunserial.o zs.o
 
diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile
--- a/drivers/scsi/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/scsi/Makefile	Wed May 29 11:43:02 2002
@@ -18,9 +18,6 @@
 CFLAGS_gdth.o    = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
 CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
 
-
-O_TARGET := scsidrv.o
-
 export-objs	:= scsi_syms.o 53c700.o
 mod-subdirs	:= pcmcia ../acorn/scsi
 
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Wed May 29 11:43:01 2002
+++ b/drivers/scsi/ide-scsi.c	Wed May 29 11:43:01 2002
@@ -234,12 +234,17 @@
 	printk("]\n");
 }
 
+static inline idescsi_scsi_t *idescsi_private(struct Scsi_Host *host)
+{
+	return (idescsi_scsi_t*) &host[1];
+}
+
 static int idescsi_end_request(struct ata_device *drive, struct request *rq, int uptodate)
 {
-	idescsi_scsi_t *scsi = drive->driver_data;
+	struct Scsi_Host *host = drive->driver_data;
+	idescsi_scsi_t *scsi = idescsi_private(host);
 	struct atapi_packet_command *pc = (struct atapi_packet_command *) rq->special;
 	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
-	struct Scsi_Host *host;
 	u8 *scsi_buf;
 	unsigned long flags;
 
@@ -289,20 +294,21 @@
  */
 static ide_startstop_t idescsi_pc_intr(struct ata_device *drive, struct request *rq)
 {
-	idescsi_scsi_t *scsi = drive->driver_data;
+	struct Scsi_Host *host = drive->driver_data;
+	idescsi_scsi_t *scsi = idescsi_private(host);
 	byte status, ireason;
 	int bcount;
-	struct atapi_packet_command *pc = scsi->pc;
+	struct atapi_packet_command *pc=scsi->pc;
 	unsigned int temp;
 
 #if IDESCSI_DEBUG_LOG
 	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
-#endif
+#endif /* IDESCSI_DEBUG_LOG */
 
-	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 #if IDESCSI_DEBUG_LOG
 		printk ("ide-scsi: %s: DMA complete\n", drive->name);
-#endif
+#endif /* IDESCSI_DEBUG_LOG */
 		pc->actually_transferred=pc->request_transfer;
 		udma_stop(drive);
 	}
@@ -372,7 +378,8 @@
 
 static ide_startstop_t idescsi_transfer_pc(struct ata_device *drive, struct request *rq)
 {
-	idescsi_scsi_t *scsi = drive->driver_data;
+	struct Scsi_Host *host = drive->driver_data;
+	idescsi_scsi_t *scsi = idescsi_private(host);
 	struct atapi_packet_command *pc = scsi->pc;
 	byte ireason;
 	ide_startstop_t startstop;
@@ -397,7 +404,8 @@
 static ide_startstop_t idescsi_issue_pc(struct ata_device *drive, struct request *rq,
 		struct atapi_packet_command *pc)
 {
-	idescsi_scsi_t *scsi = drive->driver_data;
+	struct Scsi_Host *host = drive->driver_data;
+	idescsi_scsi_t *scsi = idescsi_private(host);
 	int bcount;
 	int dma_ok = 0;
 
@@ -463,36 +471,14 @@
 	MOD_DEC_USE_COUNT;
 }
 
-static struct ata_device *idescsi_drives[MAX_HWIFS * MAX_DRIVES];
-static int idescsi_initialized = 0;
-
-/*
- *	Driver initialization.
- */
-static void idescsi_setup(struct ata_device *drive, idescsi_scsi_t *scsi, int id)
-{
-	idescsi_drives[id] = drive;
-	drive->driver_data = scsi;
-	drive->ready_stat = 0;
-	memset (scsi, 0, sizeof (idescsi_scsi_t));
-	scsi->drive = drive;
-	if (drive->id && (drive->id->config & 0x0060) == 0x20)
-		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
-	set_bit(IDESCSI_TRANSFORM, &scsi->transform);
-	clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
-#if IDESCSI_DEBUG_LOG
-	set_bit(IDESCSI_LOG_CMD, &scsi->log);
-#endif
-}
-
-static int idescsi_cleanup(struct ata_device *drive)
+static int idescsi_cleanup (struct ata_device *drive)
 {
-	idescsi_scsi_t *scsi = drive->driver_data;
+	struct Scsi_Host *host = drive->driver_data;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver (drive)) {
 		return 1;
-	drive->driver_data = NULL;
-	kfree (scsi);
+	}
+	scsi_unregister(host);
 	return 0;
 }
 
@@ -522,73 +508,9 @@
 	capacity:		NULL,
 };
 
-static void idescsi_attach(struct ata_device *drive)
-{
-	idescsi_scsi_t *scsi;
-	int i, id;
-	char *req;
-	struct ata_channel *channel;
-	int unit;
-
-	if (idescsi_initialized)
-		return;
-	idescsi_initialized = 1;
-	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
-		idescsi_drives[i] = NULL;
-
-	req = drive->driver_req;
-	if (req[0] != '\0' && strcmp(req, "ide-scsi"))
-		return;
-
-	if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
-		printk(KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
-		return;
-	}
-	if (ide_register_subdriver (drive, &idescsi_driver)) {
-		printk(KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
-		kfree (scsi);
-		return;
-	}
-	for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
-	idescsi_setup (drive, scsi, id);
-
-	channel = drive->channel;
-	unit = drive - channel->drives;
-
-	ide_revalidate_disk(mk_kdev(channel->major, unit << PARTN_BITS));
-}
-
 int idescsi_detect (Scsi_Host_Template *host_template)
 {
-	struct Scsi_Host *host;
-	int id;
-	int last_lun = 0;
-
-	host_template->proc_name = "ide-scsi";
-	host = scsi_register(host_template, 0);
-	if(host == NULL)
-		return 0;
-
-	for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++)
-		last_lun = max(last_lun, idescsi_drives[id]->last_lun);
-	host->max_id = id;
-	host->max_lun = last_lun + 1;
-	host->can_queue = host->cmd_per_lun * id;
-	return 1;
-}
-
-int idescsi_release (struct Scsi_Host *host)
-{
-	struct ata_device *drive;
-	int id;
-
-	for (id = 0; id < MAX_HWIFS * MAX_DRIVES; id++) {
-		drive = idescsi_drives[id];
-		if (drive) {
-			MOD_DEC_USE_COUNT;
-		}
-	}
-	return 0;
+	return register_ata_driver(&idescsi_driver);
 }
 
 const char *idescsi_info (struct Scsi_Host *host)
@@ -598,8 +520,7 @@
 
 int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
 {
-	struct ata_device *drive = idescsi_drives[dev->id];
-	idescsi_scsi_t *scsi = drive->driver_data;
+	idescsi_scsi_t *scsi = idescsi_private(dev->host);
 
 	if (cmd == SG_SET_TRANSFORM) {
 		if (arg)
@@ -693,7 +614,8 @@
 
 static inline int should_transform(struct ata_device *drive, Scsi_Cmnd *cmd)
 {
-	idescsi_scsi_t *scsi = drive->driver_data;
+	struct Scsi_Host *host = drive->driver_data;
+	idescsi_scsi_t *scsi = idescsi_private(host);
 
 	if (major(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR)
 		return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
@@ -702,16 +624,11 @@
 
 int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
-	struct ata_device *drive = idescsi_drives[cmd->target];
-	idescsi_scsi_t *scsi;
+	idescsi_scsi_t *scsi = idescsi_private(cmd->host);
+	struct ata_device *drive = scsi->drive;
 	struct request *rq = NULL;
 	struct atapi_packet_command *pc = NULL;
 
-	if (!drive) {
-		printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target);
-		goto abort;
-	}
-	scsi = drive->driver_data;
 	pc = kmalloc(sizeof(*pc), GFP_ATOMIC);
 	rq = kmalloc(sizeof(*rq), GFP_ATOMIC);
 	if (rq == NULL || pc == NULL) {
@@ -774,7 +691,8 @@
 
 int idescsi_bios (Disk *disk, kdev_t dev, int *parm)
 {
-	struct ata_device *drive = idescsi_drives[disk->device->id];
+	idescsi_scsi_t *scsi = idescsi_private(disk->device->host);
+	struct ata_device *drive = scsi->drive;
 
 	if (drive->bios_cyl && drive->bios_head && drive->bios_sect) {
 		parm[0] = drive->bios_head;
@@ -788,7 +706,10 @@
 	module:		THIS_MODULE,
 	name:		"idescsi",
 	detect:		idescsi_detect,
-	release:	idescsi_release,
+	release:	NULL, /* unregister_ata_driver is always
+				 called before scsi_unregister_host,
+				 there never controllers left to
+				 release by that point. */
 	info:		idescsi_info,
 	ioctl:		idescsi_ioctl,
 	queuecommand:	idescsi_queue,
@@ -801,33 +722,65 @@
 	cmd_per_lun:	5,
 	use_clustering:	DISABLE_CLUSTERING,
 	emulated:	1,
+	proc_name:	"ide-scsi",
 };
 
-
-static int __init idescsi_init(void)
+/*
+ *	Driver initialization.
+ */
+static void idescsi_attach(struct ata_device *drive)
 {
-	int ret;
-	ret = ata_driver_module(&idescsi_driver);
-	scsi_register_host(&idescsi_template);
-	return 0;
-}
+	idescsi_scsi_t *scsi;
+	struct Scsi_Host *host;
 
-static void __exit exit_idescsi_module(void)
-{
-	scsi_unregister_host(&idescsi_template);
 
-#if 0
-	/* FIXME: what about this cleanup stuff here? This all should be done
-	 * on close time perhaps? */
+	if (drive->type == ATA_DISK)
+		return;
+
+	host = scsi_register(&idescsi_template, sizeof(idescsi_scsi_t));
 
-	if (idescsi_cleanup (drive)) {
-		printk ("%s: exit_idescsi_module() called while still busy\n", drive->name);
+	if(host == NULL) {
+		printk (KERN_ERR
+			"ide-scsi: %s: Can't allocate a scsi host structure\n",
+			drive->name);
+		return;
 	}
+
+	host->max_lun = drive->last_lun + 1;
+
+	if (ide_register_subdriver (drive, &idescsi_driver)) {
+		printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
+		scsi_unregister(host);
+		return;
+	}
+
+	drive->driver_data = host;
+	drive->ready_stat = 0;
+
+	scsi = idescsi_private(host);
+	memset (scsi, 0, sizeof (idescsi_scsi_t));
+	scsi->drive = drive;
+
+	if (drive->id && (drive->id->config & 0x0060) == 0x20)
+		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
+	set_bit(IDESCSI_TRANSFORM, &scsi->transform);
+	clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+#if IDESCSI_DEBUG_LOG
+	set_bit(IDESCSI_LOG_CMD, &scsi->log);
 #endif
+}
 
+static int __init init_idescsi_module(void)
+{
+	return scsi_register_host(&idescsi_template);
+}
+
+static void __exit exit_idescsi_module(void)
+{
 	unregister_ata_driver(&idescsi_driver);
+	scsi_unregister_host(&idescsi_template);
 }
 
-module_init(idescsi_init);
+module_init(init_idescsi_module);
 module_exit(exit_idescsi_module);
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/sgi/Makefile b/drivers/sgi/Makefile
--- a/drivers/sgi/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/sgi/Makefile	Wed May 29 11:43:02 2002
@@ -5,8 +5,8 @@
 #
 # Character and Audio devices for SGI machines.
 #
-subdir-y	+= char
 subdir-m	+= char
-obj-y		+= char/sgichar.o
+
+obj-y		+= char/
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/sgi/char/Makefile b/drivers/sgi/char/Makefile
--- a/drivers/sgi/char/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/sgi/char/Makefile	Wed May 29 11:43:01 2002
@@ -1,13 +1,6 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-O_TARGET := sgichar.o
 
 export-objs	:= newport.o shmiq.o sgicons.o usema.o
 obj-y		:= newport.o shmiq.o sgicons.o usema.o streamable.o
diff -Nru a/drivers/telephony/Makefile b/drivers/telephony/Makefile
--- a/drivers/telephony/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/telephony/Makefile	Wed May 29 11:43:03 2002
@@ -1,22 +1,12 @@
 #
 # Makefile for drivers/telephony
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
 
-obj-y   :=
-obj-n   :=
-obj-m   :=
-obj-    :=
 export-objs := phonedev.o ixj.o
 
 obj-$(CONFIG_PHONE) += phonedev.o
 obj-$(CONFIG_PHONE_IXJ) += ixj.o
 obj-$(CONFIG_PHONE_IXJ_PCMCIA) += ixj_pcmcia.o
-
-O_TARGET := telephony.o
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile
--- a/drivers/usb/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/usb/Makefile	Wed May 29 11:43:03 2002
@@ -2,65 +2,61 @@
 # Makefile for the kernel USB device drivers.
 #
 
-O_TARGET	:= usbdrv.o
-
 # Object files in subdirectories
 mod-subdirs	:= serial
 
-subdir-$(CONFIG_USB)		+= core
-
-subdir-$(CONFIG_USB_EHCI_HCD)		+= host
-subdir-$(CONFIG_USB_OHCI_HCD)		+= host
-subdir-$(CONFIG_USB_OHCI)		+= host
-subdir-$(CONFIG_USB_UHCI_ALT)		+= host
-subdir-$(CONFIG_USB_UHCI_HCD_ALT)	+= host
-subdir-$(CONFIG_USB_UHCI_HCD)		+= host
-subdir-$(CONFIG_USB_UHCI)		+= host
-
-subdir-$(CONFIG_USB_ACM)		+= class
-subdir-$(CONFIG_USB_AUDIO)		+= class
-subdir-$(CONFIG_USB_BLUETOOTH_TTY)	+= class
-subdir-$(CONFIG_USB_PRINTER)		+= class
-
-subdir-$(CONFIG_USB_STORAGE)	+= storage
-
-subdir-$(CONFIG_USB_HID)	+= input
-subdir-$(CONFIG_USB_KBD)	+= input
-subdir-$(CONFIG_USB_MOUSE)	+= input
-subdir-$(CONFIG_USB_WACOM)	+= input
-
-subdir-$(CONFIG_USB_DABUSB)	+= media
-subdir-$(CONFIG_USB_DSBR)	+= media
-subdir-$(CONFIG_USB_IBMCAM)	+= media
-subdir-$(CONFIG_USB_KONICAWC)	+= media
-subdir-$(CONFIG_USB_OV511)	+= media
-subdir-$(CONFIG_USB_PWC)	+= media
-subdir-$(CONFIG_USB_SE401)	+= media
-subdir-$(CONFIG_USB_STV680)	+= media
-subdir-$(CONFIG_USB_VICAM)	+= media
-
-subdir-$(CONFIG_USB_CATC)	+= net
-subdir-$(CONFIG_USB_CDCETHER)	+= net
-subdir-$(CONFIG_USB_KAWETH)	+= net
-subdir-$(CONFIG_USB_PEGASUS)	+= net
-subdir-$(CONFIG_USB_RTL8150)	+= net
-subdir-$(CONFIG_USB_USBNET)	+= net
-
-subdir-$(CONFIG_USB_DC2XX)	+= image
-subdir-$(CONFIG_USB_HPUSBSCSI)	+= image
-subdir-$(CONFIG_USB_MDC800)	+= image
-subdir-$(CONFIG_USB_MICROTEK)	+= image
-subdir-$(CONFIG_USB_SCANNER)	+= image
-
-subdir-$(CONFIG_USB_SERIAL)	+= serial
-
-subdir-$(CONFIG_USB_AUERSWALD)	+= misc
-subdir-$(CONFIG_USB_BRLVGER)	+= misc
-subdir-$(CONFIG_USB_EMI26)	+= misc
-subdir-$(CONFIG_USB_RIO500)	+= misc
-subdir-$(CONFIG_USB_TIGL)	+= misc
-subdir-$(CONFIG_USB_USS720)	+= misc
-
-obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+obj-$(CONFIG_USB)		+= core/
+obj-$(CONFIG_USB_EHCI_HCD)	+= host/
+obj-$(CONFIG_USB_OHCI_HCD)	+= host/
+obj-$(CONFIG_USB_OHCI)		+= host/
+obj-$(CONFIG_USB_SL811HS)	+= host/
+obj-$(CONFIG_USB_UHCI_ALT)	+= host/
+obj-$(CONFIG_USB_UHCI_HCD_ALT)	+= host/
+obj-$(CONFIG_USB_UHCI_HCD)	+= host/
+obj-$(CONFIG_USB_UHCI)		+= host/
+
+obj-$(CONFIG_USB_ACM)		+= class/
+obj-$(CONFIG_USB_AUDIO)		+= class/
+obj-$(CONFIG_USB_BLUETOOTH_TTY)	+= class/
+obj-$(CONFIG_USB_PRINTER)	+= class/
+
+obj-$(CONFIG_USB_STORAGE)	+= storage/
+
+obj-$(CONFIG_USB_HID)		+= input/
+obj-$(CONFIG_USB_KBD)		+= input/
+obj-$(CONFIG_USB_MOUSE)		+= input/
+obj-$(CONFIG_USB_WACOM)		+= input/
+
+obj-$(CONFIG_USB_DABUSB)	+= media/
+obj-$(CONFIG_USB_DSBR)		+= media/
+obj-$(CONFIG_USB_IBMCAM)	+= media/
+obj-$(CONFIG_USB_KONICAWC)	+= media/
+obj-$(CONFIG_USB_OV511)		+= media/
+obj-$(CONFIG_USB_PWC)		+= media/
+obj-$(CONFIG_USB_SE401)		+= media/
+obj-$(CONFIG_USB_STV680)	+= media/
+obj-$(CONFIG_USB_VICAM)		+= media/
+
+obj-$(CONFIG_USB_CATC)		+= net/
+obj-$(CONFIG_USB_CDCETHER)	+= net/
+obj-$(CONFIG_USB_KAWETH)	+= net/
+obj-$(CONFIG_USB_PEGASUS)	+= net/
+obj-$(CONFIG_USB_RTL8150)	+= net/
+obj-$(CONFIG_USB_USBNET)	+= net/
+
+obj-$(CONFIG_USB_DC2XX)		+= image/
+obj-$(CONFIG_USB_HPUSBSCSI)	+= image/
+obj-$(CONFIG_USB_MDC800)	+= image/
+obj-$(CONFIG_USB_MICROTEK)	+= image/
+obj-$(CONFIG_USB_SCANNER)	+= image/
+
+obj-$(CONFIG_USB_SERIAL)	+= serial/
+
+obj-$(CONFIG_USB_AUERSWALD)	+= misc/
+obj-$(CONFIG_USB_BRLVGER)	+= misc/
+obj-$(CONFIG_USB_EMI26)		+= misc/
+obj-$(CONFIG_USB_RIO500)	+= misc/
+obj-$(CONFIG_USB_TIGL)		+= misc/
+obj-$(CONFIG_USB_USS720)	+= misc/
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile
--- a/drivers/usb/class/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/usb/class/Makefile	Wed May 29 11:43:03 2002
@@ -3,8 +3,6 @@
 # (one step up from the misc category)
 #
 
-O_TARGET	:= class.o
-
 obj-$(CONFIG_USB_ACM)		+= cdc-acm.o
 obj-$(CONFIG_USB_AUDIO)		+= audio.o
 obj-$(CONFIG_USB_BLUETOOTH_TTY)	+= bluetty.o
diff -Nru a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
--- a/drivers/usb/core/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/usb/core/Makefile	Wed May 29 11:43:03 2002
@@ -2,8 +2,6 @@
 # Makefile for USB Core files and filesystem
 #
 
-O_TARGET	:= core.o
-
 export-objs	:= usb.o hcd.o
 
 usbcore-objs	:= usb.o usb-debug.o hub.o hcd.o
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	Wed May 29 11:43:03 2002
+++ b/drivers/usb/core/hcd.c	Wed May 29 11:43:03 2002
@@ -745,12 +745,18 @@
 
 /*-------------------------------------------------------------------------*/
 
-/*
- * usb_calc_bus_time:
+/**
+ * usb_calc_bus_time: approximate periodic transaction time in nanoseconds
+ * @speed: from dev->speed; USB_SPEED_{LOW,FULL,HIGH}
+ * @is_input: true iff the transaction sends data to the host
+ * @is_isoc: true for isochronous transactions, false for interrupt ones
+ * @bytecount: how many bytes in the transaction.
+ *
  * Returns approximate bus time in nanoseconds for a periodic transaction.
- * See USB 2.0 spec section 5.11.3
+ * See USB 2.0 spec section 5.11.3; only periodic transfers need to be
+ * scheduled in software, this function is only used for such scheduling.
  */
-static long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
+long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
 {
 	unsigned long	tmp;
 
@@ -772,14 +778,18 @@
 			return (9107L + BW_HOST_DELAY + tmp);
 		}
 	case USB_SPEED_HIGH:	/* ISOC or INTR */
-		// FIXME merge from EHCI code; caller will need to handle
-		// each part of a split separately.
-		return 0;
+		// FIXME adjust for input vs output
+		if (isoc)
+			tmp = HS_USECS (bytecount);
+		else
+			tmp = HS_USECS_ISO (bytecount);
+		return tmp;
 	default:
 		dbg ("bogus device speed!");
 		return -1;
 	}
 }
+EXPORT_SYMBOL (usb_calc_bus_time);
 
 /*
  * usb_check_bandwidth():
diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h	Wed May 29 11:43:02 2002
+++ b/drivers/usb/core/hcd.h	Wed May 29 11:43:02 2002
@@ -263,6 +263,22 @@
 
 extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
 
+/*
+ * Ceiling microseconds (typical) for that many bytes at high speed
+ * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
+ * to preallocate bandwidth)
+ */
+#define USB2_HOST_DELAY	5	/* nsec, guess */
+#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
+	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
+	+ USB2_HOST_DELAY)
+#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \
+	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
+	+ USB2_HOST_DELAY)
+
+extern long usb_calc_bus_time (int speed, int is_input,
+			int isoc, int bytecount);
+
 /*-------------------------------------------------------------------------*/
 
 extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	Wed May 29 11:43:03 2002
+++ b/drivers/usb/core/hub.c	Wed May 29 11:43:03 2002
@@ -25,6 +25,7 @@
 #endif
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/suspend.h>
 
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -1064,6 +1065,8 @@
 	/* Send me a signal to get me die (for debugging) */
 	do {
 		usb_hub_events();
+		if (current->flags & PF_FREEZE)
+			refrigerator(PF_IOTHREAD);
 		wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); 
 	} while (!signal_pending(current));
 
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Wed May 29 11:43:03 2002
+++ b/drivers/usb/core/usb.c	Wed May 29 11:43:03 2002
@@ -2032,8 +2032,8 @@
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns zero on success, or else the status code returned by the
- * underlying usb_control_msg() call.
+ * Returns the number of bytes received on success, or else the status code
+ * returned by the underlying usb_control_msg() call.
  */
 int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
 {
@@ -2073,8 +2073,8 @@
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns zero on success, or else the status code returned by the
- * underlying usb_control_msg() call.
+ * Returns the number of bytes received on success, or else the status code
+ * returned by the underlying usb_control_msg() call.
  */
 int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
 {
@@ -2100,8 +2100,8 @@
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns zero on success, or else the status code returned by the
- * underlying usb_control_msg() call.
+ * Returns the number of bytes received on success, or else the status code
+ * returned by the underlying usb_control_msg() call.
  */
 int usb_get_device_descriptor(struct usb_device *dev)
 {
@@ -2135,8 +2135,8 @@
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns zero on success, or else the status code returned by the
- * underlying usb_control_msg() call.
+ * Returns the number of bytes received on success, or else the status code
+ * returned by the underlying usb_control_msg() call.
  */
 int usb_get_status(struct usb_device *dev, int type, int target, void *data)
 {
diff -Nru a/drivers/usb/host/Config.help b/drivers/usb/host/Config.help
--- a/drivers/usb/host/Config.help	Wed May 29 11:43:03 2002
+++ b/drivers/usb/host/Config.help	Wed May 29 11:43:03 2002
@@ -89,3 +89,13 @@
   inserted in and removed from the running kernel whenever you want).
   The module will be called usb-ohci.o. If you want to compile it
   as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SL811HS
+  Say Y here if you have a SL811HS USB host controller in your system.
+
+  If you do not know what this is, please say N.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called hc_sl811.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
diff -Nru a/drivers/usb/host/Config.in b/drivers/usb/host/Config.in
--- a/drivers/usb/host/Config.in	Wed May 29 11:43:02 2002
+++ b/drivers/usb/host/Config.in	Wed May 29 11:43:02 2002
@@ -19,3 +19,6 @@
 #   define_bool CONFIG_USB_UHCI_ALT n
 #fi
 #dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
+if [ "$CONFIG_ARM" = "y" ]; then
+   dep_tristate '  SL811HS support' CONFIG_USB_SL811HS $CONFIG_USB
+fi
diff -Nru a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
--- a/drivers/usb/host/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/usb/host/Makefile	Wed May 29 11:43:03 2002
@@ -3,8 +3,6 @@
 # framework and drivers
 #
 
-O_TARGET	:= host.o
-
 obj-$(CONFIG_USB_EHCI_HCD)	+= ehci-hcd.o
 obj-$(CONFIG_USB_OHCI_HCD)	+= ohci-hcd.o
 obj-$(CONFIG_USB_UHCI_HCD)	+= usb-uhci-hcd.o
@@ -13,5 +11,6 @@
 obj-$(CONFIG_USB_UHCI)		+= usb-uhci.o
 obj-$(CONFIG_USB_UHCI_ALT)	+= uhci.o
 obj-$(CONFIG_USB_OHCI)		+= usb-ohci.o
+obj-$(CONFIG_USB_SL811HS)	+= hc_sl811.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
--- a/drivers/usb/host/ehci-dbg.c	Wed May 29 11:43:02 2002
+++ b/drivers/usb/host/ehci-dbg.c	Wed May 29 11:43:02 2002
@@ -102,8 +102,8 @@
 
 #ifdef	DEBUG
 
-#if 0
-static void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+static void __attribute__((__unused__))
+dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 	dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label,
 		qh, qh->hw_info1, qh->hw_info2,
@@ -117,15 +117,13 @@
 			qh->hw_buf [4]);
 	}
 }
-#endif
 
 static const char *const fls_strings [] =
     { "1024", "512", "256", "??" };
 
 #else
-#if 0
-static inline void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {}
-#endif
+static inline void __attribute__((__unused__))
+dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {}
 #endif	/* DEBUG */
 
 /* functions have the "wrong" filename when they're output... */
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Wed May 29 11:43:03 2002
+++ b/drivers/usb/host/ehci-hcd.c	Wed May 29 11:43:03 2002
@@ -65,6 +65,7 @@
  *
  * HISTORY:
  *
+ * 2002-05-24	Preliminary FS/LS interrupts, using scheduling shortcuts
  * 2002-05-11	Clear TT errors for FS/LS ctrl/bulk.  Fill in some other
  *	missing pieces:  enabling 64bit dma, handoff from BIOS/SMM.
  * 2002-05-07	Some error path cleanups to report better errors; wmb();
@@ -82,7 +83,7 @@
  * 2001-June	Works with usb-storage and NEC EHCI on 2.4
  */
 
-#define DRIVER_VERSION "2002-May-11"
+#define DRIVER_VERSION "2002-May-24"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
@@ -622,7 +623,10 @@
 		return 0;
 
 	case PIPE_INTERRUPT:
-		intr_deschedule (ehci, urb->start_frame, qh, urb->interval);
+		intr_deschedule (ehci, urb->start_frame, qh,
+			(urb->dev->speed == USB_SPEED_HIGH)
+			    ? urb->interval
+			    : (urb->interval << 3));
 		if (ehci->hcd.state == USB_STATE_HALT)
 			urb->status = -ESHUTDOWN;
 		qh_completions (ehci, qh, 1);
diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c	Wed May 29 11:43:02 2002
+++ b/drivers/usb/host/ehci-sched.c	Wed May 29 11:43:02 2002
@@ -33,19 +33,6 @@
  * or with "USB On The Go" additions to USB 2.0 ...)
  */
 
-/*
- * Ceiling microseconds (typical) for that many bytes at high speed
- * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
- * to preallocate bandwidth)
- */
-#define EHCI_HOST_DELAY	5	/* nsec, guess */
-#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
-	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
-	+ EHCI_HOST_DELAY)
-#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \
-	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
-	+ EHCI_HOST_DELAY)
-	
 static int ehci_get_frame (struct usb_hcd *hcd);
 
 /*-------------------------------------------------------------------------*/
@@ -124,6 +111,9 @@
 			/* is it in the S-mask? */
 			if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
 				usecs += q->qh->usecs;
+			/* ... or C-mask? */
+			if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe)))
+				usecs += q->qh->c_usecs;
 			q = &q->qh->qh_next;
 			break;
 		case Q_TYPE_FSTN:
@@ -273,6 +263,12 @@
 	unsigned	period,
 	unsigned	usecs
 ) {
+	/* complete split running into next frame?
+	 * given FSTN support, we could sometimes check...
+	 */
+	if (uframe >= 8)
+		return 0;
+
 	/*
 	 * 80% periodic == 100 usec/uframe available
 	 * convert "usecs we need" to "max already claimed" 
@@ -284,6 +280,8 @@
 
 // FIXME delete when intr_submit handles non-empty queues
 // this gives us a one intr/frame limit (vs N/uframe)
+// ... and also lets us avoid tracking split transactions
+// that might collide at a given TT/hub.
 		if (ehci->pshadow [frame].ptr)
 			return 0;
 
@@ -305,20 +303,54 @@
 	int			mem_flags
 ) {
 	unsigned		epnum, period;
-	unsigned short		usecs;
+	unsigned short		usecs, c_usecs, gap_uf;
 	unsigned long		flags;
 	struct ehci_qh		*qh;
 	struct hcd_dev		*dev;
+	int			is_input;
 	int			status = 0;
 
-	/* get endpoint and transfer data */
+	/* get endpoint and transfer/schedule data */
 	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe))
+	is_input = usb_pipein (urb->pipe);
+	if (is_input)
 		epnum |= 0x10;
-	if (urb->dev->speed != USB_SPEED_HIGH) {
-		dbg ("no intr/tt scheduling yet"); 
-		status = -ENOSYS;
-		goto done;
+
+	/*
+	 * HS interrupt transfers are simple -- only one microframe.  FS/LS
+	 * interrupt transfers involve a SPLIT in one microframe and CSPLIT
+	 * sometime later.  We need to know how much time each will be
+	 * needed in each microframe and, for FS/LS, how many microframes
+	 * separate the two in the best case.
+	 */
+	usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
+			urb->transfer_buffer_length);
+	if (urb->dev->speed == USB_SPEED_HIGH) {
+		gap_uf = 0;
+		c_usecs = 0;
+
+		/* FIXME handle HS periods of less than 1 frame. */
+		period = urb->interval >> 3;
+		if (period < 1) {
+			dbg ("intr period %d uframes, NYET!", urb->interval);
+			status = -EINVAL;
+			goto done;
+		}
+	} else {
+		/* gap is a function of full/low speed transfer times */
+		gap_uf = 1 + usb_calc_bus_time (urb->dev->speed, is_input, 0,
+				urb->transfer_buffer_length) / (125 * 1000);
+
+		/* FIXME this just approximates SPLIT/CSPLIT times */
+		if (is_input) {		// SPLIT, gap, CSPLIT+DATA
+			c_usecs = usecs + HS_USECS (0);
+			usecs = HS_USECS (1);
+		} else {		// SPLIT+DATA, gap, CSPLIT
+			usecs = usecs + HS_USECS (1);
+			c_usecs = HS_USECS (0);
+		}
+
+		period = urb->interval;
 	}
 
 	/*
@@ -339,16 +371,6 @@
 		goto done;
 	}
 
-	usecs = HS_USECS (urb->transfer_buffer_length);
-
-	/* FIXME handle HS periods of less than 1 frame. */
-	period = urb->interval >> 3;
-	if (period < 1) {
-		dbg ("intr period %d uframes, NYET!", urb->interval);
-		status = -EINVAL;
-		goto done;
-	}
-
 	spin_lock_irqsave (&ehci->lock, flags);
 
 	/* get the qh (must be empty and idle) */
@@ -392,6 +414,7 @@
 
 		qh->hw_next = EHCI_LIST_END;
 		qh->usecs = usecs;
+		qh->c_usecs = c_usecs;
 
 		urb->hcpriv = qh_get (qh);
 		status = -ENOSPC;
@@ -399,18 +422,47 @@
 		/* pick a set of schedule slots, link the QH into them */
 		do {
 			int	uframe;
+			u32	c_mask = 0;
 
 			/* pick a set of slots such that all uframes have
 			 * enough periodic bandwidth available.
-			 *
-			 * FIXME for TT splits, need uframes for start and end.
-			 * FSTNs can put end into next frame (uframes 0 or 1).
 			 */
 			frame--;
 			for (uframe = 0; uframe < 8; uframe++) {
 				if (check_period (ehci, frame, uframe,
-						period, usecs) != 0)
-					break;
+						period, usecs) == 0)
+					continue;
+
+				/* If this is a split transaction, check the
+				 * bandwidth available for the completion
+				 * too.  check both best and worst case gaps:
+				 * worst case is SPLIT near uframe end, and
+				 * CSPLIT near start ... best is vice versa.
+				 * Difference can be almost two uframe times.
+				 *
+				 * FIXME don't even bother unless we know
+				 * this TT is idle in that uframe ... right
+				 * now we know only one interrupt transfer
+				 * will be scheduled per frame, so we don't
+				 * need to update/check TT state when we
+				 * schedule a split (QH, SITD, or FSTN).
+				 *
+				 * FIXME ehci 0.96 and above can use FSTNs
+				 */
+				if (!c_usecs)
+				    	break;
+				if (check_period (ehci, frame,
+						uframe + gap_uf,
+						period, c_usecs) == 0)
+					continue;
+				if (check_period (ehci, frame,
+						uframe + gap_uf + 1,
+						period, c_usecs) == 0)
+					continue;
+
+				c_mask = 0x03 << (8 + uframe + gap_uf);
+				c_mask = cpu_to_le32 (c_mask);
+				break;
 			}
 			if (uframe == 8)
 				continue;
@@ -419,13 +471,14 @@
 			urb->start_frame = frame;
 			status = 0;
 
-			/* set S-frame mask */
-			qh->hw_info2 |= cpu_to_le32 (1 << uframe);
+			/* reset S-frame and (maybe) C-frame masks */
+			qh->hw_info2 &= ~0xffff;
+			qh->hw_info2 |= cpu_to_le32 (1 << uframe) | c_mask;
 			// dbg_qh ("Schedule INTR qh", ehci, qh);
 
 			/* stuff into the periodic schedule */
 			qh->qh_state = QH_STATE_LINKED;
-			vdbg ("qh %p usecs %d period %d starting %d.%d",
+			vdbg ("qh %p usecs %d period %d.0 starting %d.%d",
 				qh, qh->usecs, period, frame, uframe);
 			do {
 				if (unlikely (ehci->pshadow [frame].ptr != 0)) {
@@ -443,7 +496,8 @@
 			} while (frame < ehci->periodic_size);
 
 			/* update bandwidth utilization records (for usbfs) */
-			usb_claim_bandwidth (urb->dev, urb, usecs/period, 0);
+			usb_claim_bandwidth (urb->dev, urb,
+				(usecs + c_usecs) / period, 0);
 
 			/* maybe enable periodic schedule processing */
 			if (!ehci->periodic_urbs++)
@@ -557,6 +611,7 @@
 	u32		buf1;
 	unsigned	i, epnum, maxp, multi;
 	unsigned	length;
+	int		is_input;
 
 	itd->hw_next = EHCI_LIST_END;
 	itd->urb = urb;
@@ -578,7 +633,8 @@
 	 * as encoded in the ep descriptor's maxpacket field
 	 */
 	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe)) {
+	is_input = usb_pipein (urb->pipe);
+	if (is_input) {
 		maxp = urb->dev->epmaxpacketin [epnum];
 		buf1 = (1 << 11);
 	} else {
@@ -598,7 +654,7 @@
 			urb->iso_frame_desc [index].length);
 		return -ENOSPC;
 	}
-	itd->usecs = HS_USECS_ISO (length);
+	itd->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 1, length);
 
 	/* "plus" info in low order bits of buffer pointers */
 	itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
@@ -919,17 +975,9 @@
 		return flags;
 
 	/*
-	 * For now, always give the urb back to the driver ... expect it
-	 * to submit a new urb (or resubmit this), and to have another
-	 * already queued when un-interrupted transfers are needed.
-	 * No, that's not what OHCI or UHCI are now doing.
-	 *
-	 * FIXME Revisit the ISO URB model.  It's cleaner not to have all
-	 * the special case magic, but it'd be faster to reuse existing
-	 * ITD/DMA setup and schedule state.  Easy to dma_sync/complete(),
-	 * then either reschedule or, if unlinking, free and giveback().
-	 * But we can't overcommit like the full and low speed HCs do, and
-	 * there's no clean way to report an error when rescheduling...
+	 * Always give the urb back to the driver ... expect it to submit
+	 * a new urb (or resubmit this), and to have another already queued
+	 * when un-interrupted transfers are needed.
 	 *
 	 * NOTE that for now we don't accelerate ISO unlinks; they just
 	 * happen according to the current schedule.  Means a delay of
diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h	Wed May 29 11:43:02 2002
+++ b/drivers/usb/host/ehci.h	Wed May 29 11:43:02 2002
@@ -288,14 +288,11 @@
 
 	atomic_t		refcount;
 	unsigned short		usecs;		/* intr bandwidth */
+	unsigned short		c_usecs;	/* ... split completion bw */
 	short			qh_state;
 #define	QH_STATE_LINKED		1		/* HC sees this */
 #define	QH_STATE_UNLINK		2		/* HC may still see this */
 #define	QH_STATE_IDLE		3		/* HC doesn't see this */
-
-#ifdef EHCI_SOFT_RETRIES
-	int			retries;
-#endif
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
@@ -360,6 +357,9 @@
 	union ehci_shadow	sitd_next;	/* ptr to periodic q entry */
 	struct urb		*urb;
 	dma_addr_t		buf_dma;	/* buffer address */
+
+	unsigned short		usecs;		/* start bandwidth */
+	unsigned short		c_usecs;	/* completion bandwidth */
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
diff -Nru a/drivers/usb/host/hc_simple.c b/drivers/usb/host/hc_simple.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/hc_simple.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,1074 @@
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*
+ * simple generic USB HCD frontend Version 0.9.5 (10/28/2001)
+ * for embedded HCs (SL811HS)
+ * 
+ * USB URB handling, hci_ hcs_
+ * URB queueing, qu_
+ * Transfer scheduling, sh_
+ * 
+ *
+ *-------------------------------------------------------------------------*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *-------------------------------------------------------------------------*/
+
+/* main lock for urb access */
+static spinlock_t usb_urb_lock = SPIN_LOCK_UNLOCKED;
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+/* URB HCD API function layer
+ * * * */
+
+/***************************************************************************
+ * Function Name : hcs_urb_queue
+ *
+ * This function initializes the urb status and length before queueing the 
+ * urb. 
+ *
+ * Input:  hci = data structure for the host controller
+ *         urb = USB request block data structure 
+ *
+ * Return: 0 
+ **************************************************************************/
+static inline int hcs_urb_queue (hci_t * hci, struct urb * urb)
+{
+	int i;
+
+	DBGFUNC ("enter hcs_urb_queue\n");
+	if (usb_pipeisoc (urb->pipe)) {
+		DBGVERBOSE ("hcs_urb_queue: isoc pipe\n");
+		for (i = 0; i < urb->number_of_packets; i++) {
+			urb->iso_frame_desc[i].actual_length = 0;
+			urb->iso_frame_desc[i].status = -EXDEV;
+		}
+
+		/* urb->next hack : 1 .. resub, 0 .. single shot */
+		/* urb->interval = urb->next ? 1 : 0; */
+	}
+
+	urb->status = -EINPROGRESS;
+	urb->actual_length = 0;
+	urb->error_count = 0;
+
+	if (usb_pipecontrol (urb->pipe))
+		hc_flush_data_cache (hci, urb->setup_packet, 8);
+	if (usb_pipeout (urb->pipe))
+		hc_flush_data_cache (hci, urb->transfer_buffer,
+				     urb->transfer_buffer_length);
+
+	qu_queue_urb (hci, urb);
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hcs_return_urb
+ *
+ * This function the return path of URB back to the USB core. It calls the
+ * the urb complete function if exist, and also handles the resubmition of
+ * interrupt URBs.
+ *
+ * Input:  hci = data structure for the host controller
+ *         urb = USB request block data structure 
+ *         resub_ok = resubmit flag: 1 = submit urb again, 0 = not submit 
+ *
+ * Return: 0 
+ **************************************************************************/
+static int hcs_return_urb (hci_t * hci, struct urb * urb, int resub_ok)
+{
+	struct usb_device *dev = urb->dev;
+	int resubmit = 0;
+
+	DBGFUNC ("enter hcs_return_urb, urb pointer = 0x%x, "
+		 "transferbuffer point = 0x%x, "
+		 " setup packet pointer = 0x%x, context pointer = 0x%x \n",
+		 (__u32 *) urb, (__u32 *) urb->transfer_buffer,
+		 (__u32 *) urb->setup_packet, (__u32 *) urb->context);
+	if (urb_debug)
+		urb_print (urb, "RET", usb_pipeout (urb->pipe));
+
+	resubmit = urb->interval && resub_ok;
+
+	urb->dev = urb->hcpriv = NULL;
+
+	if (urb->complete) {
+		urb->complete (urb);	/* call complete */
+	}
+
+	if (resubmit) {
+		/* requeue the URB */
+		urb->dev = dev;
+		hcs_urb_queue (hci, urb);
+	} else {
+		usb_put_urb(urb);
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hci_submit_urb
+ *
+ * This function is called by the USB core API when an URB is available to
+ * process.  This function does the following
+ *
+ * 1) Check the validity of the URB
+ * 2) Parse the device number from the URB
+ * 3) Pass the URB to the root hub routine if its intended for the hub, else
+ *    queue the urb for the attached device. 
+ *
+ * Input: urb = USB request block data structure 
+ *
+ * Return: 0 if success or error code 
+ **************************************************************************/
+static int hci_submit_urb (struct urb * urb, int mem_flags)
+{
+	hci_t *hci;
+	unsigned int pipe = urb->pipe;
+	unsigned long flags;
+	int ret;
+
+	DBGFUNC ("enter hci_submit_urb, pipe = 0x%x\n", urb->pipe);
+	if (!urb->dev || !urb->dev->bus || urb->hcpriv)
+		return -EINVAL;
+
+	if (usb_endpoint_halted
+	    (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) {
+		printk ("hci_submit_urb: endpoint_halted\n");
+		return -EPIPE;
+	}
+	hci = (hci_t *) urb->dev->bus->hcpriv;
+
+	/* a request to the virtual root hub */
+	if (usb_pipedevice (pipe) == hci->rh.devnum) {
+		if (urb_debug > 1)
+			urb_print (urb, "SUB-RH", usb_pipein (pipe));
+
+		return rh_submit_urb (urb);
+	}
+
+	/* increment urb's reference count, we now control it. */
+	urb = usb_get_urb (urb);
+
+	/* queue the URB to its endpoint-queue */
+	spin_lock_irqsave (&usb_urb_lock, flags);
+	ret = hcs_urb_queue (hci, urb);
+	if (ret != 0) {
+		/* error on return */
+		DBGERR ("hci_submit_urb: return err, ret = 0x%x, urb->status = 0x%x\n",
+			ret, urb->status);
+		usb_put_urb (urb);
+	}
+
+	spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+	return ret;
+
+}
+
+/***************************************************************************
+ * Function Name : hci_unlink_urb
+ *
+ * This function mark the URB to unlink
+ *
+ * Input: urb = USB request block data structure 
+ *
+ * Return: 0 if success or error code 
+ **************************************************************************/
+static int hci_unlink_urb (struct urb * urb)
+{
+	unsigned long flags;
+	hci_t *hci;
+	DECLARE_WAITQUEUE (wait, current);
+	void *comp = NULL;
+
+	DBGFUNC ("enter hci_unlink_urb\n");
+
+	if (!urb)		/* just to be sure */
+		return -EINVAL;
+
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+
+	hci = (hci_t *) urb->dev->bus->hcpriv;
+
+	/* a request to the virtual root hub */
+	if (usb_pipedevice (urb->pipe) == hci->rh.devnum) {
+		return rh_unlink_urb (urb);
+	}
+
+	if (urb_debug)
+		urb_print (urb, "UNLINK", 1);
+
+	spin_lock_irqsave (&usb_urb_lock, flags);
+
+	if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) {
+		/* URB active? */
+
+		if (urb->transfer_flags & (USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED)) {
+			/* asynchron with callback */
+
+			list_del (&urb->urb_list);	/* relink the urb to the del list */
+			list_add (&urb->urb_list, &hci->del_list);
+			spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+		} else {
+			/* synchron without callback */
+
+			add_wait_queue (&hci->waitq, &wait);
+
+			set_current_state (TASK_UNINTERRUPTIBLE);
+			comp = urb->complete;
+			urb->complete = NULL;
+
+			list_del (&urb->urb_list);	/* relink the urb to the del list */
+			list_add (&urb->urb_list, &hci->del_list);
+
+			spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+			schedule_timeout (HZ / 50);
+
+			if (!list_empty (&urb->urb_list))
+				list_del (&urb->urb_list);
+
+			urb->complete = comp;
+			urb->hcpriv = NULL;
+			remove_wait_queue (&hci->waitq, &wait);
+		}
+	} else {
+		/* hcd does not own URB but we keep the driver happy anyway */
+		spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+		if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) {
+			urb->status = -ENOENT;
+			urb->actual_length = 0;
+			urb->complete (urb);
+			urb->status = 0;
+		} else {
+			urb->status = -ENOENT;
+		}
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hci_alloc_dev
+ *
+ * This function allocates private data space for the usb device and 
+ * initialize the endpoint descriptor heads.
+ *
+ * Input: usb_dev = pointer to the usb device 
+ *
+ * Return: 0 if success or error code 
+ **************************************************************************/
+static int hci_alloc_dev (struct usb_device *usb_dev)
+{
+	struct hci_device *dev;
+	int i;
+
+	DBGFUNC ("enter hci_alloc_dev\n");
+	dev = kmalloc (sizeof (*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	memset (dev, 0, sizeof (*dev));
+
+	for (i = 0; i < 32; i++) {
+		INIT_LIST_HEAD (&(dev->ed[i].urb_queue));
+		dev->ed[i].pipe_head = NULL;
+	}
+
+	usb_dev->hcpriv = dev;
+
+	DBGVERBOSE ("USB HC dev alloc %d bytes\n", sizeof (*dev));
+
+	return 0;
+
+}
+
+/***************************************************************************
+ * Function Name : hci_free_dev
+ *
+ * This function de-allocates private data space for the usb devic
+ *
+ * Input: usb_dev = pointer to the usb device 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int hci_free_dev (struct usb_device *usb_dev)
+{
+	DBGFUNC ("enter hci_free_dev\n");
+
+	if (usb_dev->hcpriv)
+		kfree (usb_dev->hcpriv);
+
+	usb_dev->hcpriv = NULL;
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hci_get_current_frame_number
+ *
+ * This function get the current USB frame number
+ *
+ * Input: usb_dev = pointer to the usb device 
+ *
+ * Return: frame number  
+ **************************************************************************/
+static int hci_get_current_frame_number (struct usb_device *usb_dev)
+{
+	hci_t *hci = usb_dev->bus->hcpriv;
+	DBGFUNC ("enter hci_get_current_frame_number, frame = 0x%x \r\n",
+		 hci->frame_number);
+
+	return (hci->frame_number);
+}
+
+/***************************************************************************
+ * List of all io-functions 
+ **************************************************************************/
+
+static struct usb_operations hci_device_operations = {
+	allocate:		hci_alloc_dev,
+	deallocate:		hci_free_dev,
+	get_frame_number:	hci_get_current_frame_number,
+	submit_urb:		hci_submit_urb,
+	unlink_urb:		hci_unlink_urb,
+};
+
+/***************************************************************************
+ * URB queueing:
+ * 
+ * For each type of transfer (INTR, BULK, ISO, CTRL) there is a list of 
+ * active URBs.
+ * (hci->intr_list, hci->bulk_list, hci->iso_list, hci->ctrl_list)
+ * For every endpoint the head URB of the queued URBs is linked to one of 
+ * those lists.
+ * 
+ * The rest of the queued URBs of an endpoint are linked into a 
+ * private URB list for each endpoint. (hci_dev->ed [endpoint_io].urb_queue)
+ * hci_dev->ed [endpoint_io].pipe_head .. points to the head URB which is 
+ * in one of the active URB lists.
+ * 
+ * The index of an endpoint consists of its number and its direction.
+ * 
+ * The state of an intr and iso URB is 0. 
+ * For ctrl URBs the states are US_CTRL_SETUP, US_CTRL_DATA, US_CTRL_ACK
+ * Bulk URBs states are US_BULK and US_BULK0 (with 0-len packet)
+ * 
+ **************************************************************************/
+
+/***************************************************************************
+ * Function Name : qu_urb_timeout
+ *
+ * This function is called when the URB timeout. The function unlinks the 
+ * URB. 
+ *
+ * Input: lurb: URB 
+ *
+ * Return: none  
+ **************************************************************************/
+#ifdef HC_URB_TIMEOUT
+static void qu_urb_timeout (unsigned long lurb)
+{
+	struct urb *urb = (struct urb *) lurb;
+
+	DBGFUNC ("enter qu_urb_timeout\n");
+	urb->transfer_flags |= USB_TIMEOUT_KILLED;
+	hci_unlink_urb (urb);
+}
+#endif
+
+/***************************************************************************
+ * Function Name : qu_pipeindex
+ *
+ * This function gets the index of the pipe.   
+ *
+ * Input: pipe: the urb pipe 
+ *
+ * Return: index  
+ **************************************************************************/
+static inline int qu_pipeindex (__u32 pipe)
+{
+	DBGFUNC ("enter qu_pipeindex\n");
+	return (usb_pipeendpoint (pipe) << 1) | (usb_pipecontrol (pipe) ? 0 : usb_pipeout (pipe));
+}
+
+/***************************************************************************
+ * Function Name : qu_seturbstate
+ *
+ * This function set the state of the URB.  
+ * 
+ * control pipe: 3 states -- Setup, data, status
+ * interrupt and bulk pipe: 1 state -- data    
+ *
+ * Input: urb = USB request block data structure 
+ *        state = the urb state
+ *
+ * Return: none  
+ **************************************************************************/
+static inline void qu_seturbstate (struct urb * urb, int state)
+{
+	DBGFUNC ("enter qu_seturbstate\n");
+	urb->pipe &= ~0x1f;
+	urb->pipe |= state & 0x1f;
+}
+
+/***************************************************************************
+ * Function Name : qu_urbstate
+ *
+ * This function get the current state of the URB.  
+ * 
+ * Input: urb = USB request block data structure 
+ *
+ * Return: none  
+ **************************************************************************/
+static inline int qu_urbstate (struct urb * urb)
+{
+
+	DBGFUNC ("enter qu_urbstate\n");
+
+	return urb->pipe & 0x1f;
+}
+
+/***************************************************************************
+ * Function Name : qu_queue_active_urb
+ *
+ * This function adds the urb to the appropriate active urb list and set
+ * the urb state.
+ * 
+ * There are four active lists: isochoronous list, interrupt list, 
+ * control list, and bulk list.
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *        ed = endpoint descriptor
+ *
+ * Return: none  
+ **************************************************************************/
+static inline void qu_queue_active_urb (hci_t * hci, struct urb * urb, epd_t * ed)
+{
+	int urb_state = 0;
+	DBGFUNC ("enter qu_queue_active_urb\n");
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_CONTROL:
+		list_add (&urb->urb_list, &hci->ctrl_list);
+		urb_state = US_CTRL_SETUP;
+		break;
+
+	case PIPE_BULK:
+		list_add (&urb->urb_list, &hci->bulk_list);
+		if ((urb->transfer_flags & USB_ZERO_PACKET)
+		    && urb->transfer_buffer_length > 0
+		    &&
+		    ((urb->transfer_buffer_length %
+		      usb_maxpacket (urb->dev, urb->pipe,
+				     usb_pipeout (urb->pipe))) == 0)) {
+			urb_state = US_BULK0;
+		}
+		break;
+
+	case PIPE_INTERRUPT:
+		urb->start_frame = hci->frame_number;
+		list_add (&urb->urb_list, &hci->intr_list);
+		break;
+
+	case PIPE_ISOCHRONOUS:
+		list_add (&urb->urb_list, &hci->iso_list);
+		break;
+	}
+
+#ifdef HC_URB_TIMEOUT
+	if (urb->timeout) {
+		ed->timeout.data = (unsigned long) urb;
+		ed->timeout.expires = urb->timeout + jiffies;
+		ed->timeout.function = qu_urb_timeout;
+		add_timer (&ed->timeout);
+	}
+#endif
+
+	qu_seturbstate (urb, urb_state);
+}
+
+/***************************************************************************
+ * Function Name : qu_queue_urb
+ *
+ * This function adds the urb to the endpoint descriptor list 
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *
+ * Return: none  
+ **************************************************************************/
+static int qu_queue_urb (hci_t * hci, struct urb * urb)
+{
+	struct hci_device *hci_dev = usb_to_hci (urb->dev);
+	epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)];
+
+	DBGFUNC ("Enter qu_queue_urb\n");
+
+	/* for ISOC transfers calculate start frame index */
+
+	if (usb_pipeisoc (urb->pipe) && urb->transfer_flags & USB_ISO_ASAP) {
+		urb->start_frame = ((ed->pipe_head) ? (ed->last_iso + 1) : hci_get_current_frame_number (urb-> dev) + 1) & 0xffff;
+	}
+
+	if (ed->pipe_head) {
+		__list_add (&urb->urb_list, ed->urb_queue.prev,
+			    &(ed->urb_queue));
+	} else {
+		ed->pipe_head = urb;
+		qu_queue_active_urb (hci, urb, ed);
+		if (++hci->active_urbs == 1)
+			hc_start_int (hci);
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : qu_next_urb
+ *
+ * This function removes the URB from the queue and add the next URB to 
+ * active list. 
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *        resub_ok = resubmit flag
+ *
+ * Return: pointer to the next urb  
+ **************************************************************************/
+static struct urb *qu_next_urb (hci_t * hci, struct urb * urb, int resub_ok)
+{
+	struct hci_device *hci_dev = usb_to_hci (urb->dev);
+	epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)];
+
+	DBGFUNC ("enter qu_next_urb\n");
+	list_del (&urb->urb_list);
+	INIT_LIST_HEAD (&urb->urb_list);
+	if (ed->pipe_head == urb) {
+
+#ifdef HC_URB_TIMEOUT
+		if (urb->timeout)
+			del_timer (&ed->timeout);
+#endif
+
+		if (!--hci->active_urbs)
+			hc_stop_int (hci);
+
+		if (!list_empty (&ed->urb_queue)) {
+			urb = list_entry (ed->urb_queue.next, struct urb, urb_list);
+			list_del (&urb->urb_list);
+			INIT_LIST_HEAD (&urb->urb_list);
+			ed->pipe_head = urb;
+			qu_queue_active_urb (hci, urb, ed);
+		} else {
+			ed->pipe_head = NULL;
+			urb = NULL;
+		}
+	}
+	return urb;
+}
+
+/***************************************************************************
+ * Function Name : qu_return_urb
+ *
+ * This function is part of the return path.   
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *        resub_ok = resubmit flag
+ *
+ * Return: pointer to the next urb  
+ **************************************************************************/
+static struct urb *qu_return_urb (hci_t * hci, struct urb * urb, int resub_ok)
+{
+	struct urb *next_urb;
+
+	DBGFUNC ("enter qu_return_rub\n");
+	next_urb = qu_next_urb (hci, urb, resub_ok);
+	hcs_return_urb (hci, urb, resub_ok);
+	return next_urb;
+}
+
+/***************************************************************************
+ * Function Name : sh_scan_iso_urb_list
+ *
+ * This function goes throught the isochronous urb list and schedule the 
+ * the transfer.   
+ *
+ * Note: This function has not tested yet
+ * 
+ * Input: hci = data structure for the host controller 
+ *        list_lh = pointer to the isochronous list 
+ *        frame_number = the frame number 
+ *
+ * Return: 0 = unsuccessful; 1 = successful  
+ **************************************************************************/
+static int sh_scan_iso_urb_list (hci_t * hci, struct list_head *list_lh,
+				 int frame_number)
+{
+	struct list_head *lh = list_lh->next;
+	struct urb *urb;
+
+	DBGFUNC ("enter sh_scan_iso_urb_list\n");
+	hci->td_array->len = 0;
+
+	while (lh != list_lh) {
+		urb = list_entry (lh, struct urb, urb_list);
+		lh = lh->next;
+		if (((frame_number - urb->start_frame) & 0x7ff) <
+		    urb->number_of_packets) {
+			if (!sh_add_packet (hci, urb)) {
+				return 0;
+			} else {
+				if (((frame_number -
+				      urb->start_frame) & 0x7ff) > 0x400) {
+					if (qu_urbstate (urb) > 0)
+						urb = qu_return_urb (hci, urb, 1);
+					else
+						urb = qu_next_urb (hci, urb, 1);
+
+					if (lh == list_lh && urb)
+						lh = &urb->urb_list;
+				}
+			}
+		}
+	}
+	return 1;
+}
+
+/***************************************************************************
+ * Function Name : sh_scan_urb_list
+ *
+ * This function goes through the urb list and schedule the 
+ * the transaction.   
+ * 
+ * Input: hci = data structure for the host controller 
+ *        list_lh = pointer to the isochronous list 
+ *
+ * Return: 0 = unsuccessful; 1 = successful  
+ **************************************************************************/
+static int sh_scan_urb_list (hci_t * hci, struct list_head *list_lh)
+{
+	struct list_head *lh = NULL;
+	struct urb *urb;
+
+	if (list_lh == NULL) {
+		DBGERR ("sh_scan_urb_list: error, list_lh == NULL\n");
+	}
+
+	DBGFUNC ("enter sh_scan_urb_list: frame# \n");
+
+	list_for_each (lh, list_lh) {
+		urb = list_entry (lh, struct urb, urb_list);
+		if (urb == NULL)
+			return 1;
+		if (!usb_pipeint (urb->pipe)
+		    || (((hci->frame_number - urb->start_frame)
+			 & 0x7ff) >= urb->interval)) {
+			DBGVERBOSE ("sh_scan_urb_list !INT: %d fr_no: %d int: %d pint: %d\n",
+				    urb->start_frame, hci->frame_number, urb->interval,
+				    usb_pipeint (urb->pipe));
+			if (!sh_add_packet (hci, urb)) {
+				return 0;
+			} else {
+				DBGVERBOSE ("INT: start: %d fr_no: %d int: %d pint: %d\n",
+					    urb->start_frame, hci->frame_number,
+					    urb->interval, usb_pipeint (urb->pipe));
+				urb->start_frame = hci->frame_number;
+				return 0;
+
+			}
+		}
+	}
+	return 1;
+}
+
+/***************************************************************************
+ * Function Name : sh_shedule_trans
+ *
+ * This function schedule the USB transaction.
+ * This function will process the endpoint in the following order: 
+ * interrupt, control, and bulk.    
+ * 
+ * Input: hci = data structure for the host controller 
+ *        isSOF = flag indicate if Start Of Frame has occurred 
+ *
+ * Return: 0   
+ **************************************************************************/
+static int sh_schedule_trans (hci_t * hci, int isSOF)
+{
+	int units_left = 1;
+	struct list_head *lh;
+
+	if (hci == NULL) {
+		DBGERR ("sh_schedule_trans: hci == NULL\n");
+		return 0;
+	}
+	if (hci->td_array == NULL) {
+		DBGERR ("sh_schedule_trans: hci->td_array == NULL\n");
+		return 0;
+	}
+
+	if (hci->td_array->len != 0) {
+		DBGERR ("ERROR: schedule, hci->td_array->len = 0x%x, s/b: 0\n",
+			hci->td_array->len);
+	}
+
+	/* schedule the next available interrupt transfer or the next
+	 * stage of the interrupt transfer */
+
+	if (hci->td_array->len == 0 && !list_empty (&hci->intr_list)) {
+		units_left = sh_scan_urb_list (hci, &hci->intr_list);
+	}
+
+	/* schedule the next available control transfer or the next
+	 * stage of the control transfer */
+
+	if (hci->td_array->len == 0 && !list_empty (&hci->ctrl_list) && units_left > 0) {
+		units_left = sh_scan_urb_list (hci, &hci->ctrl_list);
+	}
+
+	/* schedule the next available bulk transfer or the next
+	 * stage of the bulk transfer */
+
+	if (hci->td_array->len == 0 && !list_empty (&hci->bulk_list) && units_left > 0) {
+		sh_scan_urb_list (hci, &hci->bulk_list);
+
+		/* be fair to each BULK URB (move list head around) 
+		 * only when the new SOF happens */
+
+		lh = hci->bulk_list.next;
+		list_del (&hci->bulk_list);
+		list_add (&hci->bulk_list, lh);
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : sh_add_packet
+ *
+ * This function forms the packet and transmit the packet. This function
+ * will handle all endpoint type: isochoronus, interrupt, control, and 
+ * bulk.
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *
+ * Return: 0 = unsucessful; 1 = successful   
+ **************************************************************************/
+static int sh_add_packet (hci_t * hci, struct urb * urb)
+{
+	__u8 *data = NULL;
+	int len = 0;
+	int toggle = 0;
+	int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+	int endpoint = usb_pipeendpoint (urb->pipe);
+	int address = usb_pipedevice (urb->pipe);
+	int slow = (((urb->pipe) >> 26) & 1);
+	int out = usb_pipeout (urb->pipe);
+	int pid = 0;
+	int ret;
+	int i = 0;
+	int iso = 0;
+
+	DBGFUNC ("enter sh_add_packet\n");
+	if (maxps == 0)
+		maxps = 8;
+
+	/* calculate len, toggle bit and add the transaction */
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_ISOCHRONOUS:
+		pid = out ? PID_OUT : PID_IN;
+		iso = 1;
+		i = hci->frame_number - urb->start_frame;
+		data = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+		len = urb->iso_frame_desc[i].length;
+		break;
+
+	case PIPE_BULK:	/* BULK and BULK0 */
+	case PIPE_INTERRUPT:
+		pid = out ? PID_OUT : PID_IN;
+		len = urb->transfer_buffer_length - urb->actual_length;
+		data = urb->transfer_buffer + urb->actual_length;
+		toggle = usb_gettoggle (urb->dev, endpoint, out);
+		break;
+
+	case PIPE_CONTROL:
+		switch (qu_urbstate (urb)) {
+		case US_CTRL_SETUP:
+			len = 8;
+			pid = PID_SETUP;
+			data = urb->setup_packet;
+			toggle = 0;
+			break;
+
+		case US_CTRL_DATA:
+			if (!hci->last_packet_nak) {
+				/* The last packet received is not a nak:
+				 * reset the nak count
+				 */
+
+				hci->nakCnt = 0;
+			}
+			if (urb->transfer_buffer_length != 0) {
+				pid = out ? PID_OUT : PID_IN;
+				len = urb->transfer_buffer_length - urb->actual_length;
+				data = urb->transfer_buffer + urb->actual_length;
+				toggle = (urb->actual_length & maxps) ? 0 : 1;
+				usb_settoggle (urb->dev,
+					       usb_pipeendpoint (urb->pipe),
+					       usb_pipeout (urb->pipe), toggle);
+				break;
+			} else {
+				/* correct state and fall through */
+				qu_seturbstate (urb, US_CTRL_ACK);
+			}
+
+		case US_CTRL_ACK:
+			len = 0;
+
+			/* reply in opposite direction */
+			pid = !out ? PID_OUT : PID_IN;
+			toggle = 1;
+			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+				       usb_pipeout (urb->pipe), toggle);
+			break;
+		}
+	}
+
+	ret =
+	    hc_add_trans (hci, len, data, toggle, maxps, slow, endpoint,
+			  address, pid, iso, qu_urbstate (urb));
+
+	DBGVERBOSE ("transfer_pa: addr:%d ep:%d pid:%x tog:%x iso:%x sl:%x "
+		    "max:%d\n len:%d ret:%d data:%p left:%d\n",
+		    address, endpoint, pid, toggle, iso, slow,
+		    maxps, len, ret, data, hci->hp.units_left);
+
+	if (ret >= 0) {
+		hci->td_array->td[hci->td_array->len].urb = urb;
+		hci->td_array->td[hci->td_array->len].len = ret;
+		hci->td_array->td[hci->td_array->len].iso_index = i;
+		hci->td_array->len++;
+		hci->active_trans = 1;
+		return 1;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : cc_to_error
+ *
+ * This function maps the SL811HS hardware error code to the linux USB error
+ * code.
+ * 
+ * Input: cc = hardware error code 
+ *
+ * Return: USB error code   
+ **************************************************************************/
+static int cc_to_error (int cc)
+{
+	int errCode = 0;
+	if (cc & SL11H_STATMASK_ERROR) {
+		errCode |= -EILSEQ;
+	} else if (cc & SL11H_STATMASK_OVF) {
+		errCode |= -EOVERFLOW;
+	} else if (cc & SL11H_STATMASK_STALL) {
+		errCode |= -EPIPE;
+	}
+	return errCode;
+}
+
+/***************************************************************************
+ * Function Name : sh_done_list
+ *
+ * This function process the packet when it has done finish transfer.
+ * 
+ * 1) It handles hardware error
+ * 2) It updates the URB state
+ * 3) If the USB transaction is complete, it start the return stack path.
+ * 
+ * Input: hci = data structure for the host controller 
+ *        isExcessNak = flag tells if there excess NAK condition occurred 
+ *
+ * Return:  urb_state or -1 if the transaction has complete   
+ **************************************************************************/
+static int sh_done_list (hci_t * hci, int *isExcessNak)
+{
+	int actbytes = 0;
+	int active = 0;
+	void *data = NULL;
+	int cc;
+	int maxps;
+	int toggle;
+	struct urb *urb;
+	int urb_state = 0;
+	int ret = 1;		/* -1 parse abbort, 1 parse ok, 0 last element */
+	int trans = 0;
+	int len;
+	int iso_index = 0;
+	int out;
+	int pid = 0;
+	int debugLen = 0;
+
+	*isExcessNak = 0;
+
+	DBGFUNC ("enter sh_done_list: td_array->len = 0x%x\n",
+		 hci->td_array->len);
+
+	debugLen = hci->td_array->len;
+	if (debugLen > 1)
+		DBGERR ("sh_done_list: td_array->len = 0x%x > 1\n",
+			hci->td_array->len);
+
+	for (trans = 0; ret && trans < hci->td_array->len && trans < MAX_TRANS;
+	     trans++) {
+		urb = hci->td_array->td[trans].urb;
+		len = hci->td_array->td[trans].len;
+		out = usb_pipeout (urb->pipe);
+
+		if (usb_pipeisoc (urb->pipe)) {
+			iso_index = hci->td_array->td[trans].iso_index;
+			data = urb->transfer_buffer + urb->iso_frame_desc[iso_index].offset;
+			toggle = 0;
+		} else {
+			data = urb->transfer_buffer + urb->actual_length;
+			toggle = usb_gettoggle (urb->dev,
+						usb_pipeendpoint (urb->pipe),
+						usb_pipeout (urb->pipe));
+
+		}
+		urb_state = qu_urbstate (urb);
+		pid = out ? PID_OUT : PID_IN;
+		ret = hc_parse_trans (hci, &actbytes, data, &cc, &toggle, len,
+				      pid, urb_state);
+		maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+
+		if (maxps == 0)
+			maxps = 8;
+
+		active = (urb_state != US_CTRL_SETUP) && (actbytes && !(actbytes & (maxps - 1)));
+
+		/* If the transfer is not bulk in, then it is necessary to get all
+		 * data specify by the urb->transfer_len.
+		 */
+
+		if (!(usb_pipebulk (urb->pipe) && usb_pipein (urb->pipe)))
+			active = active && (urb->transfer_buffer_length != urb->actual_length + actbytes);
+
+		if (urb->transfer_buffer_length == urb->actual_length + actbytes)
+			active = 0;
+
+		if ((cc &
+		     (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT |
+		      SL11H_STATMASK_OVF | SL11H_STATMASK_STALL))
+		    && !(cc & SL11H_STATMASK_NAK)) {
+			if (++urb->error_count > 3) {
+				DBGERR ("done_list: excessive error: errcount = 0x%x, cc = 0x%x\n",
+					urb->error_count, cc);
+				urb_state = 0;
+				active = 0;
+			} else {
+				DBGERR ("done_list: packet err, cc = 0x%x, "
+					" urb->length = 0x%x, actual_len = 0x%x,"
+					" urb_state =0x%x\n",
+					cc, urb->transfer_buffer_length,
+					urb->actual_length, urb_state);
+//			if (cc & SL11H_STATMASK_STALL) {
+				/* The USB function is STALLED on a control pipe (0), 
+				 * then it needs to send the SETUP command again to 
+				 * clear the STALL condition
+				 */
+
+//				if (usb_pipeendpoint (urb->pipe) == 0) {
+//					urb_state = 2;  
+//					active = 0;
+//				}
+//			} else   
+				active = 1;
+			}
+		} else {
+			if (cc & SL11H_STATMASK_NAK) {
+				if (hci->nakCnt < 0x10000) {
+					hci->nakCnt++;
+					hci->last_packet_nak = 1;
+					active = 1;
+					*isExcessNak = 0;
+				} else {
+					DBGERR ("done_list: nak count exceed limit\n");
+					active = 0;
+					*isExcessNak = 1;
+					hci->nakCnt = 0;
+				}
+			} else {
+				hci->nakCnt = 0;
+				hci->last_packet_nak = 0;
+			}
+
+			if (urb_state != US_CTRL_SETUP) {
+				/* no error */
+				urb->actual_length += actbytes;
+				usb_settoggle (urb->dev,
+					       usb_pipeendpoint (urb->pipe),
+					       usb_pipeout (urb->pipe), toggle);
+			}
+			if (usb_pipeisoc (urb->pipe)) {
+				urb->iso_frame_desc[iso_index].actual_length = actbytes;
+				urb->iso_frame_desc[iso_index].status = cc_to_error (cc);
+				active = (iso_index < urb->number_of_packets);
+			}
+		}
+		if (!active) {
+			if (!urb_state) {
+				urb->status = cc_to_error (cc);
+				if (urb->status) {
+					DBGERR ("error on received packet: urb->status = 0x%x\n",
+						urb->status);
+				}
+				hci->td_array->len = 0;
+				qu_return_urb (hci, urb, 1);
+				return -1;
+			} else {
+				/* We do not want to decrement the urb_state if exceeded nak,
+				 * because we need to finish the data stage of the control 
+				 * packet 
+				 */
+
+				if (!(*isExcessNak))
+					urb_state--;
+				qu_seturbstate (urb, urb_state);
+			}
+		}
+	}
+
+	if (urb_state < 0)
+		DBGERR ("ERROR: done_list, urb_state = %d, suppose > 0\n",
+			urb_state);
+	if (debugLen != hci->td_array->len) {
+		DBGERR ("ERROR: done_list, debugLen!= td_array->len,"
+			"debugLen = 0x%x, hci->td_array->len = 0x%x\n",
+			debugLen, hci->td_array->len);
+	}
+
+	hci->td_array->len = 0;
+
+	return urb_state;
+}
diff -Nru a/drivers/usb/host/hc_simple.h b/drivers/usb/host/hc_simple.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/hc_simple.h	Wed May 29 11:43:03 2002
@@ -0,0 +1,231 @@
+/*-------------------------------------------------------------------------*/
+/* list of all controllers using this driver 
+ * */
+
+static LIST_HEAD (hci_hcd_list);
+
+/* URB states (urb_state) */
+/* isoc, interrupt single state */
+
+/* bulk transfer main state and 0-length packet */
+#define US_BULK		0
+#define US_BULK0	1
+/* three setup states */
+#define US_CTRL_SETUP	2
+#define US_CTRL_DATA	1
+#define US_CTRL_ACK	0
+
+/*-------------------------------------------------------------------------*/
+/* HC private part of a device descriptor
+ * */
+
+#define NUM_EDS 32
+
+typedef struct epd {
+	struct urb *pipe_head;
+	struct list_head urb_queue;
+//	int urb_state;
+	struct timer_list timeout;
+	int last_iso;		/* timestamp of last queued ISOC transfer */
+
+} epd_t;
+
+struct hci_device {
+	epd_t ed[NUM_EDS];
+};
+
+/*-------------------------------------------------------------------------*/
+/* Virtual Root HUB 
+ */
+
+#define usb_to_hci(usb)	((struct hci_device *)(usb)->hcpriv)
+
+struct virt_root_hub {
+	int devnum;		/* Address of Root Hub endpoint */
+	void *urb;		/* interrupt URB of root hub */
+	int send;		/* active flag */
+	int interval;		/* intervall of roothub interrupt transfers */
+	struct timer_list rh_int_timer;	/* intervall timer for rh interrupt EP */
+};
+
+#if 1
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h and USB spec) */
+
+/* destination of request */
+#define RH_INTERFACE		0x01
+#define RH_ENDPOINT		0x02
+#define RH_OTHER		0x03
+
+#define RH_CLASS		0x20
+#define RH_VENDOR		0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	0x00
+#define RH_PORT_ENABLE		0x01
+#define RH_PORT_SUSPEND		0x02
+#define RH_PORT_OVER_CURRENT	0x03
+#define RH_PORT_RESET		0x04
+#define RH_PORT_POWER		0x08
+#define RH_PORT_LOW_SPEED	0x09
+
+#define RH_C_PORT_CONNECTION	0x10
+#define RH_C_PORT_ENABLE	0x11
+#define RH_C_PORT_SUSPEND	0x12
+#define RH_C_PORT_OVER_CURRENT	0x13
+#define RH_C_PORT_RESET		0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	0x00
+#define RH_C_HUB_OVER_CURRENT	0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP	0x00
+#define RH_ENDPOINT_STALL	0x01
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* struct for each HC 
+ */
+
+#define MAX_TRANS	32
+
+typedef struct td {
+	struct urb *urb;
+	__u16 len;
+	__u16 iso_index;
+} td_t;
+
+typedef struct td_array {
+	int len;
+	td_t td[MAX_TRANS];
+} td_array_t;
+
+typedef struct hci {
+	struct virt_root_hub rh;	/* roothub */
+	wait_queue_head_t waitq;	/* deletion of URBs and devices needs a waitqueue */
+	int active;			/* HC is operating */
+
+	struct list_head ctrl_list;	/* set of ctrl endpoints */
+	struct list_head bulk_list;	/* set of bulk endpoints */
+	struct list_head iso_list;	/* set of isoc endpoints */
+	struct list_head intr_list;	/* ordered (tree) set of int endpoints */
+	struct list_head del_list;	/* set of entpoints to be deleted */
+
+	td_array_t *td_array;
+	td_array_t a_td_array;
+	td_array_t i_td_array[2];
+
+	struct list_head hci_hcd_list;	/* list of all hci_hcd */
+	struct usb_bus *bus;		/* our bus */
+
+//	int trans;			/* number of transactions pending */
+	int active_urbs;
+	int active_trans;
+	int frame_number;		/* frame number */
+	hcipriv_t hp;			/* individual part of hc type */
+	int nakCnt;
+	int last_packet_nak;
+
+} hci_t;
+
+/*-------------------------------------------------------------------------*/
+/* condition (error) CC codes and mapping OHCI like
+ */
+
+#define TD_CC_NOERROR		0x00
+#define TD_CC_CRC		0x01
+#define TD_CC_BITSTUFFING	0x02
+#define TD_CC_DATATOGGLEM	0x03
+#define TD_CC_STALL		0x04
+#define TD_DEVNOTRESP		0x05
+#define TD_PIDCHECKFAIL		0x06
+#define TD_UNEXPECTEDPID	0x07
+#define TD_DATAOVERRUN		0x08
+#define TD_DATAUNDERRUN		0x09
+#define TD_BUFFEROVERRUN	0x0C
+#define TD_BUFFERUNDERRUN	0x0D
+#define TD_NOTACCESSED		0x0F
+
+
+/* urb interface functions */
+static int hci_get_current_frame_number (struct usb_device *usb_dev);
+static int hci_unlink_urb (struct urb * urb);
+
+static int qu_queue_urb (hci_t * hci, struct urb * urb);
+
+/* root hub */
+static int rh_init_int_timer (struct urb * urb);
+static int rh_submit_urb (struct urb * urb);
+static int rh_unlink_urb (struct urb * urb);
+
+/* schedule functions */
+static int sh_add_packet (hci_t * hci, struct urb * urb);
+
+/* hc specific functions */
+static inline void hc_flush_data_cache (hci_t * hci, void *data, int len);
+static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,
+				  int *cc, int *toggle, int length, int pid,
+				  int urb_state);
+static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle,
+				int maxps, int slow, int endpoint, int address,
+				int pid, int format, int urb_state);
+
+static void hc_start_int (hci_t * hci);
+static void hc_stop_int (hci_t * hci);
+static void SL811Write (hci_t * hci, char offset, char data);
+
+/* debug| print the main components of an URB     
+ * small: 0) header + data packets 1) just header */
+
+static void urb_print (struct urb * urb, char *str, int small)
+{
+	unsigned int pipe = urb->pipe;
+	int i, len;
+
+	if (!urb->dev || !urb->dev->bus) {
+		dbg ("%s URB: no dev", str);
+		return;
+	}
+
+	printk ("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)\n",
+		str, hci_get_current_frame_number (urb->dev),
+		usb_pipedevice (pipe), usb_pipeendpoint (pipe),
+		usb_pipeout (pipe) ? 'O' : 'I',
+		usb_pipetype (pipe) < 2 ? (usb_pipeint (pipe) ? "INTR" : "ISOC")
+		: (usb_pipecontrol (pipe) ? "CTRL" : "BULK"), urb->transfer_flags,
+		urb->actual_length, urb->transfer_buffer_length, urb->status,
+		urb->status);
+	if (!small) {
+		if (usb_pipecontrol (pipe)) {
+			printk (__FILE__ ": cmd(8):");
+			for (i = 0; i < 8; i++)
+				printk (" %02x", ((__u8 *) urb->setup_packet)[i]);
+			printk ("\n");
+		}
+		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+			printk (__FILE__ ": data(%d/%d):", urb->actual_length,
+				urb->transfer_buffer_length);
+			len = usb_pipeout (pipe) ? urb-> transfer_buffer_length : urb->actual_length;
+			for (i = 0; i < 2096 && i < len; i++)
+				printk (" %02x", ((__u8 *) urb->transfer_buffer)[i]);
+			printk ("%s stat:%d\n", i < len ? "..." : "",
+				urb->status);
+		}
+	}
+}
diff -Nru a/drivers/usb/host/hc_sl811.c b/drivers/usb/host/hc_sl811.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/hc_sl811.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,1358 @@
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*
+ * SL811HS USB HCD for Linux Version 0.1 (10/28/2001)
+ * 
+ * requires (includes) hc_simple.[hc] simple generic HCD frontend
+ *  
+ * COPYRIGHT(C) 2001 by CYPRESS SEMICONDUCTOR INC.
+ *
+ *-------------------------------------------------------------------------*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *-------------------------------------------------------------------------*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/usb.h>
+#include "../core/hcd.h"
+
+#undef HC_URB_TIMEOUT
+#undef HC_SWITCH_INT
+#undef HC_ENABLE_ISOC
+
+#define SL811_DEBUG_ERR
+
+#ifdef SL811_DEBUG_ERR
+#define DBGERR(fmt, args...) printk(fmt,## args)
+#else
+#define DBGERR(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG
+#define DBG(fmt, args...) printk(fmt,## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG_FUNC
+#define DBGFUNC(fmt, args...) printk(fmt,## args)
+#else
+#define DBGFUNC(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG_DATA
+#define DBGDATAR(fmt, args...) printk(fmt,## args)
+#define DBGDATAW(fmt, args...) printk(fmt,## args)
+#else
+#define DBGDATAR(fmt, args...)
+#define DBGDATAW(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG_VERBOSE
+#define DBGVERBOSE(fmt, args...) printk(fmt,## args)
+#else
+#define DBGVERBOSE(fmt, args...)
+#endif
+
+#define TRUE 1
+#define FALSE 0
+
+#define HC_SWITCH_INT
+#include "hc_sl811.h"
+#include "hc_simple.h"
+
+static int urb_debug = 0;
+
+#include "hc_simple.c"
+#include "hc_sl811_rh.c"
+
+/* The base_addr, data_reg_addr, and irq number are board specific.
+ * The current values are design to run on the Accelent SA1110 IDP
+ * NOTE: values need to modify for different development boards 
+ */
+
+static int base_addr = 0xd3800000;
+static int data_reg_addr = 0xd3810000;
+static int irq = 34;
+
+/* forware declaration */
+
+int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len,
+		      int toggle, int slow, int urb_state);
+
+static int sofWaitCnt = 0;
+
+MODULE_PARM (urb_debug, "i");
+MODULE_PARM_DESC (urb_debug, "debug urb messages, default is 0 (no)");
+
+MODULE_PARM (base_addr, "i");
+MODULE_PARM_DESC (base_addr, "sl811 base address 0xd3800000");
+MODULE_PARM (data_reg_addr, "i");
+MODULE_PARM_DESC (data_reg_addr, "sl811 data register address 0xd3810000");
+MODULE_PARM (irq, "i");
+MODULE_PARM_DESC (irq, "IRQ 34 (default)");
+
+static int hc_reset (hci_t * hci);
+
+/***************************************************************************
+ * Function Name : SL811Read
+ *
+ * Read a byte of data from the SL811H/SL11H
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = address of SL811/SL11H register or memory
+ *
+ * Return: data 
+ **************************************************************************/
+char SL811Read (hci_t * hci, char offset)
+{
+	hcipriv_t *hp = &hci->hp;
+	char data;
+	writeb (offset, hp->hcport);
+	wmb ();
+	data = readb (hp->hcport2);
+	rmb ();
+	return (data);
+}
+
+/***************************************************************************
+ * Function Name : SL811Write
+ *
+ * Write a byte of data to the SL811H/SL11H
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = address of SL811/SL11H register or memory
+ *         data  = the data going to write to SL811H
+ *
+ * Return: none 
+ **************************************************************************/
+void SL811Write (hci_t * hci, char offset, char data)
+{
+	hcipriv_t *hp = &hci->hp;
+	writeb (offset, hp->hcport);
+	writeb (data, hp->hcport2);
+	wmb ();
+}
+
+/***************************************************************************
+ * Function Name : SL811BufRead
+ *
+ * Read consecutive bytes of data from the SL811H/SL11H buffer
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = SL811/SL11H register offset
+ *         buf = the buffer where the data will store
+ *         size = number of bytes to read
+ *
+ * Return: none 
+ **************************************************************************/
+void SL811BufRead (hci_t * hci, short offset, char *buf, short size)
+{
+	hcipriv_t *hp = &hci->hp;
+	if (size <= 0)
+		return;
+	writeb ((char) offset, hp->hcport);
+	wmb ();
+	DBGDATAR ("SL811BufRead: offset = 0x%x, data = ", offset);
+	while (size--) {
+		*buf++ = (char) readb (hp->hcport2);
+		DBGDATAR ("0x%x ", *(buf - 1));
+		rmb ();
+	}
+	DBGDATAR ("\n");
+}
+
+/***************************************************************************
+ * Function Name : SL811BufWrite
+ *
+ * Write consecutive bytes of data to the SL811H/SL11H buffer
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = SL811/SL11H register offset
+ *         buf = the data buffer 
+ *         size = number of bytes to write
+ *
+ * Return: none 
+ **************************************************************************/
+void SL811BufWrite (hci_t * hci, short offset, char *buf, short size)
+{
+	hcipriv_t *hp = &hci->hp;
+	if (size <= 0)
+		return;
+	writeb ((char) offset, hp->hcport);
+	wmb ();
+	DBGDATAW ("SL811BufWrite: offset = 0x%x, data = ", offset);
+	while (size--) {
+		DBGDATAW ("0x%x ", *buf);
+		writeb (*buf, hp->hcport2);
+		wmb ();
+		buf++;
+	}
+	DBGDATAW ("\n");
+}
+
+/***************************************************************************
+ * Function Name : regTest
+ *
+ * This routine test the Read/Write functionality of SL811HS registers  
+ *
+ * 1) Store original register value into a buffer
+ * 2) Write to registers with a RAMP pattern. (10, 11, 12, ..., 255)
+ * 3) Read from register
+ * 4) Compare the written value with the read value and make sure they are 
+ *    equivalent
+ * 5) Restore the original register value 
+ *
+ * Input:  hci = data structure for the host controller
+ *   
+ *
+ * Return: TRUE = passed; FALSE = failed 
+ **************************************************************************/
+int regTest (hci_t * hci)
+{
+	int i, data, result = TRUE;
+	char buf[256];
+
+	DBGFUNC ("Enter regTest\n");
+	for (i = 0x10; i < 256; i++) {
+		/* save the original buffer */
+		buf[i] = (char) SL811Read (hci, i);
+
+		/* Write the new data to the buffer */
+		SL811Write (hci, i, i);
+	}
+
+	/* compare the written data */
+	for (i = 0x10; i < 256; i++) {
+		data = SL811Read (hci, i);
+		if (data != i) {
+			DBGERR ("Pattern test failed!! value = 0x%x, s/b 0x%x\n",
+				data, i);
+			result = FALSE;
+		}
+	}
+
+	/* restore the data */
+	for (i = 0x10; i < 256; i++) {
+		SL811Write (hci, i, buf[i]);
+	}
+
+	return (result);
+}
+
+/***************************************************************************
+ * Function Name : regShow
+ *
+ * Display all SL811HS register values
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return: none 
+ **************************************************************************/
+void regShow (hci_t * hci)
+{
+	int i;
+	for (i = 0; i < 256; i++) {
+		printk ("offset %d: 0x%x\n", i, SL811Read (hci, i));
+	}
+}
+
+/************************************************************************
+ * Function Name : USBReset
+ *  
+ * This function resets SL811HS controller and detects the speed of
+ * the connecting device				  
+ *
+ * Input:  hci = data structure for the host controller
+ *                
+ * Return: 0 = no device attached; 1 = USB device attached
+ *                
+ ***********************************************************************/
+static int USBReset (hci_t * hci)
+{
+	int status;
+	hcipriv_t *hp = &hci->hp;
+
+	DBGFUNC ("enter USBReset\n");
+
+	SL811Write (hci, SL11H_CTLREG2, 0xae);
+
+	// setup master and full speed
+
+	SL811Write (hci, SL11H_CTLREG1, 0x08);	// reset USB
+	mdelay (20);		// 20ms                             
+	SL811Write (hci, SL11H_CTLREG1, 0);	// remove SE0        
+
+	for (status = 0; status < 100; status++)
+		SL811Write (hci, SL11H_INTSTATREG, 0xff);	// clear all interrupt bits
+
+	status = SL811Read (hci, SL11H_INTSTATREG);
+
+	if (status & 0x40)	// Check if device is removed
+	{
+		DBG ("USBReset: Device removed\n");
+		SL811Write (hci, SL11H_INTENBLREG,
+			    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
+			    SL11H_INTMASK_INSRMV);
+		hp->RHportStatus->portStatus &=
+		    ~(PORT_CONNECT_STAT | PORT_ENABLE_STAT);
+
+		return 0;
+	}
+
+	SL811Write (hci, SL11H_BUFLNTHREG_B, 0);	//zero lenth
+	SL811Write (hci, SL11H_PIDEPREG_B, 0x50);	//send SOF to EP0       
+	SL811Write (hci, SL11H_DEVADDRREG_B, 0x01);	//address0
+	SL811Write (hci, SL11H_SOFLOWREG, 0xe0);
+
+	if (!(status & 0x80)) {
+		/* slow speed device connect directly to root-hub */
+
+		DBG ("USBReset: low speed Device attached\n");
+		SL811Write (hci, SL11H_CTLREG1, 0x8);
+		mdelay (20);
+		SL811Write (hci, SL11H_SOFTMRREG, 0xee);
+		SL811Write (hci, SL11H_CTLREG1, 0x21);
+
+		/* start the SOF or EOP */
+
+		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x01);
+		hp->RHportStatus->portStatus |=
+		    (PORT_CONNECT_STAT | PORT_LOW_SPEED_DEV_ATTACH_STAT);
+
+		/* clear all interrupt bits */
+
+		for (status = 0; status < 20; status++)
+			SL811Write (hci, SL11H_INTSTATREG, 0xff);
+	} else {
+		/* full speed device connect directly to root hub */
+
+		DBG ("USBReset: full speed Device attached\n");
+		SL811Write (hci, SL11H_CTLREG1, 0x8);
+		mdelay (20);
+		SL811Write (hci, SL11H_SOFTMRREG, 0xae);
+		SL811Write (hci, SL11H_CTLREG1, 0x01);
+
+		/* start the SOF or EOP */
+
+		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x01);
+		hp->RHportStatus->portStatus |= (PORT_CONNECT_STAT);
+		hp->RHportStatus->portStatus &= ~PORT_LOW_SPEED_DEV_ATTACH_STAT;
+
+		/* clear all interrupt bits */
+
+		SL811Write (hci, SL11H_INTSTATREG, 0xff);
+
+	}
+
+	/* enable all interrupts */
+	SL811Write (hci, SL11H_INTENBLREG,
+		    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
+		    SL11H_INTMASK_INSRMV);
+
+	return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+/* tl functions */
+static inline void hc_mark_last_trans (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+	__u8 *ptd = hp->tl;
+
+	dbg ("enter hc_mark_last_trans\n");
+	if (ptd == NULL) {
+		printk ("hc_mark_last_trans: ptd = null\n");
+		return;
+	}
+	if (hp->xferPktLen > 0)
+		*(ptd + hp->tl_last) |= (1 << 3);
+}
+
+static inline void hc_flush_data_cache (hci_t * hci, void *data, int len)
+{
+}
+
+/************************************************************************
+ * Function Name : hc_add_trans
+ *  
+ * This function sets up the SL811HS register and transmit the USB packets.
+ * 
+ * 1) Determine if enough time within the current frame to send the packet
+ * 2) Load the data into the SL811HS register
+ * 3) Set the appropriate command to the register and trigger the transmit
+ *
+ * Input:  hci = data structure for the host controller
+ *         len = data length
+ *         data = transmitting data
+ *         toggle = USB toggle bit, either 0 or 1
+ *         maxps = maximum packet size for this endpoint
+ *         slow = speed of the device
+ *         endpoint = endpoint number
+ *         address = USB address of the device
+ *         pid = packet ID
+ *         format = 
+ *         urb_state = the current stage of USB transaction
+ *       
+ * Return: 0 = no time left to schedule the transfer
+ *         1 = success 
+ *                
+ ***********************************************************************/
+static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle,
+				int maxps, int slow, int endpoint, int address,
+				int pid, int format, int urb_state)
+{
+	hcipriv_t *hp = &hci->hp;
+	__u16 speed;
+	int ii, jj, kk;
+
+	DBGFUNC ("enter hc_addr_trans: len =0x%x, toggle:0x%x, endpoing:0x%x,"
+		 " addr:0x%x, pid:0x%x,format:0x%x\n", len, toggle, endpoint,
+		 i address, pid, format);
+
+	if (len > maxps) {
+		len = maxps;
+	}
+
+	speed = hp->RHportStatus->portStatus;
+	if (speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) {
+//      ii = (8*7*8 + 6*3) * len + 800; 
+		ii = 8 * 8 * len + 1024;
+	} else {
+		if (slow) {
+//          ii = (8*7*8 + 6*3) * len + 800; 
+			ii = 8 * 8 * len + 2048;
+		} else
+//          ii = (8*7 + 6*3)*len + 110;
+			ii = 8 * len + 256;
+	}
+
+	ii += 2 * 10 * len;
+
+	jj = SL811Read (hci, SL11H_SOFTMRREG);
+	kk = (jj & 0xFF) * 64 - ii;
+
+	if (kk < 0) {
+		DBGVERBOSE
+		    ("hc_add_trans: no bandwidth for schedule, ii = 0x%x,"
+		     "jj = 0x%x, len =0x%x, active_trans = 0x%x\n", ii, jj, len,
+		     hci->active_trans);
+		return (-1);
+	}
+
+	if (pid != PID_IN) {
+		/* Load data into hc */
+
+		SL811BufWrite (hci, SL11H_DATA_START, (__u8 *) data, len);
+	}
+
+	/* transmit */
+
+	SL11StartXaction (hci, (__u8) address, (__u8) endpoint, (__u8) pid, len,
+			  toggle, slow, urb_state);
+
+	return len;
+}
+
+/************************************************************************
+ * Function Name : hc_parse_trans
+ *  
+ * This function checks the status of the transmitted or received packet
+ * and copy the data from the SL811HS register into a buffer.
+ *
+ * 1) Check the status of the packet 
+ * 2) If successful, and IN packet then copy the data from the SL811HS register
+ *    into a buffer
+ *
+ * Input:  hci = data structure for the host controller
+ *         actbytes = pointer to actual number of bytes
+ *         data = data buffer
+ *         cc = packet status
+ *         length = the urb transmit length
+ *         pid = packet ID
+ *         urb_state = the current stage of USB transaction
+ *       
+ * Return: 0 
+ ***********************************************************************/
+static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,
+				  int *cc, int *toggle, int length, int pid,
+				  int urb_state)
+{
+	__u8 addr;
+	__u8 len;
+
+	DBGFUNC ("enter hc_parse_trans\n");
+
+	/* get packet status; convert ack rcvd to ack-not-rcvd */
+
+	*cc = (int) SL811Read (hci, SL11H_PKTSTATREG);
+
+	if (*cc &
+	    (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT | SL11H_STATMASK_OVF |
+	     SL11H_STATMASK_NAK | SL11H_STATMASK_STALL)) {
+		if (*cc & SL11H_STATMASK_OVF)
+			DBGERR ("parse trans: error recv ack, cc = 0x%x, TX_BASE_Len = "
+				"0x%x, TX_count=0x%x\n", *cc,
+				SL811Read (hci, SL11H_BUFLNTHREG),
+				SL811Read (hci, SL11H_XFERCNTREG));
+
+	} else {
+		DBGVERBOSE ("parse trans: recv ack, cc = 0x%x, len = 0x%x, \n",
+			    *cc, length);
+
+		/* Successful data */
+		if ((pid == PID_IN) && (urb_state != US_CTRL_SETUP)) {
+
+			/* Find the base address */
+			addr = SL811Read (hci, SL11H_BUFADDRREG);
+
+			/* Find the Transmit Length */
+			len = SL811Read (hci, SL11H_BUFLNTHREG);
+
+			/* The actual data length = xmit length reg - xfer count reg */
+			*actbytes = len - SL811Read (hci, SL11H_XFERCNTREG);
+
+			if ((data != NULL) && (*actbytes > 0)) {
+				SL811BufRead (hci, addr, data, *actbytes);
+
+			} else if ((data == NULL) && (*actbytes <= 0)) {
+				DBGERR ("hc_parse_trans: data = NULL or actbyte = 0x%x\n",
+					*actbytes);
+				return 0;
+			}
+		} else if (pid == PID_OUT) {
+			*actbytes = length;
+		} else {
+			// printk ("ERR:parse_trans, pid != IN or OUT, pid = 0x%x\n", pid);
+		}
+		*toggle = !*toggle;
+	}
+
+	return 0;
+}
+
+/************************************************************************
+ * Function Name : hc_start_int
+ *  
+ * This function enables SL811HS interrupts
+ *
+ * Input:  hci = data structure for the host controller
+ *       
+ * Return: none 
+ ***********************************************************************/
+static void hc_start_int (hci_t * hci)
+{
+#ifdef HC_SWITCH_INT
+	int mask =
+	    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
+	    SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET;
+	SL811Write (hci, IntEna, mask);
+#endif
+}
+
+/************************************************************************
+ * Function Name : hc_stop_int
+ *  
+ * This function disables SL811HS interrupts
+ *
+ * Input:  hci = data structure for the host controller
+ *       
+ * Return: none 
+ ***********************************************************************/
+static void hc_stop_int (hci_t * hci)
+{
+#ifdef HC_SWITCH_INT
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+//  SL811Write(hci, SL11H_INTENBLREG, SL11H_INTMASK_INSRMV);
+
+#endif
+}
+
+/************************************************************************
+ * Function Name : handleInsRmvIntr
+ *  
+ * This function handles the insertion or removal of device on  SL811HS. 
+ * It resets the controller and updates the port status
+ *
+ * Input:  hci = data structure for the host controller
+ *       
+ * Return: none 
+ ***********************************************************************/
+void handleInsRmvIntr (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+
+	USBReset (hci);
+
+	/* Changes in connection status */
+
+	hp->RHportStatus->portChange |= PORT_CONNECT_CHANGE;
+
+	/* Port Enable or Disable */
+
+	if (hp->RHportStatus->portStatus & PORT_CONNECT_STAT) {
+		/* device is connected to the port:
+		 *    1) Enable port 
+		 *    2) Resume ?? 
+		 */
+//               hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;
+
+		/* Over Current is not supported by the SL811 HW ?? */
+
+		/* How about the Port Power ?? */
+
+	} else {
+		/* Device has disconnect:
+		 *    1) Disable port
+		 */
+
+		hp->RHportStatus->portStatus &= ~(PORT_ENABLE_STAT);
+		hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;
+
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: SL11StartXaction
+ *  
+ * This functions load the registers with appropriate value and 
+ * transmit the packet.				  
+ *
+ * Input:  hci = data structure for the host controller
+ *         addr = USB address of the device
+ *         epaddr = endpoint number
+ *         pid = packet ID
+ *         len = data length
+ *         toggle = USB toggle bit, either 0 or 1
+ *         slow = speed of the device
+ *         urb_state = the current stage of USB transaction
+ *
+ * Return: 0 = error; 1 = successful
+ *                
+ *****************************************************************/
+int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len,
+		      int toggle, int slow, int urb_state)
+{
+
+	hcipriv_t *hp = &hci->hp;
+	__u8 cmd = 0;
+	__u8 setup_data[4];
+	__u16 speed;
+
+	speed = hp->RHportStatus->portStatus;
+	if (!(speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) && slow) {
+		cmd |= SL11H_HCTLMASK_PREAMBLE;
+	}
+	switch (pid) {
+	case PID_SETUP:
+		cmd &= SL11H_HCTLMASK_PREAMBLE;
+		cmd |=
+		    (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP |
+		     SL11H_HCTLMASK_WRITE);
+		break;
+
+	case PID_OUT:
+		cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);
+		cmd |=
+		    (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP |
+		     SL11H_HCTLMASK_WRITE);
+		if (toggle) {
+			cmd |= SL11H_HCTLMASK_SEQ;
+		}
+		break;
+
+	case PID_IN:
+		cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);
+		cmd |= (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP);
+		break;
+
+	default:
+		DBGERR ("ERR: SL11StartXaction: unknow pid = 0x%x\n", pid);
+		return 0;
+	}
+	setup_data[0] = SL11H_DATA_START;
+	setup_data[1] = len;
+	setup_data[2] = (((pid & 0x0F) << 4) | (epaddr & 0xF));
+	setup_data[3] = addr & 0x7F;
+
+	SL811BufWrite (hci, SL11H_BUFADDRREG, (__u8 *) & setup_data[0], 4);
+
+	SL811Write (hci, SL11H_HOSTCTLREG, cmd);
+
+#if 0
+	/* The SL811 has a hardware flaw when hub devices sends out
+	 * SE0 between packets. It has been found in a TI chipset and
+	 * cypress hub chipset. It causes the SL811 to hang
+	 * The workaround is to re-issue the preample again.
+	 */
+
+	if ((cmd & SL11H_HCTLMASK_PREAMBLE)) {
+		SL811Write (hci, SL11H_PIDEPREG_B, 0xc0);
+		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x1);	// send the premable
+	}
+#endif
+	return 1;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_interrupt
+ *
+ * Interrupt service routine. 
+ *
+ * 1) determine the causes of interrupt
+ * 2) clears all interrupts
+ * 3) calls appropriate function to service the interrupt
+ *
+ * Input:  irq = interrupt line associated with the controller 
+ *         hci = data structure for the host controller
+ *         r = holds the snapshot of the processor's context before 
+ *             the processor entered interrupt code. (not used here) 
+ *
+ * Return value  : None.
+ *                
+ *****************************************************************/
+static void hc_interrupt (int irq, void *__hci, struct pt_regs *r)
+{
+	char ii;
+	hci_t *hci = __hci;
+	int isExcessNak = 0;
+	int urb_state = 0;
+	char tmpIrq = 0;
+
+	/* Get value from interrupt status register */
+
+	ii = SL811Read (hci, SL11H_INTSTATREG);
+
+	if (ii & SL11H_INTMASK_INSRMV) {
+		/* Device insertion or removal detected for the USB port */
+
+		SL811Write (hci, SL11H_INTENBLREG, 0);
+		SL811Write (hci, SL11H_CTLREG1, 0);
+		mdelay (100);	// wait for device stable 
+		handleInsRmvIntr (hci);
+		return;
+	}
+
+	/* Clear all interrupts */
+
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+
+	if (ii & SL11H_INTMASK_XFERDONE) {
+		/* USB Done interrupt occurred */
+
+		urb_state = sh_done_list (hci, &isExcessNak);
+#ifdef WARNING
+		if (hci->td_array->len > 0)
+			printk ("WARNING: IRQ, td_array->len = 0x%x, s/b:0\n",
+				hci->td_array->len);
+#endif
+		if (hci->td_array->len == 0 && !isExcessNak
+		    && !(ii & SL11H_INTMASK_SOFINTR) && (urb_state == 0)) {
+			if (urb_state == 0) {
+				/* All urb_state has not been finished yet! 
+				 * continue with the current urb transaction 
+				 */
+
+				if (hci->last_packet_nak == 0) {
+					if (!usb_pipecontrol
+					    (hci->td_array->td[0].urb->pipe))
+						sh_add_packet (hci, hci->td_array-> td[0].urb);
+				}
+			} else {
+				/* The last transaction has completed:
+				 * schedule the next transaction 
+				 */
+
+				sh_schedule_trans (hci, 0);
+			}
+		}
+		SL811Write (hci, SL11H_INTSTATREG, 0xff);
+		return;
+	}
+
+	if (ii & SL11H_INTMASK_SOFINTR) {
+		hci->frame_number = (hci->frame_number + 1) % 2048;
+		if (hci->td_array->len == 0)
+			sh_schedule_trans (hci, 1);
+		else {
+			if (sofWaitCnt++ > 100) {
+				/* The last transaction has not completed.
+				 * Need to retire the current td, and let
+				 * it transmit again later on.
+				 * (THIS NEEDS TO BE WORK ON MORE, IT SHOULD NEVER 
+				 *  GET TO THIS POINT)
+				 */
+
+				DBGERR ("SOF interrupt: td_array->len = 0x%x, s/b: 0\n",
+					hci->td_array->len);
+				urb_print (hci->td_array->td[hci->td_array->len - 1].urb,
+					   "INTERRUPT", 0);
+				sh_done_list (hci, &isExcessNak);
+				SL811Write (hci, SL11H_INTSTATREG, 0xff);
+				hci->td_array->len = 0;
+				sofWaitCnt = 0;
+			}
+		}
+		tmpIrq = SL811Read (hci, SL11H_INTSTATREG) & SL811Read (hci, SL11H_INTENBLREG);
+		if (tmpIrq) {
+			DBG ("IRQ occurred while service SOF: irq = 0x%x\n",
+			     tmpIrq);
+
+			/* If we receive a DONE IRQ after schedule, need to 
+			 * handle DONE IRQ again 
+			 */
+
+			if (tmpIrq & SL11H_INTMASK_XFERDONE) {
+				DBGERR ("IRQ occurred while service SOF: irq = 0x%x\n",
+					tmpIrq);
+				urb_state = sh_done_list (hci, &isExcessNak);
+			}
+			SL811Write (hci, SL11H_INTSTATREG, 0xff);
+		}
+	} else {
+		DBG ("SL811 ISR: unknown, int = 0x%x \n", ii);
+	}
+
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+	return;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_reset
+ *
+ * This function does register test and resets the SL811HS 
+ * controller.
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0
+ *                
+ *****************************************************************/
+static int hc_reset (hci_t * hci)
+{
+	int attachFlag = 0;
+
+	DBGFUNC ("Enter hc_reset\n");
+	regTest (hci);
+	attachFlag = USBReset (hci);
+	if (attachFlag) {
+		setPortChange (hci, PORT_CONNECT_CHANGE);
+	}
+	return (0);
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_alloc_trans_buffer
+ *
+ * This function allocates all transfer buffer  
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0
+ *                
+ *****************************************************************/
+static int hc_alloc_trans_buffer (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+	int maxlen;
+
+	hp->itl0_len = 0;
+	hp->itl1_len = 0;
+	hp->atl_len = 0;
+
+	hp->itl_buffer_len = 1024;
+	hp->atl_buffer_len = 4096 - 2 * hp->itl_buffer_len;	/* 2048 */
+
+	maxlen = (hp->itl_buffer_len > hp->atl_buffer_len) ? hp->itl_buffer_len : hp->atl_buffer_len;
+
+	hp->tl = kmalloc (maxlen, GFP_KERNEL);
+
+	if (!hp->tl)
+		return -ENOMEM;
+
+	memset (hp->tl, 0, maxlen);
+	return 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: getPortStatusAndChange
+ *
+ * This function gets the ports status from SL811 and format it 
+ * to a USB request format
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : port status and change
+ *                
+ *****************************************************************/
+static __u32 getPortStatusAndChange (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+	__u32 portstatus;
+
+	DBGFUNC ("enter getPorStatusAndChange\n");
+
+	portstatus = hp->RHportStatus->portChange << 16 | hp->RHportStatus->portStatus;
+
+	return (portstatus);
+}
+
+/*****************************************************************
+ *
+ * Function Name: setPortChange
+ *
+ * This function set the bit position of portChange.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void setPortChange (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+
+	switch (bitPos) {
+	case PORT_CONNECT_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_ENABLE_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_RESET_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_POWER_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_SUSPEND_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_OVER_CURRENT_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: clrPortChange
+ *
+ * This function clear the bit position of portChange.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void clrPortChange (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+	switch (bitPos) {
+	case PORT_CONNECT_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_ENABLE_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_RESET_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_SUSPEND_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_OVER_CURRENT_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: clrPortStatus
+ *
+ * This function clear the bit position of portStatus.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void clrPortStatus (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+	switch (bitPos) {
+	case PORT_ENABLE_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+
+	case PORT_RESET_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+
+	case PORT_POWER_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+
+	case PORT_SUSPEND_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: setPortStatus
+ *
+ * This function set the bit position of portStatus.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void setPortStatus (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+	switch (bitPos) {
+	case PORT_ENABLE_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+
+	case PORT_RESET_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+
+	case PORT_POWER_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+
+	case PORT_SUSPEND_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_start
+ *
+ * This function starts the root hub functionality. 
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0 
+ *                
+ *****************************************************************/
+static int hc_start (hci_t * hci)
+{
+	DBGFUNC ("Enter hc_start\n");
+
+	rh_connect_rh (hci);
+
+	return 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_alloc_hci
+ *
+ * This function allocates all data structure and store in the 
+ * private data structure. 
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0 
+ *                
+ *****************************************************************/
+static hci_t *__devinit hc_alloc_hci (void)
+{
+	hci_t *hci;
+	hcipriv_t *hp;
+	portstat_t *ps;
+	struct usb_bus *bus;
+
+	DBGFUNC ("Enter hc_alloc_hci\n");
+	hci = (hci_t *) kmalloc (sizeof (hci_t), GFP_KERNEL);
+	if (!hci)
+		return NULL;
+
+	memset (hci, 0, sizeof (hci_t));
+
+	hp = &hci->hp;
+
+	hp->irq = -1;
+	hp->hcport = -1;
+
+	/* setup root hub port status */
+
+	ps = (portstat_t *) kmalloc (sizeof (portstat_t), GFP_KERNEL);
+
+	if (!ps)
+		return NULL;
+	ps->portStatus = PORT_STAT_DEFAULT;
+	ps->portChange = PORT_CHANGE_DEFAULT;
+	hp->RHportStatus = ps;
+
+	hci->nakCnt = 0;
+	hci->last_packet_nak = 0;
+
+	hci->a_td_array.len = 0;
+	hci->i_td_array[0].len = 0;
+	hci->i_td_array[1].len = 0;
+	hci->td_array = &hci->a_td_array;
+	hci->active_urbs = 0;
+	hci->active_trans = 0;
+	INIT_LIST_HEAD (&hci->hci_hcd_list);
+	list_add (&hci->hci_hcd_list, &hci_hcd_list);
+	init_waitqueue_head (&hci->waitq);
+
+	INIT_LIST_HEAD (&hci->ctrl_list);
+	INIT_LIST_HEAD (&hci->bulk_list);
+	INIT_LIST_HEAD (&hci->iso_list);
+	INIT_LIST_HEAD (&hci->intr_list);
+	INIT_LIST_HEAD (&hci->del_list);
+
+	bus = usb_alloc_bus (&hci_device_operations);
+	if (!bus) {
+		kfree (hci);
+		return NULL;
+	}
+
+	hci->bus = bus;
+	bus->hcpriv = (void *) hci;
+
+	return hci;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_release_hci
+ *
+ * This function De-allocate all resources  
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0 
+ *                
+ *****************************************************************/
+static void hc_release_hci (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+
+	DBGFUNC ("Enter hc_release_hci\n");
+
+	/* disconnect all devices */
+	if (hci->bus->root_hub)
+		usb_disconnect (&hci->bus->root_hub);
+
+	hc_reset (hci);
+
+	if (hp->tl)
+		kfree (hp->tl);
+
+	if (hp->hcport > 0) {
+		release_region (hp->hcport, 2);
+		hp->hcport = 0;
+	}
+
+	if (hp->irq >= 0) {
+		free_irq (hp->irq, hci);
+		hp->irq = -1;
+	}
+
+	usb_deregister_bus (hci->bus);
+	usb_free_bus (hci->bus);
+
+	list_del (&hci->hci_hcd_list);
+	INIT_LIST_HEAD (&hci->hci_hcd_list);
+
+	kfree (hci);
+}
+
+/*****************************************************************
+ *
+ * Function Name: init_irq
+ *
+ * This function is board specific.  It sets up the interrupt to 
+ * be an edge trigger and trigger on the rising edge  
+ *
+ * Input: none 
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+void init_irq (void)
+{
+	GPDR &= ~(1 << 13);
+	set_GPIO_IRQ_edge (1 << 13, GPIO_RISING_EDGE);
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_found_hci
+ *
+ * This function request IO memory regions, request IRQ, and
+ * allocate all other resources. 
+ *
+ * Input: addr = first IO address
+ *        addr2 = second IO address
+ *        irq = interrupt number 
+ *
+ * Return: 0 = success or error condition 
+ *                
+ *****************************************************************/
+static int __devinit hc_found_hci (int addr, int addr2, int irq)
+{
+	hci_t *hci;
+	hcipriv_t *hp;
+
+	DBGFUNC ("Enter hc_found_hci\n");
+	hci = hc_alloc_hci ();
+	if (!hci) {
+		return -ENOMEM;
+	}
+
+	init_irq ();
+	hp = &hci->hp;
+
+	if (!request_region (addr, 256, "SL811 USB HOST")) {
+		DBGERR ("request address %d failed", addr);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+	hp->hcport = addr;
+	if (!hp->hcport) {
+		DBGERR ("Error mapping SL811 Memory 0x%x", hp->hcport);
+	}
+
+	if (!request_region (addr2, 256, "SL811 USB HOST")) {
+		DBGERR ("request address %d failed", addr2);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+	hp->hcport2 = addr2;
+	if (!hp->hcport2) {
+		DBGERR ("Error mapping SL811 Memory 0x%x", hp->hcport2);
+	}
+
+	if (hc_alloc_trans_buffer (hci)) {
+		hc_release_hci (hci);
+		return -ENOMEM;
+	}
+
+	usb_register_bus (hci->bus);
+
+	if (request_irq (irq, hc_interrupt, 0, "SL811", hci) != 0) {
+		DBGERR ("request interrupt %d failed", irq);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+	hp->irq = irq;
+
+	printk (KERN_INFO __FILE__ ": USB SL811 at %x, addr2 = %x, IRQ %d\n",
+		addr, addr2, irq);
+	hc_reset (hci);
+
+	if (hc_start (hci) < 0) {
+		DBGERR ("can't start usb-%x", addr);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hci_hcd_init
+ *
+ * This is an init function, and it is the first function being called
+ *
+ * Input: none 
+ *
+ * Return: 0 = success or error condition 
+ *                
+ *****************************************************************/
+static int __init hci_hcd_init (void)
+{
+	int ret;
+
+	DBGFUNC ("Enter hci_hcd_init\n");
+	ret = hc_found_hci (base_addr, data_reg_addr, irq);
+
+	return ret;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hci_hcd_cleanup
+ *
+ * This is a cleanup function, and it is called when module is 
+ * unloaded. 
+ *
+ * Input: none 
+ *
+ * Return: none 
+ *                
+ *****************************************************************/
+static void __exit hci_hcd_cleanup (void)
+{
+	struct list_head *hci_l;
+	hci_t *hci;
+
+	DBGFUNC ("Enter hci_hcd_cleanup\n");
+	for (hci_l = hci_hcd_list.next; hci_l != &hci_hcd_list;) {
+		hci = list_entry (hci_l, hci_t, hci_hcd_list);
+		hci_l = hci_l->next;
+		hc_release_hci (hci);
+	}
+}
+
+module_init (hci_hcd_init);
+module_exit (hci_hcd_cleanup);
+
+MODULE_AUTHOR ("Pei Liu <pbl@cypress.com>");
+MODULE_DESCRIPTION ("USB SL811HS Host Controller Driver");
diff -Nru a/drivers/usb/host/hc_sl811.h b/drivers/usb/host/hc_sl811.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/hc_sl811.h	Wed May 29 11:43:03 2002
@@ -0,0 +1,385 @@
+/*
+ * SL811HS HCD (Host Controller Driver) for USB.
+ * 
+ * COPYRIGHT (C) by CYPRESS SEMICONDUCTOR INC 
+ * 
+ *
+ */
+
+#define GET_FRAME_NUMBER(hci)	READ_REG32 (hci, HcFmNumber)
+
+/*
+ * Maximum number of root hub ports
+ */
+#define MAX_ROOT_PORTS		15	/* maximum OHCI root hub ports */
+
+/* control and status registers */
+#define HcRevision		0x00
+#define HcControl		0x01
+#define HcCommandStatus		0x02
+#define HcInterruptStatus	0x03
+#define HcInterruptEnable	0x04
+#define HcInterruptDisable	0x05
+#define HcFmInterval		0x0D
+#define HcFmRemaining		0x0E
+#define HcFmNumber		0x0F
+#define HcLSThreshold		0x11
+#define HcRhDescriptorA		0x12
+#define HcRhDescriptorB		0x13
+#define HcRhStatus		0x14
+#define HcRhPortStatus		0x15
+
+#define HcHardwareConfiguration 0x20
+#define HcDMAConfiguration	0x21
+#define HcTransferCounter	0x22
+#define HcuPInterrupt		0x24
+#define HcuPInterruptEnable	0x25
+#define HcChipID		0x27
+#define HcScratch		0x28
+#define HcSoftwareReset		0x29
+#define HcITLBufferLength	0x2A
+#define HcATLBufferLength	0x2B
+#define HcBufferStatus		0x2C
+#define HcReadBackITL0Length	0x2D
+#define HcReadBackITL1Length	0x2E
+#define HcITLBufferPort		0x40
+#define HcATLBufferPort		0x41
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_HCFS		(3 << 6)	/* BUS state mask */
+#define OHCI_CTRL_RWC		(1 << 9)	/* remote wakeup connected */
+#define OHCI_CTRL_RWE		(1 << 10)	/* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#define OHCI_USB_RESET		(0 << 6)
+#define OHCI_USB_RESUME		(1 << 6)
+#define OHCI_USB_OPER		(2 << 6)
+#define OHCI_USB_SUSPEND	(3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR	(1 << 0)	/* host controller reset */
+#define OHCI_SO		(3 << 16)	/* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
+
+#define OHCI_INTR_SF	(1 << 2)	/* start frame */
+#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
+#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
+#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
+#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
+#define OHCI_INTR_ATD	(1 << 7)	/* scheduling overrun */
+
+#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
+
+/*
+ * HcHardwareConfiguration
+ */
+#define InterruptPinEnable	(1 << 0)
+#define InterruptPinTrigger	(1 << 1)
+#define InterruptOutputPolarity	(1 << 2)
+#define DataBusWidth16		(1 << 3)
+#define DREQOutputPolarity	(1 << 5)
+#define DACKInputPolarity	(1 << 6)
+#define EOTInputPolarity	(1 << 7)
+#define DACKMode		(1 << 8)
+#define AnalogOCEnable		(1 << 10)
+#define SuspendClkNotStop	(1 << 11)
+#define DownstreamPort15KRSel	(1 << 12)
+
+/* 
+ * HcDMAConfiguration
+ */
+#define DMAReadWriteSelect 	(1 << 0)
+#define ITL_ATL_DataSelect	(1 << 1)
+#define DMACounterSelect	(1 << 2)
+#define DMAEnable		(1 << 4)
+#define BurstLen_1		0
+#define BurstLen_4		(1 << 5)
+#define BurstLen_8		(2 << 5)
+
+/*
+ * HcuPInterrupt
+ */
+#define SOFITLInt		(1 << 0)
+#define ATLInt			(1 << 1)
+#define AllEOTInterrupt		(1 << 2)
+#define OPR_Reg			(1 << 4)
+#define HCSuspended		(1 << 5)
+#define ClkReady		(1 << 6)
+
+/*
+ * HcBufferStatus
+ */
+#define ITL0BufferFull		(1 << 0)
+#define ITL1BufferFull		(1 << 1)
+#define ATLBufferFull		(1 << 2)
+#define ITL0BufferDone		(1 << 3)
+#define ITL1BufferDone		(1 << 4)
+#define ATLBufferDone		(1 << 5)
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS            0x00000001	/* current connect status */
+#define RH_PS_PES            0x00000002	/* port enable status */
+#define RH_PS_PSS            0x00000004	/* port suspend status */
+#define RH_PS_POCI           0x00000008	/* port over current indicator */
+#define RH_PS_PRS            0x00000010	/* port reset status */
+#define RH_PS_PPS            0x00000100	/* port power status */
+#define RH_PS_LSDA           0x00000200	/* low speed device attached */
+#define RH_PS_CSC            0x00010000	/* connect status change */
+#define RH_PS_PESC           0x00020000	/* port enable status change */
+#define RH_PS_PSSC           0x00040000	/* port suspend status change */
+#define RH_PS_OCIC           0x00080000	/* over current indicator change */
+#define RH_PS_PRSC           0x00100000	/* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS		0x00000001	/* local power status */
+#define RH_HS_OCI		0x00000002	/* over current indicator */
+#define RH_HS_DRWE		0x00008000	/* device remote wakeup enable */
+#define RH_HS_LPSC		0x00010000	/* local power status change */
+#define RH_HS_OCIC		0x00020000	/* over current indicator change */
+#define RH_HS_CRWE		0x80000000	/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR			0x0000ffff	/* device removable flags */
+#define RH_B_PPCM		0xffff0000	/* port power control mask */
+
+/* roothub.a masks */
+#define	RH_A_NDP		(0xff << 0)	/* number of downstream ports */
+#define	RH_A_PSM		(1 << 8)	/* power switching mode */
+#define	RH_A_NPS		(1 << 9)	/* no power switching */
+#define	RH_A_DT			(1 << 10)	/* device type (mbz) */
+#define	RH_A_OCPM		(1 << 11)	/* over current protection mode */
+#define	RH_A_NOCP		(1 << 12)	/* no over current protection */
+#define	RH_A_POTPGT		(0xff << 24)	/* power on to power good time */
+
+#define URB_DEL 1
+
+#define PORT_STAT_DEFAULT		0x0100
+#define PORT_CONNECT_STAT  		0x1
+#define PORT_ENABLE_STAT		0x2
+#define PORT_SUSPEND_STAT		0x4
+#define PORT_OVER_CURRENT_STAT		0x8
+#define PORT_RESET_STAT			0x10
+#define PORT_POWER_STAT			0x100
+#define PORT_LOW_SPEED_DEV_ATTACH_STAT	0x200
+
+#define PORT_CHANGE_DEFAULT		0x0
+#define PORT_CONNECT_CHANGE		0x1
+#define PORT_ENABLE_CHANGE		0x2
+#define PORT_SUSPEND_CHANGE		0x4
+#define PORT_OVER_CURRENT_CHANGE	0x8
+#define PORT_RESET_CHANGE		0x10
+
+/* Port Status Request info */
+
+typedef struct portstat {
+	__u16 portChange;
+	__u16 portStatus;
+} portstat_t;
+
+typedef struct hcipriv {
+	int irq;
+	int disabled;		/* e.g. got a UE, we're hung */
+	atomic_t resume_count;	/* defending against multiple resumes */
+	struct ohci_regs *regs;	/* OHCI controller's memory */
+	int hcport;		/* I/O base address */
+	int hcport2;		/* I/O data reg addr */
+
+	struct portstat *RHportStatus;	/* root hub port status */
+
+	int intrstatus;
+	__u32 hc_control;	/* copy of the hc control reg */
+
+	int frame;
+
+	__u8 *tl;
+	int xferPktLen;
+	int atl_len;
+	int atl_buffer_len;
+	int itl0_len;
+	int itl1_len;
+	int itl_buffer_len;
+	int itl_index;
+	int tl_last;
+	int units_left;
+
+} hcipriv_t;
+struct hci;
+
+#define cClt        0		// Control
+#define cISO        1		// ISO
+#define cBULK       2		// BULK
+#define cInt        3		// Interrupt
+#define ISO_BIT     0x10
+
+/*-------------------------------------------------------------------------
+ * EP0 use for configuration and Vendor Specific command interface
+ *------------------------------------------------------------------------*/
+#define cMemStart       0x10
+#define EP0Buf          0x40	/* SL11H/SL811H memory start at 0x40 */
+#define EP0Len          0x40	/* Length of config buffer EP0Buf */
+#define EP1Buf          0x60
+#define EP1Len          0x40
+
+/*-------------------------------------------------------------------------
+ * SL11H/SL811H memory from 80h-ffh use as ping-pong buffer.
+ *------------------------------------------------------------------------*/
+#define uBufA           0x80	/* buffer A address for DATA0 */
+#define uBufB           0xc0	/* buffer B address for DATA1 */
+#define uXferLen        0x40	/* xfer length */
+#define sMemSize        0xc0	/* Total SL11 memory size */
+#define cMemEnd         256
+
+/*-------------------------------------------------------------------------
+ * SL811H Register Control memory map
+ * --Note: 
+ *      --SL11H only has one control register set from 0x00-0x04
+ *      --SL811H has two control register set from 0x00-0x04 and 0x08-0x0c
+ *------------------------------------------------------------------------*/
+
+#define EP0Control      0x00
+#define EP0Address      0x01
+#define EP0XferLen      0x02
+#define EP0Status       0x03
+#define EP0Counter      0x04
+
+#define EP1Control      0x08
+#define EP1Address      0x09
+#define EP1XferLen      0x0a
+#define EP1Status       0x0b
+#define EP1Counter      0x0c
+
+#define CtrlReg         0x05
+#define IntEna          0x06
+			 // 0x07 is reserved
+#define IntStatus       0x0d
+#define cDATASet        0x0e
+#define cSOFcnt         0x0f
+#define IntMask         0x57	/* Reset|DMA|EP0|EP2|EP1 for IntEna */
+#define HostMask        0x47	/* Host request command  for IntStatus */
+#define ReadMask        0xd7	/* Read mask interrupt   for IntStatus */
+
+/*-------------------------------------------------------------------------
+ * Standard Chapter 9 definition
+ *-------------------------------------------------------------------------
+ */
+#define GET_STATUS      0x00
+#define CLEAR_FEATURE   0x01
+#define SET_FEATURE     0x03
+#define SET_ADDRESS     0x05
+#define GET_DESCRIPTOR  0x06
+#define SET_DESCRIPTOR  0x07
+#define GET_CONFIG      0x08
+#define SET_CONFIG      0x09
+#define GET_INTERFACE   0x0a
+#define SET_INTERFACE   0x0b
+#define SYNCH_FRAME     0x0c
+
+#define DEVICE          0x01
+#define CONFIGURATION   0x02
+#define STRING          0x03
+#define INTERFACE       0x04
+#define ENDPOINT        0x05
+
+/*-------------------------------------------------------------------------
+ * SL11H/SL811H definition
+ *-------------------------------------------------------------------------
+ */
+#define DATA0_WR	0x07	// (Arm+Enable+tranmist to Host+DATA0)
+#define DATA1_WR	0x47	// (Arm+Enable+tranmist to Host on DATA1)
+#define ZDATA0_WR	0x05	// (Arm+Transaction Ignored+tranmist to Host+DATA0)
+#define ZDATA1_WR	0x45	// (Arm+Transaction Ignored+tranmist to Host+DATA1)
+#define DATA0_RD	0x03	// (Arm+Enable+received from Host+DATA0)
+#define DATA1_RD	0x43	// (Arm+Enable+received from Host+DATA1)
+
+#define PID_SETUP	0x2d	// USB Specification 1.1 Standard Definition
+#define PID_SOF		0xA5
+#define PID_IN		0x69
+#define PID_OUT		0xe1
+
+#define MAX_RETRY	0xffff
+#define TIMEOUT		5		/* 2 mseconds */
+
+#define SL11H_HOSTCTLREG	0
+#define SL11H_BUFADDRREG	1
+#define SL11H_BUFLNTHREG	2
+#define SL11H_PKTSTATREG	3	/* read */
+#define SL11H_PIDEPREG		3	/* write */
+#define SL11H_XFERCNTREG	4	/* read */
+#define SL11H_DEVADDRREG	4	/* write */
+#define SL11H_CTLREG1		5
+#define SL11H_INTENBLREG	6
+
+#define SL11H_HOSTCTLREG_B	8
+#define SL11H_BUFADDRREG_B	9
+#define SL11H_BUFLNTHREG_B	0x0A
+#define SL11H_PKTSTATREG_B	0x0B	/* read */
+#define SL11H_PIDEPREG_B	0x0B	/* write */
+#define SL11H_XFERCNTREG_B	0x0C	/* read */
+#define SL11H_DEVADDRREG_B	0x0C	/* write */
+
+#define SL11H_INTSTATREG	0x0D	/* write clears bitwise */
+#define SL11H_HWREVREG		0x0E	/* read */
+#define SL11H_SOFLOWREG		0x0E	/* write */
+#define SL11H_SOFTMRREG		0x0F	/* read */
+#define SL11H_CTLREG2		0x0F	/* write */
+#define SL11H_DATA_START	0x10
+
+/* Host control register bits (addr 0) */
+#define SL11H_HCTLMASK_ARM	1
+#define SL11H_HCTLMASK_ENBLEP	2
+#define SL11H_HCTLMASK_WRITE	4
+#define SL11H_HCTLMASK_ISOCH	0x10
+#define SL11H_HCTLMASK_AFTERSOF	0x20
+#define SL11H_HCTLMASK_SEQ	0x40
+#define SL11H_HCTLMASK_PREAMBLE	0x80
+
+/* Packet status register bits (addr 3) */
+#define SL11H_STATMASK_ACK	1
+#define SL11H_STATMASK_ERROR	2
+#define SL11H_STATMASK_TMOUT	4
+#define SL11H_STATMASK_SEQ	8
+#define SL11H_STATMASK_SETUP	0x10
+#define SL11H_STATMASK_OVF	0x20
+#define SL11H_STATMASK_NAK	0x40
+#define SL11H_STATMASK_STALL	0x80
+
+/* Control register 1 bits (addr 5) */
+#define SL11H_CTL1MASK_DSBLSOF	1
+#define SL11H_CTL1MASK_NOTXEOF2	4
+#define SL11H_CTL1MASK_DSTATE	0x18
+#define SL11H_CTL1MASK_NSPD	0x20
+#define SL11H_CTL1MASK_SUSPEND	0x40
+#define SL11H_CTL1MASK_CLK12	0x80
+
+#define SL11H_CTL1VAL_RESET	8
+
+/* Interrut enable (addr 6) and interrupt status register bits (addr 0xD) */
+#define SL11H_INTMASK_XFERDONE	1
+#define SL11H_INTMASK_SOFINTR	0x10
+#define SL11H_INTMASK_INSRMV	0x20
+#define SL11H_INTMASK_USBRESET	0x40
+#define SL11H_INTMASK_DSTATE	0x80	/* only in status reg */
+
+/* HW rev and SOF lo register bits (addr 0xE) */
+#define SL11H_HWRMASK_HWREV	0xF0
+
+/* SOF counter and control reg 2 (addr 0xF) */
+#define SL11H_CTL2MASK_SOFHI	0x3F
+#define SL11H_CTL2MASK_DSWAP	0x40
+#define SL11H_CTL2MASK_HOSTMODE	0xae
+
diff -Nru a/drivers/usb/host/hc_sl811_rh.c b/drivers/usb/host/hc_sl811_rh.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/hc_sl811_rh.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,526 @@
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*
+ * SL811HS virtual root hub
+ *  
+ * based on usb-ohci.c by R. Weissgaerber et al.
+ *-------------------------------------------------------------------------*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#undef DEBUG
+#endif
+static __u32 getPortStatusAndChange (hci_t * hci);
+static void setPortStatus (hci_t * hci, __u16 bitPos);
+static void setPortChange (hci_t * hci, __u16 bitPos);
+static void clrPortStatus (hci_t * hci, __u16 bitPos);
+static void clrPortChange (hci_t * hci, __u16 bitPos);
+static int USBReset (hci_t * hci);
+static int cc_to_error (int cc);
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub 
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] = {
+	0x12,			/*  __u8  bLength; */
+	0x01,			/*  __u8  bDescriptorType; Device */
+	0x10,			/*  __u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  bDeviceSubClass; */
+	0x00,			/*  __u8  bDeviceProtocol; */
+	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,			/*  __u16 idVendor; */
+	0x00,
+	0x00,			/*  __u16 idProduct; */
+	0x00,
+	0x00,			/*  __u16 bcdDevice; */
+	0x00,
+	0x00,			/*  __u8  iManufacturer; */
+	0x02,			/*  __u8  iProduct; */
+	0x01,			/*  __u8  iSerialNumber; */
+	0x01			/*  __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] = {
+	0x09,			/*  __u8  bLength; */
+	0x02,			/*  __u8  bDescriptorType; Configuration */
+	0x19,			/*  __u16 wTotalLength; */
+	0x00,
+	0x01,			/*  __u8  bNumInterfaces; */
+	0x01,			/*  __u8  bConfigurationValue; */
+	0x00,			/*  __u8  iConfiguration; */
+	0x40,			/*  __u8  bmAttributes; 
+				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 
+				   4..0: resvd */
+	0x00,			/*  __u8  MaxPower; */
+
+	/* interface */
+	0x09,			/*  __u8  if_bLength; */
+	0x04,			/*  __u8  if_bDescriptorType; Interface */
+	0x00,			/*  __u8  if_bInterfaceNumber; */
+	0x00,			/*  __u8  if_bAlternateSetting; */
+	0x01,			/*  __u8  if_bNumEndpoints; */
+	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  if_bInterfaceSubClass; */
+	0x00,			/*  __u8  if_bInterfaceProtocol; */
+	0x00,			/*  __u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,			/*  __u8  ep_bLength; */
+	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
+	0x02,			/*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+	0x00,
+	0xff			/*  __u8  ep_bInterval; 255 ms */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+/***************************************************************************
+ * Function Name : rh_send_irq
+ * 
+ * This function examine the port change in the virtual root hub.
+ * 
+ * Note: This function assumes only one port exist in the root hub.
+ *
+ * Input:  hci = data structure for the host controller
+ *         rh_data = The pointer to port change data
+ *         rh_len = length of the data in bytes
+ *
+ * Return: length of data  
+ **************************************************************************/
+static int rh_send_irq (hci_t * hci, void *rh_data, int rh_len)
+{
+	int num_ports;
+	int i;
+	int ret;
+	int len;
+	__u8 data[8];
+
+	DBGFUNC ("enter rh_send_irq: \n");
+
+	/* Assuming the root hub has one port.  This value need to change if
+	 * there are more than one port for the root hub
+	 */
+
+	num_ports = 1;
+
+	/* The root hub status is not implemented, it basically has two fields:
+	 *     -- Local Power Status
+	 *     -- Over Current Indicator
+	 *     -- Local Power Change
+	 *     -- Over Current Indicator
+	 *
+	 * Right now, It is assume the power is good and no changes 
+	 */
+
+	*(__u8 *) data = 0;
+
+	ret = *(__u8 *) data;
+
+	/* Has the port status change within the root hub: It checks for
+	 *      -- Port Connect Status change
+	 *      -- Port Enable Change
+	 */
+
+	for (i = 0; i < num_ports; i++) {
+		*(__u8 *) (data + (i + 1) / 8) |=
+		    (((getPortStatusAndChange (hci) >> 16) & (PORT_CONNECT_STAT | PORT_ENABLE_STAT)) ? 1 : 0) << ((i + 1) % 8);
+		ret += *(__u8 *) (data + (i + 1) / 8);
+
+		/* After the port change is read, it should be reset so the next time 
+		 * is it doesn't trigger a change again */
+
+	}
+	len = i / 8 + 1;
+
+	if (ret > 0) {
+		memcpy (rh_data, data, min (len, min (rh_len, (int)sizeof (data))));
+		return len;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : rh_int_timer_do
+ * 
+ * This function is called when the timer expires.  It gets the the port 
+ * change data and pass along to the upper protocol.
+ * 
+ * Note:  The virtual root hub interrupt pipe are polled by the timer
+ *        every "interval" ms
+ *
+ * Input:  ptr = ptr to the urb
+ *
+ * Return: none  
+ **************************************************************************/
+static void rh_int_timer_do (unsigned long ptr)
+{
+	int len;
+	struct urb *urb = (struct urb *) ptr;
+	hci_t *hci = urb->dev->bus->hcpriv;
+
+	DBGFUNC ("enter rh_int_timer_do\n");
+
+	if (hci->rh.send) {
+		len = rh_send_irq (hci, urb->transfer_buffer,
+				   urb->transfer_buffer_length);
+		if (len > 0) {
+			urb->actual_length = len;
+			if (urb_debug == 2)
+				urb_print (urb, "RET-t(rh)",
+					   usb_pipeout (urb->pipe));
+
+			if (urb->complete) {
+				urb->complete (urb);
+			}
+		}
+	}
+
+	/* re-activate the timer */
+	rh_init_int_timer (urb);
+}
+
+/***************************************************************************
+ * Function Name : rh_init_int_timer
+ * 
+ * This function creates a timer that act as interrupt pipe in the
+ * virtual hub.   
+ * 
+ * Note:  The virtual root hub's interrupt pipe are polled by the timer
+ *        every "interval" ms
+ *
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_init_int_timer (struct urb * urb)
+{
+	hci_t *hci = urb->dev->bus->hcpriv;
+	hci->rh.interval = urb->interval;
+
+	init_timer (&hci->rh.rh_int_timer);
+	hci->rh.rh_int_timer.function = rh_int_timer_do;
+	hci->rh.rh_int_timer.data = (unsigned long) urb;
+	hci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
+	add_timer (&hci->rh.rh_int_timer);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* helper macro */
+#define OK(x) 			len = (x); break
+
+/***************************************************************************
+ * Function Name : rh_submit_urb
+ * 
+ * This function handles all USB request to the the virtual root hub
+ * 
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_submit_urb (struct urb * urb)
+{
+	struct usb_device *usb_dev = urb->dev;
+	hci_t *hci = usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+	void *data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = TD_CC_NOERROR;
+	__u32 datab[4];
+	__u8 *data_buf = (__u8 *) datab;
+
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	DBGFUNC ("enter rh_submit_urb\n");
+	if (usb_pipeint (pipe)) {
+		hci->rh.urb = urb;
+		hci->rh.send = 1;
+		hci->rh.interval = urb->interval;
+		rh_init_int_timer (urb);
+		urb->status = cc_to_error (TD_CC_NOERROR);
+
+		return 0;
+	}
+
+	bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
+	wValue = le16_to_cpu (cmd->wValue);
+	wIndex = le16_to_cpu (cmd->wIndex);
+	wLength = le16_to_cpu (cmd->wLength);
+
+	DBG ("rh_submit_urb, req = %d(%x) len=%d",
+	     bmRType_bReq, bmRType_bReq, wLength);
+
+	switch (bmRType_bReq) {
+		/* Request Destination:
+		   without flags: Device, 
+		   RH_INTERFACE: interface, 
+		   RH_ENDPOINT: endpoint,
+		   RH_CLASS means HUB here, 
+		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+		 */
+
+	case RH_GET_STATUS:
+		*(__u16 *) data_buf = cpu_to_le16 (1);
+		OK (2);
+
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *) data_buf = cpu_to_le16 (0);
+		OK (2);
+
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *) data_buf = cpu_to_le16 (0);
+		OK (2);
+
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *) data_buf = cpu_to_le32 (0);
+		OK (4);
+
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		*(__u32 *) data_buf =
+		    cpu_to_le32 (getPortStatusAndChange (hci));
+		OK (4);
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+		case (RH_ENDPOINT_STALL):
+			OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+		case RH_C_HUB_LOCAL_POWER:
+			OK (0);
+
+		case (RH_C_HUB_OVER_CURRENT):
+			/* Over Current Not Implemented */
+			OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_ENABLE):
+			clrPortStatus (hci, PORT_ENABLE_STAT);
+			OK (0);
+
+		case (RH_PORT_SUSPEND):
+			clrPortStatus (hci, PORT_SUSPEND_STAT);
+			OK (0);
+
+		case (RH_PORT_POWER):
+			clrPortStatus (hci, PORT_POWER_STAT);
+			OK (0);
+
+		case (RH_C_PORT_CONNECTION):
+			clrPortChange (hci, PORT_CONNECT_STAT);
+			OK (0);
+
+		case (RH_C_PORT_ENABLE):
+			clrPortChange (hci, PORT_ENABLE_STAT);
+			OK (0);
+
+		case (RH_C_PORT_SUSPEND):
+			clrPortChange (hci, PORT_SUSPEND_STAT);
+			OK (0);
+
+		case (RH_C_PORT_OVER_CURRENT):
+			clrPortChange (hci, PORT_OVER_CURRENT_STAT);
+			OK (0);
+
+		case (RH_C_PORT_RESET):
+			clrPortChange (hci, PORT_RESET_STAT);
+			OK (0);
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_SUSPEND):
+			setPortStatus (hci, PORT_SUSPEND_STAT);
+			OK (0);
+
+		case (RH_PORT_RESET):
+			setPortStatus (hci, PORT_RESET_STAT);
+			// USBReset(hci);
+			clrPortChange (hci,
+				       PORT_CONNECT_CHANGE | PORT_ENABLE_CHANGE
+				       | PORT_SUSPEND_CHANGE |
+				       PORT_OVER_CURRENT_CHANGE);
+			setPortChange (hci, PORT_RESET_CHANGE);
+			clrPortStatus (hci, PORT_RESET_STAT);
+			setPortStatus (hci, PORT_ENABLE_STAT);
+
+			OK (0);
+
+		case (RH_PORT_POWER):
+			setPortStatus (hci, PORT_POWER_STAT);
+			OK (0);
+
+		case (RH_PORT_ENABLE):
+			setPortStatus (hci, PORT_ENABLE_STAT);
+			OK (0);
+		}
+		break;
+
+	case RH_SET_ADDRESS:
+		hci->rh.devnum = wValue;
+		OK (0);
+
+	case RH_GET_DESCRIPTOR:
+		DBGVERBOSE ("rh_submit_urb: RH_GET_DESCRIPTOR, wValue = 0x%x\n", wValue);
+		switch ((wValue & 0xff00) >> 8) {
+		case (0x01):	/* device descriptor */
+			len = min (leni, min ((__u16)sizeof (root_hub_dev_des), wLength));
+			data_buf = root_hub_dev_des;
+			OK (len);
+
+		case (0x02):	/* configuration descriptor */
+			len = min (leni, min ((__u16)sizeof (root_hub_config_des), wLength));
+			data_buf = root_hub_config_des;
+			OK (len);
+
+		case (0x03):	/* string descriptors */
+			len = usb_root_hub_string (wValue & 0xff, (int) (long) 0,
+						   "SL811HS", data, wLength);
+			if (len > 0) {
+				data_buf = data;
+				OK (min (leni, len));
+			}
+
+		default:
+			status = SL11H_STATMASK_STALL;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		data_buf[0] = 9;	// min length;
+		data_buf[1] = 0x29;
+		data_buf[2] = 1;	// # of downstream port
+		data_buf[3] = 0;
+		datab[1] = 0;
+		data_buf[5] = 50;	// 100 ms for port reset
+		data_buf[7] = 0xfc;	// which port is attachable
+		if (data_buf[2] < 7) {
+			data_buf[8] = 0xff;
+		} else {
+		}
+
+		len = min (leni, min ((__u16)data_buf[0], wLength));
+		OK (len);
+
+	case RH_GET_CONFIGURATION:
+		*(__u8 *) data_buf = 0x01;
+		OK (1);
+
+	case RH_SET_CONFIGURATION:
+		OK (0);
+
+	default:
+		DBGERR ("unsupported root hub command");
+		status = SL11H_STATMASK_STALL;
+	}
+
+	len = min (len, leni);
+	if (data != data_buf)
+		memcpy (data, data_buf, len);
+	urb->actual_length = len;
+	urb->status = cc_to_error (status);
+
+	urb->hcpriv = NULL;
+	urb->dev = NULL;
+	if (urb->complete) {
+		urb->complete (urb);
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : rh_unlink_urb
+ * 
+ * This function unlinks the URB 
+ * 
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_unlink_urb (struct urb * urb)
+{
+	hci_t *hci = urb->dev->bus->hcpriv;
+
+	DBGFUNC ("enter rh_unlink_urb\n");
+	if (hci->rh.urb == urb) {
+		hci->rh.send = 0;
+		del_timer (&hci->rh.rh_int_timer);
+		hci->rh.urb = NULL;
+
+		urb->hcpriv = NULL;
+		usb_put_dev (urb->dev);
+		urb->dev = NULL;
+		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+			urb->status = -ECONNRESET;
+			if (urb->complete) {
+				urb->complete (urb);
+			}
+		} else
+			urb->status = -ENOENT;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : rh_connect_rh
+ * 
+ * This function connect the virtual root hub to the USB stack 
+ * 
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_connect_rh (hci_t * hci)
+{
+	struct usb_device *usb_dev;
+
+	hci->rh.devnum = 0;
+	usb_dev = usb_alloc_dev (NULL, hci->bus);
+	if (!usb_dev)
+		return -ENOMEM;
+
+	hci->bus->root_hub = usb_dev;
+	usb_connect (usb_dev);
+	if (usb_new_device (usb_dev) != 0) {
+		usb_free_dev (usb_dev);
+		return -ENODEV;
+	}
+
+	return 0;
+}
diff -Nru a/drivers/usb/host/usb-uhci-dbg.c b/drivers/usb/host/usb-uhci-dbg.c
--- a/drivers/usb/host/usb-uhci-dbg.c	Wed May 29 11:43:03 2002
+++ b/drivers/usb/host/usb-uhci-dbg.c	Wed May 29 11:43:03 2002
@@ -5,7 +5,7 @@
     Georg Acher      +    Deti Fliegl    +    Thomas Sailer
     georg@acher.org      deti@fliegl.de   sailer@ife.ee.ethz.ch
   
-    $Id: usb-uhci-dbg.c,v 1.1 2002/05/14 20:36:57 acher Exp $
+    $Id: usb-uhci-dbg.c,v 1.2 2002/05/21 21:40:16 acher Exp $
 */
 
 #ifdef DEBUG
@@ -105,7 +105,7 @@
 
 void uhci_show_status (struct uhci_hcd *uhci)
 {
-	unsigned int io_addr = (int)uhci->hcd.regs;
+	unsigned long io_addr = (unsigned long)uhci->hcd.regs;
 	unsigned short usbcmd, usbstat, usbint, usbfrnum;
 	unsigned int flbaseadd;
 	unsigned char sof;
diff -Nru a/drivers/usb/host/usb-uhci-hcd.c b/drivers/usb/host/usb-uhci-hcd.c
--- a/drivers/usb/host/usb-uhci-hcd.c	Wed May 29 11:43:02 2002
+++ b/drivers/usb/host/usb-uhci-hcd.c	Wed May 29 11:43:02 2002
@@ -13,7 +13,7 @@
     HW-initalization based on material of
     Randy Dunlap + Johannes Erdfelt + Gregory P. Smith + Linus Torvalds 
 
-    $Id: usb-uhci-hcd.c,v 1.1 2002/05/14 20:36:57 acher Exp $
+    $Id: usb-uhci-hcd.c,v 1.3 2002/05/25 16:42:41 acher Exp $
  */
 
 #include <linux/config.h>
@@ -37,7 +37,6 @@
 #include <asm/byteorder.h>
 #include <linux/usb.h>
 
-#define CONFIG_USB_DEBUG
 #ifdef CONFIG_USB_DEBUG
 	#define DEBUG
 #else
@@ -47,34 +46,34 @@
 #include "../core/hcd.h"
 #include "usb-uhci-hcd.h"
 
-#define DRIVER_VERSION "$Revision: 1.1 $"
+#define DRIVER_VERSION "$Revision: 1.3 $"
 #define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer"
 #define DRIVER_DESC "USB 1.1 Universal Host Controller Interface driver (HCD)"
-/*--------------------------------------------------------------------------*/
-// Values you may tweak
 
-/* CONFIG_USB_UHCI_HIGH_BANDWITH turns on Full Speed Bandwidth
- * Reclamation: feature that puts loop on descriptor loop when
+/*--------------------------------------------------------------------------*/
+/* Values you may tweak with module parameters
+ *  
+ * high_bw: 1=on (default), 0=off
+ * Turns on Full Speed Bandwidth Reclamation: 
+ * Feature that puts a loop on the descriptor chain when
  * there's some transfer going on. With FSBR, USB performance
  * is optimal, but PCI can be slowed down up-to 5 times, slowing down
  * system performance (eg. framebuffer devices).
- */
-#define CONFIG_USB_UHCI_HIGH_BANDWIDTH 
-
-/* *_DEPTH_FIRST puts descriptor in depth-first mode. This has
- * somehow similar effect to FSBR (higher speed), but does not
+ *
+ * bulk_depth/ctrl_depth: 0=off (default), 1:on
+ * Puts descriptors for bulk/control transfers in depth-first mode. 
+ * This has somehow similar effect to FSBR (higher speed), but does not
  * slow PCI down. OTOH USB performace is slightly slower than
  * in FSBR case and single device could hog whole USB, starving
- * other devices.
- */
-#define USE_CTRL_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
-#define USE_BULK_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
-
-/* Turning off both CONFIG_USB_UHCI_HIGH_BANDWITH and *_DEPTH_FIRST
+ * other devices. Some devices (e.g. STV680-based cameras) NEED this depth 
+ * first search to work properly.
+ *
+ * Turning off both high_bw and bulk_depth/ctrl_depth
  * will lead to <64KB/sec performance over USB for bulk transfers targeting
  * one device's endpoint. You probably do not want to do that.
  */
 
+// Other constants, there's usually no need to change them.
 // stop bandwidth reclamation after (roughly) 50ms
 #define IDLE_TIMEOUT  (HZ/20)
 
@@ -100,6 +99,14 @@
 //                   NO serviceable parts below!
 /*--------------------------------------------------------------------------*/
 
+/* Can be set by module parameters */
+static int high_bw = 1;
+static int ctrl_depth = 0;  /* 0: Breadth first, 1: Depth first */
+static int bulk_depth = 0;  /* 0: Breadth first, 1: Depth first */
+
+// How much URBs with ->next are walked
+#define MAX_NEXT_COUNT 2048
+
 static struct uhci *devs = NULL;
 
 /* used by userspace UHCI data structure dumper */
@@ -155,7 +162,6 @@
 
 	spin_lock_irqsave (&uhci->urb_list_lock, flags);
 
-
 	queued_urb = search_dev_ep (uhci, urb); // returns already queued urb for that pipe
 
 	if (queued_urb) {
@@ -165,7 +171,7 @@
 		    ((type == PIPE_BULK) &&
 		     (!(urb->transfer_flags & USB_QUEUE_BULK) || !(queued_urb->transfer_flags & USB_QUEUE_BULK)))) {
 			spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-			err("ENXIO (%s)  %08x, flags %x, urb %p, burb %p, propably device driver bug...", 
+			err("ENXIO (%s)  %08x, flags %x, urb %p, burb %p, probably device driver bug...", 
 			    PIPESTRING(type),
 			    urb->pipe,urb->transfer_flags,urb,queued_urb);
 			return -ENXIO;	// urb already queued
@@ -196,7 +202,7 @@
 							       PCI_DMA_TODEVICE);
 
 	// for bulk queuing it is essential that interrupts are disabled until submission
-	// all other type enable interrupts again
+	// all other types enable interrupts again
 	switch (type) {
 	case PIPE_BULK:
 		if (queued_urb) {
@@ -293,7 +299,7 @@
 /*--------------------------------------------------------------------------*/
 static int hc_reset (struct uhci_hcd *uhci)
 {
-	unsigned int io_addr = (int)uhci->hcd.regs;
+	unsigned long io_addr = (unsigned long)uhci->hcd.regs;
 
 	uhci->apm_state = 0;
 	uhci->running = 0;
@@ -306,7 +312,7 @@
 /*--------------------------------------------------------------------------*/
 static int hc_irq_run(struct uhci_hcd *uhci)
 {
-	unsigned int io_addr = (int)uhci->hcd.regs;
+	unsigned long io_addr = (unsigned long)uhci->hcd.regs;
 	/* Turn on all interrupts */
 	outw (USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
 
@@ -324,7 +330,7 @@
 /*--------------------------------------------------------------------------*/
 static int hc_start (struct uhci_hcd *uhci)
 {
-	unsigned int io_addr = (int)uhci->hcd.regs;
+	unsigned long io_addr = (unsigned long)uhci->hcd.regs;
 	int timeout = 10;
 	struct usb_device	*udev;
 	init_dbg("hc_start uhci %p",uhci);
@@ -351,7 +357,6 @@
 	uhci->hcd.state = USB_STATE_READY;
 	if (!udev) {
 	    uhci->running = 0;
-// FIXME cleanup
 	    return -ENOMEM;
 	}
 
@@ -360,7 +365,6 @@
 	if (usb_register_root_hub (udev, &uhci->hcd.pdev->dev) != 0) {
 		usb_free_dev (udev); 
 		uhci->running = 0;
-// FIXME cleanup
 		return -ENODEV;
 	}
 	
@@ -374,7 +378,7 @@
 {
 	struct uhci_hcd	*uhci = hcd_to_uhci (hcd);
 	int ret;
-	int io_addr=(int)hcd->regs, io_size=0x20; // FIXME
+	unsigned long io_addr=(unsigned long)hcd->regs, io_size=0x20;
 	
 	init_dbg("uhci_start hcd %p uhci %p, pdev %p",hcd,uhci,hcd->pdev);
 	/* disable legacy emulation, Linux takes over... */
@@ -448,7 +452,7 @@
 static void uhci_irq (struct usb_hcd *hcd)
 {	
 	struct uhci_hcd	*uhci = hcd_to_uhci (hcd);
-	unsigned int io_addr = (int)hcd->regs;
+	unsigned long io_addr = (unsigned long)hcd->regs;
 	unsigned short status;
 	struct list_head *p, *p2;
 	int restarts, work_done;
@@ -589,6 +593,12 @@
 MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_DESCRIPTION (DRIVER_INFO);
 MODULE_LICENSE ("GPL");
+MODULE_PARM (high_bw, "i");
+MODULE_PARM_DESC (high_bw, "high_hw: Enable high bandwidth mode, 1=on (default), 0=off"); 
+MODULE_PARM (bulk_depth, "i");
+MODULE_PARM_DESC (bulk_depth, "bulk_depth: Depth first processing for bulk transfers, 0=off (default), 1=on");
+MODULE_PARM (ctrl_depth, "i");
+MODULE_PARM_DESC (ctrl_depth, "ctrl_depth: Depth first processing for control transfers, 0=off (default), 1=on");
 
 static const struct pci_device_id __devinitdata pci_ids [] = { {
 
@@ -627,6 +637,10 @@
 	init_dbg (DRIVER_INFO);
 	init_dbg ("block sizes: hq %d td %d",
 		sizeof (struct qh), sizeof (struct td));
+	info("High bandwidth mode %s.%s%s",
+	     high_bw?"enabled":"disabled",
+	     ctrl_depth?"CTRL depth first enabled":"",
+	     bulk_depth?"BULK depth first enabled":"");
 	return pci_module_init (&uhci_pci_driver);
 }
 
diff -Nru a/drivers/usb/host/usb-uhci-hub.c b/drivers/usb/host/usb-uhci-hub.c
--- a/drivers/usb/host/usb-uhci-hub.c	Wed May 29 11:43:03 2002
+++ b/drivers/usb/host/usb-uhci-hub.c	Wed May 29 11:43:03 2002
@@ -13,7 +13,7 @@
     HW-initalization based on material of
     Randy Dunlap + Johannes Erdfelt + Gregory P. Smith + Linus Torvalds 
 
-    $Id: usb-uhci-hub.c,v 1.1 2002/05/14 20:36:57 acher Exp $
+    $Id: usb-uhci-hub.c,v 1.2 2002/05/21 21:40:16 acher Exp $
 */
 
 #define CLR_RH_PORTSTAT(x) \
@@ -34,7 +34,7 @@
 static int uhci_hub_status_data (struct usb_hcd *hcd, char *buf)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci (hcd);
-	unsigned int io_addr = (int)uhci->hcd.regs;
+	unsigned long io_addr = (unsigned long)uhci->hcd.regs;
 	int i, len=0, data = 0, portstate;
 	int changed=0;
 
@@ -99,7 +99,7 @@
 	int status = 0;
 	int stat = 0;
 	int cstatus;
-	unsigned int io_addr = (int)uhci->hcd.regs;
+	unsigned long io_addr = (unsigned long)uhci->hcd.regs;
 	int		ports = uhci->maxports;
 
 	switch (typeReq) {	
diff -Nru a/drivers/usb/host/usb-uhci-mem.c b/drivers/usb/host/usb-uhci-mem.c
--- a/drivers/usb/host/usb-uhci-mem.c	Wed May 29 11:43:03 2002
+++ b/drivers/usb/host/usb-uhci-mem.c	Wed May 29 11:43:03 2002
@@ -14,7 +14,7 @@
     HW-initalization based on material of
     Randy Dunlap + Johannes Erdfelt + Gregory P. Smith + Linus Torvalds 
 
-    $Id: usb-uhci-mem.c,v 1.1 2002/05/14 20:36:57 acher Exp $
+    $Id: usb-uhci-mem.c,v 1.3 2002/05/25 16:42:41 acher Exp $
  */
 
 /*###########################################################################*/
@@ -387,10 +387,9 @@
 	wmb();
 }
 /*-------------------------------------------------------------------*/
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
 static void enable_desc_loop(struct uhci_hcd *uhci, struct urb *urb)
 {
-	int flags;
+	unsigned long flags;
 
 	if (urb->transfer_flags & USB_NO_FSBR)
 		return;
@@ -405,7 +404,7 @@
 /*-------------------------------------------------------------------*/
 static void disable_desc_loop(struct uhci_hcd *uhci, struct urb *urb)
 {
-	int flags;
+	unsigned long flags;
 
 	if (urb->transfer_flags & USB_NO_FSBR)
 		return;
@@ -422,18 +421,16 @@
 	}
 	spin_unlock_irqrestore (&uhci->qh_lock, flags);
 }
-#endif
 /*-------------------------------------------------------------------*/
 static void queue_urb_unlocked (struct uhci_hcd *uhci, struct urb *urb)
 {
 	urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
 	int type;
 	type=usb_pipetype (urb->pipe);
 	
-	if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
+	if (high_bw && ((type == PIPE_BULK) || (type == PIPE_CONTROL)))
 			enable_desc_loop(uhci, urb);
-#endif
+
 	urb->status = -EINPROGRESS;
 	priv->started=jiffies;
 
@@ -455,14 +452,12 @@
 static void dequeue_urb (struct uhci_hcd *uhci, struct urb *urb)
 {
 	urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
 	int type;
 	dbg("dequeue URB %p",urb);
 	type=usb_pipetype (urb->pipe);
 
-	if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
+	if (high_bw && ((type == PIPE_BULK) || (type == PIPE_CONTROL)))
 		disable_desc_loop(uhci, urb);
-#endif
 
 	list_del (&priv->urb_list);
 	if (urb->timeout && uhci->timeout_urbs)
@@ -624,10 +619,10 @@
 	insert_qh (uhci, uhci->bulk_chain, qh, 0);
 	uhci->control_chain = qh;
 
-#ifdef	CONFIG_USB_UHCI_HIGH_BANDWIDTH
 	// disabled reclamation loop
-	set_qh_head(uhci->chain_end, uhci->control_chain->dma_addr | UHCI_PTR_QH | UHCI_PTR_TERM);
-#endif
+	if (high_bw)
+		set_qh_head(uhci->chain_end, uhci->control_chain->dma_addr | UHCI_PTR_QH | UHCI_PTR_TERM);
+
 
 	init_dbg("allocating qh: ls_control_chain");
 	if (alloc_qh (uhci, &qh))
diff -Nru a/drivers/usb/host/usb-uhci-q.c b/drivers/usb/host/usb-uhci-q.c
--- a/drivers/usb/host/usb-uhci-q.c	Wed May 29 11:43:01 2002
+++ b/drivers/usb/host/usb-uhci-q.c	Wed May 29 11:43:01 2002
@@ -13,7 +13,7 @@
     HW-initalization based on material of
     Randy Dunlap + Johannes Erdfelt + Gregory P. Smith + Linus Torvalds 
 
-    $Id: usb-uhci-q.c,v 1.1 2002/05/14 20:36:57 acher Exp $
+    $Id: usb-uhci-q.c,v 1.3 2002/05/25 16:42:41 acher Exp $
 */
 
 /*-------------------------------------------------------------------*/
@@ -59,7 +59,7 @@
 	urb_priv_t *urb_priv = urb->hcpriv;
 	unsigned long destination, status;
 	int maxsze = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
-	int depth_first=USE_CTRL_DEPTH_FIRST;  // UHCI descriptor chasing method
+	int depth_first = ctrl_depth;  // UHCI descriptor chasing method
 	unsigned long len;
 	char *data;
 
@@ -175,7 +175,7 @@
 	unsigned int pipe = urb->pipe;
 	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
 	int info, len, last;
-	int depth_first=USE_BULK_DEPTH_FIRST;  // UHCI descriptor chasing method
+	int depth_first = bulk_depth;  // UHCI descriptor chasing method
 
 	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
 		return -EPIPE;
@@ -305,7 +305,7 @@
 static int uhci_submit_int_urb (struct uhci_hcd *uhci, struct urb *urb)
 {
 	urb_priv_t *urb_priv = urb->hcpriv;
-	int nint, n;
+	int nint;
 	uhci_desc_t *td;
 	int status, destination;
 	int info;
@@ -313,16 +313,14 @@
 	
 	if (urb->interval == 0)
 		nint = 0;
-	else {  // round interval down to 2^n
-		for (nint = 0, n = 1; nint <= 8; nint++, n += n)	
-			if (urb->interval < n) {
-				urb->interval = n / 2;
-				break;
-			}
-		nint--;
+	else {  
+		// log2-function (urb->interval already 2^n)
+		nint = ffs(urb->interval);
+		if (nint>7)
+			nint=7;
 	}
 
-	dbg("Rounded interval to %i, chain  %i", urb->interval, nint);
+	dbg("INT-interval %i, chain  %i", urb->interval, nint);
 	// remember start frame, just in case...
 	urb->start_frame = UHCI_GET_CURRENT_FRAME (uhci) & 1023;	
 
@@ -381,7 +379,7 @@
 	}
 	
 	if (last_urb) {
-		*end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
+		*end = (last_urb->start_frame + last_urb->number_of_packets*last_urb->interval) & 1023;
 		ret=0;
 	}
 	
@@ -395,12 +393,14 @@
 static int iso_find_start (struct uhci_hcd *uhci, struct urb *urb)
 {
 	unsigned int now;
-	unsigned int start_limit = 0, stop_limit = 0, queued_size;
+	unsigned int start_limit = 0, stop_limit = 0, queued_size, number_of_frames;
 	int limits;
 
 	now = UHCI_GET_CURRENT_FRAME (uhci) & 1023;
 
-	if ((unsigned) urb->number_of_packets > 900)
+	number_of_frames = (unsigned) (urb->number_of_packets*urb->interval);
+
+	if ( number_of_frames > 900)
 		return -EFBIG;
 	
 	limits = find_iso_limits (uhci, urb, &start_limit, &stop_limit);
@@ -415,17 +415,17 @@
 		else {
 			urb->start_frame = stop_limit;		// seamless linkage
 
-			if (((now - urb->start_frame) & 1023) <= (unsigned) urb->number_of_packets) {
+			if (((now - urb->start_frame) & 1023) <= (unsigned) number_of_frames) {
 				info("iso_find_start: gap in seamless isochronous scheduling");
-				dbg("iso_find_start: now %u start_frame %u number_of_packets %u pipe 0x%08x",
-					now, urb->start_frame, urb->number_of_packets, urb->pipe);
+				dbg("iso_find_start: now %u start_frame %u number_of_packets %u interval %u pipe 0x%08x",
+					now, urb->start_frame, urb->number_of_packets, urb->interval, urb->pipe);
 				urb->start_frame = (now + 5) & 1023;	// 5ms setup should be enough
 			}
 		}
 	}
 	else {
 		urb->start_frame &= 1023;
-		if (((now - urb->start_frame) & 1023) < (unsigned) urb->number_of_packets) {
+		if (((now - urb->start_frame) & 1023) < number_of_frames) {
 			dbg("iso_find_start: now between start_frame and end");
 			return -EAGAIN;
 		}
@@ -436,7 +436,7 @@
 		return 0;
 
 	if (((urb->start_frame - start_limit) & 1023) < queued_size ||
-	    ((urb->start_frame + urb->number_of_packets - 1 - start_limit) & 1023) < queued_size) {
+	    ((urb->start_frame + number_of_frames - 1 - start_limit) & 1023) < queued_size) {
 		dbg("iso_find_start: start_frame %u number_of_packets %u start_limit %u stop_limit %u",
 			urb->start_frame, urb->number_of_packets, start_limit, stop_limit);
 		return -EAGAIN;
@@ -507,7 +507,7 @@
 			 urb_priv->transfer_buffer_dma + urb->iso_frame_desc[n].offset);
 		list_add_tail (&td->desc_list, &urb_priv->desc_list);
 	
-		insert_td_horizontal (uhci, uhci->iso_td[(urb->start_frame + n) & 1023], td);	// store in iso-tds
+		insert_td_horizontal (uhci, uhci->iso_td[(urb->start_frame + n*urb->interval) & 1023], td);	// store in iso-tds
 	}
 
 	kfree (tdm);
@@ -742,6 +742,7 @@
 
 	switch (usb_pipetype (urb->pipe)) {
 	case PIPE_INTERRUPT:
+		urb_priv->flags = 0; // mark as deleted (if called from completion)
 		uhci_do_toggle (urb);
 
 	case PIPE_ISOCHRONOUS:
@@ -853,12 +854,9 @@
 			async_dbg("uhci_check_timeout: timeout for %p",urb);
 			uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
 		}
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-		else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
+		else if (high_bw && ((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
 			 (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))
 			disable_desc_loop(uhci, urb);
-#endif
-
 	}
 	uhci->timeout_check=jiffies;
 }
@@ -1040,9 +1038,8 @@
 	uhci_clean_transfer(uhci, urb, qh, mode);
 	urb->status = status;
 
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH	
-	disable_desc_loop(uhci,urb);
-#endif	
+	if (high_bw)
+		disable_desc_loop(uhci,urb);
 
 	dbg("process_transfer: (end) urb %p, wanted len %d, len %d status %x err %d",
 		urb,urb->transfer_buffer_length,urb->actual_length, urb->status, urb->error_count);
@@ -1088,21 +1085,19 @@
 			urb->actual_length = actual_length;
 
 	recycle:
+		((urb_priv_t*)urb->hcpriv)->flags=1; // set to detect unlink during completion
+
 		uhci_urb_dma_sync(uhci, urb, urb->hcpriv);
 		if (urb->complete) {
 			//dbg("process_interrupt: calling completion, status %i",status);
 			urb->status = status;
-			((urb_priv_t*)urb->hcpriv)->flags=1; // if unlink_urb is called during completion
-
 			spin_unlock(&uhci->urb_list_lock);
 			urb->complete ((struct urb *) urb);
 			spin_lock(&uhci->urb_list_lock);
-
-			((urb_priv_t*)urb->hcpriv)->flags=0; // FIXME: unlink in completion not handled...
 		}
 		
 		if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) &&
-			    (urb->status != -ENOENT)) {
+			    (urb->status != -ENOENT) && ((urb_priv_t*)urb->hcpriv)->flags) {
 
 			urb->status = -EINPROGRESS;
 
@@ -1125,7 +1120,7 @@
 				mb();
 			}
 			else {
-				uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);				
+				uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
 				uhci_do_toggle (urb); // correct toggle after unlink
 				clr_td_ioc(desc);    // inactivate TD
 			}
@@ -1199,7 +1194,6 @@
 		p_tmp = p;
 		p = p->next;
 		list_del (p_tmp);
-//		delete_desc (uhci, desc);
 
 		// add to cool down pool
 		INIT_LIST_HEAD(&desc->horizontal);
@@ -1243,19 +1237,18 @@
 		break;
 	}
 
-	if (urb->status != -EINPROGRESS) {
+	if (urb->status != -EINPROGRESS && type != PIPE_INTERRUPT) {
 
 		dequeue_urb (uhci, urb);
+ 		uhci_free_priv(uhci, urb, urb->hcpriv);
 
-		uhci_free_priv(uhci, urb, urb->hcpriv);
+		spin_unlock(&uhci->urb_list_lock);
+		dbg("giveback urb %p, status %i, length %i\n", 
+		    urb, urb->status, urb->transfer_buffer_length);
+		
+		usb_hcd_giveback_urb(&uhci->hcd, urb);
+		spin_lock(&uhci->urb_list_lock);
 
-		if (type != PIPE_INTERRUPT) {  // process_interrupt does completion on its own		
-			spin_unlock(&uhci->urb_list_lock);
-			dbg("giveback urb %p, status %i, length %i\n", 
-			    urb, urb->status, urb->transfer_buffer_length);
-			usb_hcd_giveback_urb(&uhci->hcd, urb);
-			spin_lock(&uhci->urb_list_lock);
-		}
 	}
 	return ret;
 }
diff -Nru a/drivers/usb/image/Makefile b/drivers/usb/image/Makefile
--- a/drivers/usb/image/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/usb/image/Makefile	Wed May 29 11:43:01 2002
@@ -2,8 +2,6 @@
 # Makefile for USB Image drivers
 #
 
-O_TARGET	:= image.o
-
 obj-$(CONFIG_USB_MDC800)	+= mdc800.o
 obj-$(CONFIG_USB_HPUSBSCSI)	+= hpusbscsi.o
 obj-$(CONFIG_USB_MICROTEK)	+= microtek.o
diff -Nru a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
--- a/drivers/usb/input/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/usb/input/Makefile	Wed May 29 11:43:01 2002
@@ -2,8 +2,6 @@
 # Makefile for the USB input drivers
 #
 
-O_TARGET	:= input.o
-
 # Multipart objects.
 hid-objs	:= hid-core.o
 
diff -Nru a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile
--- a/drivers/usb/media/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/usb/media/Makefile	Wed May 29 11:43:01 2002
@@ -2,8 +2,6 @@
 # Makefile for USB Media drivers
 #
 
-O_TARGET	:= media.o
-
 export-objs	:= ov511.o pwc-uncompress.o usbvideo.o
 
 pwc-objs	:= pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o
diff -Nru a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
--- a/drivers/usb/misc/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/usb/misc/Makefile	Wed May 29 11:43:03 2002
@@ -3,8 +3,6 @@
 # (the ones that don't fit into any other categories)
 #
 
-O_TARGET	:= misc.o
-
 obj-$(CONFIG_USB_AUERSWALD)	+= auerswald.o
 obj-$(CONFIG_USB_BRLVGER)	+= brlvger.o
 obj-$(CONFIG_USB_EMI26)		+= emi26.o
diff -Nru a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile
--- a/drivers/usb/net/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/usb/net/Makefile	Wed May 29 11:43:01 2002
@@ -2,8 +2,6 @@
 # Makefile for USB Network drivers
 #
 
-O_TARGET	:= net.o
-
 obj-$(CONFIG_USB_CATC)		+= catc.o
 obj-$(CONFIG_USB_CDCETHER)	+= cdc-ether.o
 obj-$(CONFIG_USB_KAWETH)	+= kaweth.o
diff -Nru a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
--- a/drivers/usb/serial/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/usb/serial/Makefile	Wed May 29 11:43:02 2002
@@ -2,8 +2,6 @@
 # Makefile for the USB serial device drivers.
 #
 
-O_TARGET	:= serial.o
-
 # Object file lists.
 
 obj-$(CONFIG_USB_SERIAL)                        += usbserial.o
diff -Nru a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
--- a/drivers/usb/storage/Makefile	Wed May 29 11:43:03 2002
+++ b/drivers/usb/storage/Makefile	Wed May 29 11:43:03 2002
@@ -5,7 +5,6 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-O_TARGET	:= storage.o
 EXTRA_CFLAGS	:= -I../../scsi/
 
 obj-$(CONFIG_USB_STORAGE)	+= usb-storage.o
diff -Nru a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h
--- a/drivers/usb/storage/debug.h	Wed May 29 11:43:03 2002
+++ b/drivers/usb/storage/debug.h	Wed May 29 11:43:03 2002
@@ -4,7 +4,7 @@
  * $Id: debug.h,v 1.6 2001/01/12 23:51:04 mdharm Exp $
  *
  * Current development and maintenance by:
- *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Initial work by:
  *   (c) 1999 Michael Gee (michael@linuxspecific.com)
diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
--- a/drivers/usb/storage/isd200.c	Wed May 29 11:43:03 2002
+++ b/drivers/usb/storage/isd200.c	Wed May 29 11:43:03 2002
@@ -1265,7 +1265,7 @@
 				/* ATA Command Identify successful */
 				int i;
 				__u16 *src, *dest;
-				ide_fix_driveid(&info->drive);
+				ata_fix_driveid(&info->drive);
 
 				US_DEBUGP("   Identify Data Structure:\n");
 				US_DEBUGP("      config = 0x%x\n", info->drive.config);
diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
--- a/drivers/usb/storage/scsiglue.c	Wed May 29 11:43:03 2002
+++ b/drivers/usb/storage/scsiglue.c	Wed May 29 11:43:03 2002
@@ -4,7 +4,7 @@
  * $Id: scsiglue.c,v 1.26 2002/04/22 03:39:43 mdharm Exp $
  *
  * Current development and maintenance by:
- *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Developed with the assistance of:
  *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
@@ -56,9 +56,6 @@
  */
 
 #define US_ACT_COMMAND		1
-#define US_ACT_DEVICE_RESET	2
-#define US_ACT_BUS_RESET	3
-#define US_ACT_HOST_RESET	4
 #define US_ACT_EXIT		5
 
 /***********************************************************************
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	Wed May 29 11:43:02 2002
+++ b/drivers/usb/storage/transport.c	Wed May 29 11:43:02 2002
@@ -351,6 +351,29 @@
  * Data transfer routines
  ***********************************************************************/
 
+/*
+ * This is subtle, so pay attention:
+ * ---------------------------------
+ * We're very concered about races with a command abort.  Hanging this code is
+ * a sure fire way to hang the kernel.
+ *
+ * The abort function first sets the machine state, then tries to acquire the
+ * lock on the current_urb to abort it.
+ *
+ * Once a function grabs the current_urb_sem, then it -MUST- test the state to
+ * see if we just got aborted before the lock was grabbed.  If so, it's
+ * essential to release the lock and return.
+ *
+ * The idea is that, once the current_urb_sem is held, the state can't really
+ * change anymore without also engaging the usb_unlink_urb() call _after_ the
+ * URB is actually submitted.
+ *
+ * So, we've guaranteed that (after the sm_state test), if we do submit the
+ * URB it will get aborted when we release the current_urb_sem.  And we've
+ * also guaranteed that if the abort code was called before we held the
+ * current_urb_sem, we can safely get out before the URB is submitted.
+ */
+
 /* This is the completion handler which will wake us up when an URB
  * completes.
  */
@@ -363,6 +386,9 @@
 
 /* This is the common part of the URB message submission code
  * This function expects the current_urb_sem to be held upon entry.
+ *
+ * All URBs from the usb-storage driver _must_ pass through this function
+ * (or something like it) for the abort mechanisms to work properly.
  */
 static int usb_stor_msg_common(struct us_data *us)
 {
@@ -385,16 +411,6 @@
 		return status;
 	}
 
-	/* has the current command been aborted? */
-	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-
-		/* avoid a race with usb_stor_abort_transport():
-		 *  if the abort took place before we submitted
-		 *  the URB, we must cancel it ourselves */
-		if (us->current_urb->status == -EINPROGRESS)
-			usb_unlink_urb(us->current_urb);
-		}
-
 	/* wait for the completion of the URB */
 	up(&(us->current_urb_sem));
 	wait_for_completion(&urb_done);
@@ -428,9 +444,15 @@
 	/* lock the URB */
 	down(&(us->current_urb_sem));
 
+	/* has the current command been aborted? */
+	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+		up(&(us->current_urb_sem));
+		return 0;
+	}
+
 	/* fill the URB */
 	FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, 
-			 (unsigned char*) &dr, data, size, 
+			 (unsigned char*) dr, data, size, 
 			 usb_stor_blocking_completion, NULL);
 
 	/* submit the URB */
@@ -456,6 +478,12 @@
 	/* lock the URB */
 	down(&(us->current_urb_sem));
 
+	/* has the current command been aborted? */
+	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+		up(&(us->current_urb_sem));
+		return 0;
+	}
+
 	/* fill the URB */
 	FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len,
 		      usb_stor_blocking_completion, NULL);
@@ -473,7 +501,15 @@
 
 /* This is a version of usb_clear_halt() that doesn't read the status from
  * the device -- this is because some devices crash their internal firmware
- * when the status is requested after a halt
+ * when the status is requested after a halt.
+ *
+ * A definitive list of these 'bad' devices is too difficult to maintain or
+ * make complete enough to be useful.  This problem was first observed on the
+ * Hagiwara FlashGate DUAL unit.  However, bus traces reveal that neither
+ * MacOS nor Windows checks the status after clearing a halt.
+ *
+ * Since many vendors in this space limit their testing to interoperability
+ * with these two OSes, specification violations like this one are common.
  */
 int usb_stor_clear_halt(struct us_data *us, int pipe)
 {
@@ -823,24 +859,31 @@
 
 	/* If the current state is wrong or if there's
 	 *  no srb, then there's nothing to do */
-	if ( !(state == US_STATE_RUNNING || state == US_STATE_RESETTING)
-		    || !us->srb) {
-		US_DEBUGP("-- invalid current state\n");
-		return;
-	}
+	BUG_ON((state != US_STATE_RUNNING && state != US_STATE_RESETTING));
+	BUG_ON(!(us->srb));
+
+	/* set state to abort */
 	atomic_set(&us->sm_state, US_STATE_ABORTING);
 
 	/* If the state machine is blocked waiting for an URB or an IRQ,
-	 *  let's wake it up */
+	 * let's wake it up */
 
-	/* if we have an URB pending, cancel it */
+	/* If we have an URB pending, cancel it.  Note that we guarantee with
+	 * the current_urb_sem that either (a) an URB has just been submitted,
+	 * or (b) the URB will never get submitted.  But, because of the use
+	 * of us->sm_state and current_urb_sem, we can't get an URB sumbitted
+	 * _after_ we set the state to US_STATE_ABORTING and this section of
+	 * code runs.  Thus we avoid deadlocks.
+	 */
+	down(&(us->current_urb_sem));
 	if (us->current_urb->status == -EINPROGRESS) {
 		US_DEBUGP("-- cancelling URB\n");
 		usb_unlink_urb(us->current_urb);
 	}
+	up(&(us->current_urb_sem));
 
-	/* if we are waiting for an IRQ, simulate it */
-	else if (test_bit(IP_WANTED, &us->bitflags)) {
+	/* If we are waiting for an IRQ, simulate it */
+	if (test_bit(IP_WANTED, &us->bitflags)) {
 		US_DEBUGP("-- simulating missing IRQ\n");
 		usb_stor_CBI_irq(us->irq_urb);
 	}
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c	Wed May 29 11:43:02 2002
+++ b/drivers/usb/storage/usb.c	Wed May 29 11:43:02 2002
@@ -104,9 +104,6 @@
  */
 
 #define US_ACT_COMMAND		1
-#define US_ACT_DEVICE_RESET	2
-#define US_ACT_BUS_RESET	3
-#define US_ACT_HOST_RESET	4
 #define US_ACT_EXIT		5
 
 /* The list of structures and the protective lock for them */
@@ -344,10 +341,12 @@
 	for(;;) {
 		struct Scsi_Host *host;
 		US_DEBUGP("*** thread sleeping.\n");
+		atomic_set(&us->sm_state, US_STATE_IDLE);
 		if(down_interruptible(&us->sema))
 			break;
 			
 		US_DEBUGP("*** thread awakened.\n");
+		atomic_set(&us->sm_state, US_STATE_RUNNING);
 
 		/* lock access to the queue element */
 		spin_lock_irq(&us->queue_exclusion);
@@ -361,145 +360,131 @@
 		/* release the queue lock as fast as possible */
 		spin_unlock_irq(&us->queue_exclusion);
 
-		switch (action) {
-		case US_ACT_COMMAND:
-			/* reject the command if the direction indicator 
-			 * is UNKNOWN
-			 */
-			if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) {
-				US_DEBUGP("UNKNOWN data direction\n");
-				us->srb->result = DID_ERROR << 16;
-				scsi_lock(host);
-				us->srb->scsi_done(us->srb);
-				us->srb = NULL;
-				scsi_unlock(host);
-				break;
-			}
+		/* exit if we get a signal to exit */
+		if (action == US_ACT_EXIT) {
+			US_DEBUGP("-- US_ACT_EXIT command received\n");
+			break;
+		}
 
-			/* reject if target != 0 or if LUN is higher than
-			 * the maximum known LUN
-			 */
-			if (us->srb->target && 
-					!(us->flags & US_FL_SCM_MULT_TARG)) {
-				US_DEBUGP("Bad target number (%d/%d)\n",
-					  us->srb->target, us->srb->lun);
-				us->srb->result = DID_BAD_TARGET << 16;
-
-				scsi_lock(host);
-				us->srb->scsi_done(us->srb);
-				us->srb = NULL;
-				scsi_unlock(host);
-				break;
-			}
+		BUG_ON(action != US_ACT_COMMAND);
 
-			if (us->srb->lun > us->max_lun) {
-				US_DEBUGP("Bad LUN (%d/%d)\n",
-					  us->srb->target, us->srb->lun);
-				us->srb->result = DID_BAD_TARGET << 16;
-
-				scsi_lock(host);
-				us->srb->scsi_done(us->srb);
-				us->srb = NULL;
-				scsi_unlock(host);
-				break;
-			}
-
-			/* handle those devices which can't do a START_STOP */
-			if ((us->srb->cmnd[0] == START_STOP) &&
-			    (us->flags & US_FL_START_STOP)) {
-				US_DEBUGP("Skipping START_STOP command\n");
-				us->srb->result = GOOD << 1;
+		/* reject the command if the direction indicator 
+		 * is UNKNOWN
+		 */
+		if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) {
+			US_DEBUGP("UNKNOWN data direction\n");
+			us->srb->result = DID_ERROR << 16;
+			scsi_lock(host);
+			us->srb->scsi_done(us->srb);
+			us->srb = NULL;
+			scsi_unlock(host);
+			continue;
+		}
 
-				scsi_lock(host);
-				us->srb->scsi_done(us->srb);
-				us->srb = NULL;
-				scsi_unlock(host);
-				break;
-			}
+		/* reject if target != 0 or if LUN is higher than
+		 * the maximum known LUN
+		 */
+		if (us->srb->target && 
+				!(us->flags & US_FL_SCM_MULT_TARG)) {
+			US_DEBUGP("Bad target number (%d/%d)\n",
+				  us->srb->target, us->srb->lun);
+			us->srb->result = DID_BAD_TARGET << 16;
+
+			scsi_lock(host);
+			us->srb->scsi_done(us->srb);
+			us->srb = NULL;
+			scsi_unlock(host);
+			continue;
+		}
+
+		if (us->srb->lun > us->max_lun) {
+			US_DEBUGP("Bad LUN (%d/%d)\n",
+				  us->srb->target, us->srb->lun);
+			us->srb->result = DID_BAD_TARGET << 16;
+
+			scsi_lock(host);
+			us->srb->scsi_done(us->srb);
+			us->srb = NULL;
+			scsi_unlock(host);
+			continue;
+		}
+
+		/* handle those devices which can't do a START_STOP */
+		if ((us->srb->cmnd[0] == START_STOP) &&
+		    (us->flags & US_FL_START_STOP)) {
+			US_DEBUGP("Skipping START_STOP command\n");
+			us->srb->result = GOOD << 1;
+
+			scsi_lock(host);
+			us->srb->scsi_done(us->srb);
+			us->srb = NULL;
+			scsi_unlock(host);
+			continue;
+		}
 
-			/* lock the device pointers */
-			down(&(us->dev_semaphore));
+		/* lock the device pointers */
+		down(&(us->dev_semaphore));
 
-			/* our device has gone - pretend not ready */
-			if (atomic_read(&us->sm_state) == US_STATE_DETACHED) {
-				US_DEBUGP("Request is for removed device\n");
-				/* For REQUEST_SENSE, it's the data.  But
-				 * for anything else, it should look like
-				 * we auto-sensed for it.
-				 */
-				if (us->srb->cmnd[0] == REQUEST_SENSE) {
-					memcpy(us->srb->request_buffer, 
-					       usb_stor_sense_notready, 
-					       sizeof(usb_stor_sense_notready));
-					us->srb->result = GOOD << 1;
-				} else if(us->srb->cmnd[0] == INQUIRY) {
-					unsigned char data_ptr[36] = {
-					    0x20, 0x80, 0x02, 0x02,
-					    0x1F, 0x00, 0x00, 0x00};
-					US_DEBUGP("Faking INQUIRY command for disconnected device\n");
-					fill_inquiry_response(us, data_ptr, 36);
-					us->srb->result = GOOD << 1;
-				} else {
-					memcpy(us->srb->sense_buffer, 
-					       usb_stor_sense_notready, 
-					       sizeof(usb_stor_sense_notready));
-					us->srb->result = CHECK_CONDITION << 1;
-				}
-			} else { /* atomic_read(&us->sm_state) == STATE_DETACHED */
-
-				/* Handle those devices which need us to fake 
-				 * their inquiry data */
-				if ((us->srb->cmnd[0] == INQUIRY) &&
-				    (us->flags & US_FL_FIX_INQUIRY)) {
-					unsigned char data_ptr[36] = {
-					    0x00, 0x80, 0x02, 0x02,
-					    0x1F, 0x00, 0x00, 0x00};
-
-					US_DEBUGP("Faking INQUIRY command\n");
-					fill_inquiry_response(us, data_ptr, 36);
-					us->srb->result = GOOD << 1;
-				} else {
-					/* we've got a command, let's do it! */
-					US_DEBUG(usb_stor_show_command(us->srb));
-					atomic_set(&us->sm_state, US_STATE_RUNNING);
-					us->proto_handler(us->srb, us);
-					atomic_set(&us->sm_state, US_STATE_IDLE);
-				}
+		/* our device has gone - pretend not ready */
+		if (atomic_read(&us->device_state) == US_STATE_DETACHED) {
+			US_DEBUGP("Request is for removed device\n");
+			/* For REQUEST_SENSE, it's the data.  But
+			 * for anything else, it should look like
+			 * we auto-sensed for it.
+			 */
+			if (us->srb->cmnd[0] == REQUEST_SENSE) {
+				memcpy(us->srb->request_buffer, 
+				       usb_stor_sense_notready, 
+				       sizeof(usb_stor_sense_notready));
+				us->srb->result = GOOD << 1;
+			} else if(us->srb->cmnd[0] == INQUIRY) {
+				unsigned char data_ptr[36] = {
+				    0x20, 0x80, 0x02, 0x02,
+				    0x1F, 0x00, 0x00, 0x00};
+				US_DEBUGP("Faking INQUIRY command for disconnected device\n");
+				fill_inquiry_response(us, data_ptr, 36);
+				us->srb->result = GOOD << 1;
+			} else {
+				memcpy(us->srb->sense_buffer, 
+				       usb_stor_sense_notready, 
+				       sizeof(usb_stor_sense_notready));
+				us->srb->result = CHECK_CONDITION << 1;
 			}
+		} else { /* atomic_read(&us->device_state) == STATE_DETACHED */
 
-			/* unlock the device pointers */
-			up(&(us->dev_semaphore));
+			/* Handle those devices which need us to fake 
+			 * their inquiry data */
+			if ((us->srb->cmnd[0] == INQUIRY) &&
+			    (us->flags & US_FL_FIX_INQUIRY)) {
+				unsigned char data_ptr[36] = {
+				    0x00, 0x80, 0x02, 0x02,
+				    0x1F, 0x00, 0x00, 0x00};
 
-			/* indicate that the command is done */
-			if (us->srb->result != DID_ABORT << 16) {
-				US_DEBUGP("scsi cmd done, result=0x%x\n", 
-					   us->srb->result);
-				scsi_lock(host);
-				us->srb->scsi_done(us->srb);
-				us->srb = NULL;
-				scsi_unlock(host);
+				US_DEBUGP("Faking INQUIRY command\n");
+				fill_inquiry_response(us, data_ptr, 36);
+				us->srb->result = GOOD << 1;
 			} else {
-				US_DEBUGP("scsi command aborted\n");
-				us->srb = NULL;
-				complete(&(us->notify));
+				/* we've got a command, let's do it! */
+				US_DEBUG(usb_stor_show_command(us->srb));
+				us->proto_handler(us->srb, us);
 			}
-			break;
-
-		case US_ACT_DEVICE_RESET:
-			break;
-
-		case US_ACT_BUS_RESET:
-			break;
-
-		case US_ACT_HOST_RESET:
-			break;
+		}
 
-		} /* end switch on action */
+		/* unlock the device pointers */
+		up(&(us->dev_semaphore));
 
-		/* exit if we get a signal to exit */
-		if (action == US_ACT_EXIT) {
-			US_DEBUGP("-- US_ACT_EXIT command received\n");
-			break;
+		/* indicate that the command is done */
+		if (us->srb->result != DID_ABORT << 16) {
+			US_DEBUGP("scsi cmd done, result=0x%x\n", 
+				   us->srb->result);
+			scsi_lock(host);
+			us->srb->scsi_done(us->srb);
+			us->srb = NULL;
+			scsi_unlock(host);
+		} else {
+			US_DEBUGP("scsi command aborted\n");
+			us->srb = NULL;
+			complete(&(us->notify));
 		}
 	} /* for (;;) */
 
@@ -725,7 +710,7 @@
 		/* establish the connection to the new device upon reconnect */
 		ss->ifnum = ifnum;
 		ss->pusb_dev = dev;
-		atomic_set(&ss->sm_state, US_STATE_IDLE);
+		atomic_set(&ss->device_state, US_STATE_ATTACHED);
 
 		/* copy over the endpoint data */
 		if (ep_in)
@@ -1016,6 +1001,7 @@
 
 		/* start up our control thread */
 		atomic_set(&ss->sm_state, US_STATE_IDLE);
+		atomic_set(&ss->device_state, US_STATE_ATTACHED);
 		ss->pid = kernel_thread(usb_stor_control_thread, ss,
 					CLONE_VM);
 		if (ss->pid < 0) {
diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h	Wed May 29 11:43:03 2002
+++ b/drivers/usb/storage/usb.h	Wed May 29 11:43:03 2002
@@ -4,7 +4,7 @@
  * $Id: usb.h,v 1.21 2002/04/21 02:57:59 mdharm Exp $
  *
  * Current development and maintenance by:
- *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Initial work by:
  *   (c) 1999 Michael Gee (michael@linuxspecific.com)
@@ -103,11 +103,15 @@
 #define US_FL_SCM_MULT_TARG   0x00000020 /* supports multiple targets */
 #define US_FL_FIX_INQUIRY     0x00000040 /* INQUIRY response needs fixing */
 
-#define US_STATE_DETACHED	1	/* State machine states */
-#define US_STATE_IDLE		2
-#define US_STATE_RUNNING	3
-#define US_STATE_RESETTING	4
-#define US_STATE_ABORTING	5
+/* device attached/detached states */
+#define US_STATE_DETACHED	1
+#define US_STATE_ATTACHED	2
+
+/* processing state machine states */
+#define US_STATE_IDLE		1
+#define US_STATE_RUNNING	2
+#define US_STATE_RESETTING	3
+#define US_STATE_ABORTING	4
 
 #define USB_STOR_STRING_LEN 32
 
@@ -120,8 +124,13 @@
 struct us_data {
 	struct us_data		*next;		 /* next device */
 
-	/* the device we're working with */
+	/* The device we're working with
+	 * It's important to note:
+	 *    (o) you must hold dev_semaphore to change pusb_dev
+	 *    (o) device_state should change whenever pusb_dev does
+	 */
 	struct semaphore	dev_semaphore;	 /* protect pusb_dev */
+	atomic_t		device_state;	 /* attached or detached */
 	struct usb_device	*pusb_dev;	 /* this usb_device */
 
 	unsigned int		flags;		 /* from filter initially */
diff -Nru a/drivers/video/Config.in b/drivers/video/Config.in
--- a/drivers/video/Config.in	Wed May 29 11:43:03 2002
+++ b/drivers/video/Config.in	Wed May 29 11:43:03 2002
@@ -10,9 +10,6 @@
 if [ "$CONFIG_FB" = "y" ]; then
    define_bool CONFIG_DUMMY_CONSOLE y
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      if [ "$CONFIG_PCI" = "y" ]; then
-         tristate '  nVidia Riva support (EXPERIMENTAL)' CONFIG_FB_RIVA
-      fi
       if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then
 	 tristate '  Cirrus Logic support (EXPERIMENTAL)' CONFIG_FB_CLGEN
 	 tristate '  Permedia2 support (EXPERIMENTAL)' CONFIG_FB_PM2
@@ -127,6 +124,7 @@
    fi
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       if [ "$CONFIG_PCI" != "n" ]; then
+	 tristate '  nVidia Riva support (EXPERIMENTAL)' CONFIG_FB_RIVA
 	 tristate '  Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX
 	 if [ "$CONFIG_FB_MATROX" != "n" ]; then
 	    bool '    Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
@@ -156,6 +154,8 @@
 	 tristate '  NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC
 	 tristate '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
 	 tristate '  3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1
+	 tristate '  Trident support (EXPERIMENTAL)' CONFIG_FB_TRIDENT
+	 tristate '  Permedia3 support (EXPERIMENTAL)' CONFIG_FB_PM3
       fi
    fi
    if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
@@ -220,6 +220,7 @@
       tristate '    16 bpp packed pixels support' CONFIG_FBCON_CFB16
       tristate '    24 bpp packed pixels support' CONFIG_FBCON_CFB24
       tristate '    32 bpp packed pixels support' CONFIG_FBCON_CFB32
+      tristate '    Hardware acceleration support' CONFIG_FBCON_ACCEL
       tristate '    Amiga bitplanes support' CONFIG_FBCON_AFB
       tristate '    Amiga interleaved bitplanes support' CONFIG_FBCON_ILBM
       tristate '    Atari interleaved bitplanes (2 planes) support' CONFIG_FBCON_IPLAN2P2
@@ -235,29 +236,25 @@
       if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \
 	   "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
 	   "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \
-	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
-	   "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y"  -o \
-	   "$CONFIG_FB_TX3912" = "y" ]; then
+	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
+	   "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then 
 	 define_tristate CONFIG_FBCON_MFB y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \
 	      "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
 	      "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \
-	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
-	      "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
-	      "$CONFIG_FB_TX3912" = "m" ]; then
+	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_TX3912" = "m" -o \
+	      "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then 
 	    define_tristate CONFIG_FBCON_MFB m
 	 fi
       fi
       if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
-	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
-	   "$CONFIG_FB_TX3912" = "y" ]; then
+	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_TX3912" = "y" ]; then 
 	 define_tristate CONFIG_FBCON_CFB2 y
 	 define_tristate CONFIG_FBCON_CFB4 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
-	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
-	      "$CONFIG_FB_TX3912" = "m" ]; then
+	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_TX3912" = "m" ]; then 
 	    define_tristate CONFIG_FBCON_CFB2 m
 	    define_tristate CONFIG_FBCON_CFB4 m
 	 fi
@@ -265,10 +262,10 @@
       if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \
 	   "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
 	   "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \
-	   "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	   "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_PM3" = "y" -o \
 	   "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
 	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
-	   "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
+	   "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
 	   "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
            "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
@@ -276,53 +273,50 @@
 	   "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
 	   "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
-	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
+	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_SIS" = "y" -o \
 	   "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
-	   "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
-	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
+	   "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" ]; then 
 	 define_tristate CONFIG_FBCON_CFB8 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
 	      "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
 	      "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \
-	      "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_PM3" = "m" -o \
 	      "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
 	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
-	      "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \
+	      "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_TRIDENT" = "m" -o \
 	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
 	      "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
               "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
 	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
 	      "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
-	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \
+	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_TX3912" = "m" -o \
 	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \
 	      "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
 	      "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
-	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
-	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
+	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then 
 	    define_tristate CONFIG_FBCON_CFB8 m
 	 fi
       fi
       if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
-	   "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
-	   "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
-	   "$CONFIG_FB_Q40" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
+	   "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \
+	   "$CONFIG_FB_TRIDENT" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
+	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
 	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
 	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
 	   "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
 	   "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
 	   "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
-	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
+	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PM3" = "y"  -o \
 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
-	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
-	   "$CONFIG_FB_NEOMAGIC" = "y" ]; then
+	   "$CONFIG_FB_PVR2" = "y" ]; then 
 	 define_tristate CONFIG_FBCON_CFB16 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
-	      "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
-	      "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
-	      "$CONFIG_FB_Q40" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \
+	      "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" -o \
+	      "$CONFIG_FB_TRIDENT" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
+	      "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_PM3" = "m" -o \
 	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
 	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
 	      "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
@@ -331,8 +325,7 @@
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
-	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
-	      "$CONFIG_FB_NEOMAGIC" = "m" ]; then
+	      "$CONFIG_FB_PVR2" = "m" ]; then 
 	    define_tristate CONFIG_FBCON_CFB16 m
 	 fi
       fi
@@ -354,29 +347,42 @@
 	 fi
       fi
       if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
-	   "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_TRIDENT" = "y" -o \
 	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
 	   "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
 	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
-	   "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
+	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
 	   "$CONFIG_FB_RADEON" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
-	   "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" -o \
-	   "$CONFIG_FB_VOODOO1" = "y" ]; then
+	   "$CONFIG_FB_PM3" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB32 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
-	      "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_TRIDENT" = "m" -o \
 	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
 	      "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
 	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
-	      "$CONFIG_FB_3DFX" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
+	      "$CONFIG_FB_PM3" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
-	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then
+	      "$CONFIG_FB_PVR2" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB32 m
 	 fi
       fi
+      if [ "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
+	   "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_HIT" = "y" -o \
+	   "$CONFIG_FB_HP300" = "y" -o "$CONFIG_FB_Q40" = "y" -o \
+	   "$CONFIG_FB_ANAKIN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
+	   "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_CLPS711X" = "y" -o \
+	   "$CONFIG_FB_3DFX" = "y" ]; then
+	 define_tristate CONFIG_FBCON_ACCEL y
+      else
+	 if [ "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_HIT" = "m" -o \
+	      "$CONFIG_FB_G364" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_CLPS711X" = "m" -o "$CONFIG_FB_3DFX" = "m" ]; then 
+	    define_tristate CONFIG_FBCON_ACCEL m
+         fi       
+      fi
       if [ "$CONFIG_FB_AMIGA" = "y" ]; then
 	 define_tristate CONFIG_FBCON_AFB y
 	 define_tristate CONFIG_FBCON_ILBM y
@@ -399,10 +405,10 @@
 #	    define_tristate CONFIG_FBCON_IPLAN2P16 m
 	 fi
       fi
-      if [ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+      if [ "$CONFIG_FB_MAC" = "y" ]; then
 	 define_tristate CONFIG_FBCON_MAC  y
       else
-	 if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+	 if [ "$CONFIG_FB_MAC" = "m" ]; then
 	    define_tristate CONFIG_FBCON_MAC  m
 	 fi
       fi
diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile
--- a/drivers/video/Makefile	Wed May 29 11:43:01 2002
+++ b/drivers/video/Makefile	Wed May 29 11:43:01 2002
@@ -2,8 +2,6 @@
 # 5 Aug 1999, James Simmons, <mailto:jsimmons@users.sf.net>
 # Rewritten to use lists instead of if-statements.
 
-O_TARGET := video.o
-
 mod-subdirs	:= matrox
 
 # All of the (potential) objects that export symbols.
@@ -44,8 +42,9 @@
 obj-$(CONFIG_FB_ACORN)            += acornfb.o
 obj-$(CONFIG_FB_AMIGA)            += amifb.o
 obj-$(CONFIG_FB_PM2)              += pm2fb.o
+obj-$(CONFIG_FB_PM3)		  += pm3fb.o
 obj-$(CONFIG_FB_APOLLO)           += dnfb.o
-obj-$(CONFIG_FB_Q40)              += q40fb.o
+obj-$(CONFIG_FB_Q40)              += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_ATARI)            += atafb.o
 obj-$(CONFIG_FB_ATY128)           += aty128fb.o
 obj-$(CONFIG_FB_RADEON)		  += radeonfb.o
@@ -56,24 +55,25 @@
 obj-$(CONFIG_FB_VALKYRIE)         += valkyriefb.o
 obj-$(CONFIG_FB_CT65550)          += chipsfb.o
 obj-$(CONFIG_FB_ANAKIN)           += anakinfb.o
-obj-$(CONFIG_FB_CLPS711X)         += clps711xfb.o
+obj-$(CONFIG_FB_CLPS711X)         += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_CYBER)            += cyberfb.o
 obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o
 obj-$(CONFIG_FB_SGIVW)            += sgivwfb.o
 obj-$(CONFIG_FB_3DFX)             += tdfxfb.o
 obj-$(CONFIG_FB_MAC)              += macfb.o macmodes.o
-obj-$(CONFIG_FB_HP300)            += hpfb.o
+obj-$(CONFIG_FB_HP300)            += hpfb.o cfbfillrect.o cfbimgblt.o
 obj-$(CONFIG_FB_OF)               += offb.o
 obj-$(CONFIG_FB_IMSTT)            += imsttfb.o
 obj-$(CONFIG_FB_RETINAZ3)         += retz3fb.o
 obj-$(CONFIG_FB_CLGEN)            += clgenfb.o
+obj-$(CONFIG_FB_TRIDENT)	  += tridentfb.o
 obj-$(CONFIG_FB_S3TRIO)           += S3triofb.o
 obj-$(CONFIG_FB_TGA)              += tgafb.o
-obj-$(CONFIG_FB_VESA)             += vesafb.o 
+obj-$(CONFIG_FB_VESA)             += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o 
 obj-$(CONFIG_FB_VGA16)            += vga16fb.o fbcon-vga-planes.o
 obj-$(CONFIG_FB_VIRGE)            += virgefb.o
-obj-$(CONFIG_FB_G364)             += g364fb.o
-obj-$(CONFIG_FB_FM2)              += fm2fb.o
+obj-$(CONFIG_FB_G364)             += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+obj-$(CONFIG_FB_FM2)              += fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_CREATOR)          += creatorfb.o sbusfb.o
 obj-$(CONFIG_FB_CGSIX)            += cgsixfb.o sbusfb.o
 obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o sbusfb.o
@@ -97,8 +97,8 @@
 obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o
 obj-$(CONFIG_FB_HGA)              += hgafb.o  
 obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
-obj-$(CONFIG_FB_VIRTUAL)          += vfb.o  
-obj-$(CONFIG_FB_HIT)              += hitfb.o
+obj-$(CONFIG_FB_VIRTUAL)          += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o 
+obj-$(CONFIG_FB_HIT)              += hitfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_E1355)            += epson1355fb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
@@ -122,6 +122,7 @@
 obj-$(CONFIG_FBCON_VGA)           += fbcon-vga.o
 obj-$(CONFIG_FBCON_HGA)           += fbcon-hga.o
 obj-$(CONFIG_FBCON_STI)           += fbcon-sti.o
+obj-$(CONFIG_FBCON_ACCEL)	  += fbcon-accel.o
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/drivers/video/anakinfb.c b/drivers/video/anakinfb.c
--- a/drivers/video/anakinfb.c	Wed May 29 11:43:03 2002
+++ b/drivers/video/anakinfb.c	Wed May 29 11:43:03 2002
@@ -23,23 +23,34 @@
 #include <video/fbcon.h>
 #include <video/fbcon-cfb16.h>
 
-static u16 colreg[16];
+static u32 colreg[16];
 static struct fb_info fb_info;
 static struct display display;
 
-static int
-anakinfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-			u_int *transp, struct fb_info *info)
-{
-	if (regno > 15)
-		return 1;
+static struct fb_var_screeninfo anakinfb_var = {
+	xres:		400,
+	yres:		234,
+	xres_virtual:	400,
+	yres_virtual:	234,
+	bits_per_pixel:	16,
+	red:		{ 11, 5, 0 },
+	green:		{  5, 6, 0 }, 
+	blue:		{  0, 5, 0 },
+        activate:       FB_ACTIVATE_NOW,
+        height:         -1,
+        width:          -1,
+        vmode:          FB_VMODE_NONINTERLACED,
+};
 
-	*red = colreg[regno] & 0xf800;
-	*green = colreg[regno] & 0x7e0 << 5;
-	*blue = colreg[regno] & 0x1f << 11;
-	*transp = 0;
-	return 0;
-}
+static struct fb_fix_screeninfo anakinfb_fix = {
+	id:		"AnakinFB",
+	smem_start:	VGA_START,
+	smem_len:	VGA_SIZE,
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_TRUECOLOR,
+	line_length:	400*2,
+	accel:		FB_ACCEL_NONE,
+};
 
 static int
 anakinfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
@@ -53,153 +64,48 @@
 	return 0;
 }
 
-static int
-anakinfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, "AnakinFB");
-	fix->smem_start = VGA_START;
-	fix->smem_len = VGA_SIZE;
-	fix->type = FB_TYPE_PACKED_PIXELS;
-	fix->type_aux = 0;
-	fix->visual = FB_VISUAL_TRUECOLOR;
-	fix->xpanstep = 0;
-	fix->ypanstep = 0;
-	fix->ywrapstep = 0;
-        fix->line_length = 400 * 2;
-	fix->accel = FB_ACCEL_NONE;
-	return 0;
-}
-        
-static int
-anakinfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
-{
-	memset(var, 0, sizeof(struct fb_var_screeninfo));
-	var->xres = 400;
-	var->yres = 234;
-	var->xres_virtual = 400;
-	var->yres_virtual = 234;
-	var->xoffset = 0;
-	var->yoffset = 0;
-	var->bits_per_pixel = 16;
-	var->grayscale = 0;
-	var->red.offset = 11;
-	var->red.length = 5;
-	var->green.offset = 5;
-	var->green.length = 6;
-	var->blue.offset = 0;
-	var->blue.length = 5;
-	var->transp.offset = 0;
-	var->transp.length = 0;
-	var->nonstd = 0;
-	var->activate = FB_ACTIVATE_NOW;
-	var->height = -1;
-	var->width = -1;
-	var->pixclock = 0;
-	var->left_margin = 0;
-	var->right_margin = 0;
-	var->upper_margin = 0;
-	var->lower_margin = 0;
-	var->hsync_len = 0;
-	var->vsync_len = 0;
-	var->sync = 0;
-	var->vmode = FB_VMODE_NONINTERLACED;
-	return 0;
-}
-
-static int
-anakinfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
-{
-	return -EINVAL;
-}
-
-static int
-anakinfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			struct fb_info *info)
-{
-	if (con == info->currcon)
-		return fb_get_cmap(cmap, kspc, anakinfb_getcolreg, info);
-	else if (fb_display[con].cmap.len)
-		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		fb_copy_cmap(fb_default_cmap(16), cmap, kspc ? 0 : 2);
-	return 0;
-}
-
-static int
-anakinfb_switch_con(int con, struct fb_info *info)
-{ 
-	info->currcon = con;
-	return 0;
-
-}
-
-static int
-anakinfb_updatevar(int con, struct fb_info *info)
-{
-	return 0;
-}
-
-static void
-anakinfb_blank(int blank, struct fb_info *info)
-{
-	/*
-	 * TODO: use I2C to blank/unblank the screen
-	 */
-}
-
 static struct fb_ops anakinfb_ops = {
 	owner:		THIS_MODULE,
-	fb_get_fix:	anakinfb_get_fix,
-	fb_get_var:	anakinfb_get_var,
-	fb_set_var:	anakinfb_set_var,
-	fb_get_cmap:	anakinfb_get_cmap,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
 	fb_set_cmap:	gen_set_cmap,
 	fb_setcolreg:	anakinfb_setcolreg,
-	fb_blank:	anakinfb_blank,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
 };
 
 int __init
 anakinfb_init(void)
 {
 	memset(&fb_info, 0, sizeof(struct fb_info));
-	strcpy(fb_info.modename, "AnakinFB");
-	fb_info.node = NODEV;
+	memset(&display, 0, sizeof(struct display));
+
+	strcpy(fb_info.modename, anakinfb_fix.id);
+	fb_info.node = fb_info.currcon = -1;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;
 	fb_info.fbops = &anakinfb_ops;
-	fb_info.currcon = -1;
+	fb_info.var = anakinfb_var;
+	fb_info.fix = anakinfb_fix;
 	fb_info.disp = &display;
 	strcpy(fb_info.fontname, "VGA8x16");
 	fb_info.changevar = NULL;
-	fb_info.switch_con = &anakinfb_switch_con;
-	fb_info.updatevar = &anakinfb_updatevar;
-
-	memset(&display, 0, sizeof(struct display));
-	anakinfb_get_var(&display.var, 0, &fb_info);
+	fb_info.switch_con = gen_switch_con;
+	fb_info.updatevar = gen_update_var;
 	if (!(request_mem_region(VGA_START, VGA_SIZE, "vga")))
 		return -ENOMEM;
-	if (!(fb_info.screen_base = ioremap(VGA_START, VGA_SIZE))) {
+	if (fb_info.screen_base = ioremap(VGA_START, VGA_SIZE)) {
 		release_mem_region(VGA_START, VGA_SIZE);
 		return -EIO;
 	}
-	display.visual = FB_VISUAL_TRUECOLOR;
-	display.type = FB_TYPE_PACKED_PIXELS;
-	display.type_aux = 0;
-	display.ypanstep = 0;
-	display.ywrapstep = 0;
-	display.line_length = 400 * 2;
-	display.can_soft_blank = 1;
-	display.inverse = 0;
-
-#ifdef FBCON_HAS_CFB16
-	display.dispsw = &fbcon_cfb16;
-	display.dispsw_data = colreg;
-#else
-	display.dispsw = &fbcon_dummy;
-#endif
+
+	fb_alloc_cmap(&fb_info.cmap, 16, 0);
+	gen_set_disp(-1, &fb_info);
 
 	if (register_framebuffer(&fb_info) < 0) {
-		iounmap(fb_info.screen_base);
+		iounmap(display.screen_base);
 		release_mem_region(VGA_START, VGA_SIZE);
 		return -EINVAL;
 	}
diff -Nru a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/video/cfbcopyarea.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,222 @@
+/*
+ *  Generic function for frame buffer with packed pixels of any depth.
+ *
+ *      Copyright (C)  June 1999 James Simmons
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ * NOTES:
+ * 
+ *  This is for cfb packed pixels. Iplan and such are incorporated in the 
+ *  drivers that need them.
+ * 
+ *  FIXME
+ *  The code for 24 bit is horrible. It copies byte by byte size instead of 
+ *  longs like the other sizes. Needs to be optimized. 
+ *
+ *  Also need to add code to deal with cards endians that are different than 
+ *  the native cpu endians. I also need to deal with MSB position in the word.
+ *  
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/slab.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <video/fbcon.h>
+
+void cfb_copyarea(struct fb_info *p, struct fb_copyarea *area)
+{
+	int x2, y2, lineincr, shift, shift_right, shift_left, old_dx, old_dy;
+	int n, j, linesize = p->fix.line_length, bpl = sizeof(unsigned long);
+	unsigned long start_index, end_index, start_mask, end_mask, last;
+	unsigned long *dst = NULL, *src = NULL;
+	char *src1, *dst1;
+	int tmp, height;
+
+	/* clip the destination */
+	old_dx = area->dx;
+	old_dy = area->dy;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly.
+	 */
+	x2 = area->dx + area->width;
+	y2 = area->dy + area->height;
+	area->dx = area->dx > 0 ? area->dx : 0;
+	area->dy = area->dy > 0 ? area->dy : 0;
+	x2 = x2 < p->var.xres_virtual ? x2 : p->var.xres_virtual;
+	y2 = y2 < p->var.yres_virtual ? y2 : p->var.yres_virtual;
+	area->width = x2 - area->dx;
+	area->height = y2 - area->dy;
+
+	/* update sx1,sy1 */
+	area->sx += (area->dx - old_dx);
+	area->sy += (area->dy - old_dy);
+
+	height = area->height;
+
+	/* the source must be completely inside the virtual screen */
+	if (area->sx < 0 || area->sy < 0 ||
+	    (area->sx + area->width) > p->var.xres_virtual ||
+	    (area->sy + area->height) > p->var.yres_virtual)
+		return;
+
+	if (area->dy < area->sy
+	    || (area->dy == area->sy && area->dx < area->sx)) {
+		/* start at the top */
+		src1 = p->screen_base + area->sy * linesize +
+		    ((area->sx * p->var.bits_per_pixel) >> 3);
+		dst1 = p->screen_base + area->dy * linesize +
+		    ((area->dx * p->var.bits_per_pixel) >> 3);
+		lineincr = linesize;
+	} else {
+		/* start at the bottom */
+		src1 = p->screen_base + (area->sy + area->height-1) * linesize
+			+ (((area->sx + area->width - 1) * p->var.bits_per_pixel) >> 3);
+		dst1 = p->screen_base + (area->dy + area->height-1) * linesize
+			+ (((area->dx + area->width - 1) * p->var.bits_per_pixel) >> 3);
+		lineincr = -linesize;
+	}
+
+	if ((BITS_PER_LONG % p->var.bits_per_pixel) == 0) {
+		int ppw = BITS_PER_LONG / p->var.bits_per_pixel;
+		int n = ((area->width * p->var.bits_per_pixel) >> 3);
+
+		start_index = ((unsigned long) src1 & (bpl - 1));
+		end_index = ((unsigned long) (src1 + n) & (bpl - 1));
+		shift = ((unsigned long) dst1 & (bpl - 1)) -
+		    	((unsigned long) src1 & (bpl - 1));
+		start_mask = end_mask = 0;
+
+		if (start_index) {
+			start_mask = -1 >> (start_index << 3);
+			n -= (bpl - start_index);
+		}
+
+		if (end_index) {
+			end_mask = -1 << ((bpl - end_index) << 3);
+			n -= end_index;
+		}
+		n = n / bpl;
+
+		if (n <= 0) {
+			if (start_mask) {
+				if (end_mask)
+					end_mask &= start_mask;
+				else
+					end_mask = start_mask;
+				start_mask = 0;
+			}
+			n = 0;
+		}
+
+		if (shift) {
+			if (shift > 0) {
+				/* dest is over to right more */
+				shift_right =
+				    shift * p->var.bits_per_pixel;
+				shift_left =
+				    (ppw - shift) * p->var.bits_per_pixel;
+			} else {
+				/* source is to the right more */
+				shift_right =
+				    (ppw + shift) * p->var.bits_per_pixel;
+				shift_left =
+				    -shift * p->var.bits_per_pixel;
+			}
+			/* general case, positive increment */
+			if (lineincr > 0) {
+				if (shift < 0)
+					n++;
+				do {
+					dst = (unsigned long *) dst1;
+					src = (unsigned long *) src1;
+
+					last = (fb_readl(src) & start_mask);
+
+					if (shift > 0)
+						fb_writel(fb_readl(dst) | (last >> shift_right), dst);
+					for (j = 0; j < n; j++) {
+						dst++;
+						tmp = fb_readl(src);
+						src++;
+						fb_writel((last << shift_left) | (tmp >> shift_right), dst);
+						last = tmp;
+						src++;
+					}
+					fb_writel(fb_readl(dst) | (last << shift_left), dst);
+					src1 += lineincr;
+					dst1 += lineincr;
+				} while (--height);
+			} else {
+				/* general case, negative increment */
+				if (shift > 0)
+					n++;
+				do {
+					dst = (unsigned long *) dst1;
+					src = (unsigned long *) src1;
+
+					last = (fb_readl(src) & end_mask);
+
+					if (shift < 0)
+						fb_writel(fb_readl(dst) | (last >> shift_right), dst);
+					for (j = 0; j < n; j++) {
+						dst--;
+						tmp = fb_readl(src);
+						src--;
+						fb_writel((tmp << shift_left) | (last >> shift_right), dst);
+						last = tmp;
+						src--;
+					}
+					fb_writel(fb_readl(dst) | (last >> shift_right), dst);
+					src1 += lineincr;
+					dst1 += lineincr;
+				} while (--height);
+			}
+		} else {
+			/* no shift needed */
+			if (lineincr > 0) {
+				/* positive increment */
+				do {
+					dst = (unsigned long *) (dst1 - start_index);
+					src = (unsigned long *) (src1 - start_index);
+
+					if (start_mask)
+						fb_writel(fb_readl(src) | start_mask, dst);
+
+					for (j = 0; j < n; j++) {
+						fb_writel(fb_readl(src), dst);
+						dst++;
+						src++;
+					}
+
+					if (end_mask)
+						fb_writel(fb_readl(src) | end_mask, dst);
+					src1 += lineincr;
+					dst1 += lineincr;
+				} while (--height);
+			} else {
+				/* negative increment */
+				do {
+					dst = (unsigned long *) dst1;
+					src = (unsigned long *) src1;
+
+					if (start_mask)
+						fb_writel(fb_readl(src) | start_mask, dst);
+					for (j = 0; j < n; j++) {
+						fb_writel(fb_readl(src), dst);
+						dst--;
+						src--;
+					}
+					src1 += lineincr;
+					dst1 += lineincr;
+				} while (--height);
+			}
+		}
+	}
+}
diff -Nru a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/video/cfbfillrect.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,209 @@
+/*
+ *  Generic fillrect for frame buffers with packed pixels of any depth. 
+ *
+ *      Copyright (C)  2000 James Simmons (jsimmons@linux-fbdev.org) 
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ * NOTES:
+ *
+ *  The code for depths like 24 that don't have integer number of pixels per 
+ *  long is broken and needs to be fixed. For now I turned these types of 
+ *  mode off.
+ *
+ *  Also need to add code to deal with cards endians that are different than
+ *  the native cpu endians. I also need to deal with MSB position in the word.
+ *
+ */
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+#include <video/fbcon.h>
+
+void cfb_fillrect(struct fb_info *p, struct fb_fillrect *rect)
+{
+	unsigned long start_index, end_index, start_mask = 0, end_mask = 0;
+	unsigned long height, ppw, fg, fgcolor;
+	int i, n, x2, y2, linesize = p->fix.line_length;
+	int bpl = sizeof(unsigned long);
+	unsigned long *dst;
+	char *dst1;
+
+	if (!rect->width || !rect->height)
+		return;
+
+	/* We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly. */
+	x2 = rect->dx + rect->width;
+	y2 = rect->dy + rect->height;
+	x2 = x2 < p->var.xres_virtual ? x2 : p->var.xres_virtual;
+	y2 = y2 < p->var.yres_virtual ? y2 : p->var.yres_virtual;
+	rect->width = x2 - rect->dx;
+	height = y2 - rect->dy;
+
+	/* Size of the scanline in bytes */
+	n = (rect->width * (p->var.bits_per_pixel >> 3));
+	ppw = BITS_PER_LONG / p->var.bits_per_pixel;
+
+	dst1 = p->screen_base + (rect->dy * linesize) +
+	    	(rect->dx * (p->var.bits_per_pixel >> 3));
+	start_index = ((unsigned long) dst1 & (bpl - 1));
+	end_index = ((unsigned long) (dst1 + n) & (bpl - 1));
+
+	if (p->fix.visual == FB_VISUAL_TRUECOLOR)
+		fg = fgcolor = ((u32 *) (p->pseudo_palette))[rect->color];
+	else
+		fg = fgcolor = rect->color;
+
+	for (i = 0; i < ppw - 1; i++) {
+		fg <<= p->var.bits_per_pixel;
+		fg |= fgcolor;
+	}
+
+	if (start_index) {
+		start_mask = fg << (start_index << 3);
+		n -= (bpl - start_index);
+	}
+
+	if (end_index) {
+		end_mask = fg >> ((bpl - end_index) << 3);
+		n -= end_index;
+	}
+
+	n = n / bpl;
+
+	if (n <= 0) {
+		if (start_mask) {
+			if (end_mask)
+				end_mask &= start_mask;
+			else
+				end_mask = start_mask;
+			start_mask = 0;
+		}
+		n = 0;
+	}
+
+	if ((BITS_PER_LONG % p->var.bits_per_pixel) == 0) {
+		switch (rect->rop) {
+		case ROP_COPY:
+			do {
+				/* Word align to increases performace :-) */
+				dst = (unsigned long *) (dst1 - start_index);
+
+				if (start_mask) {
+#if BITS_PER_LONG == 32
+					fb_writel(fb_readl(dst) |
+						  start_mask, dst);
+#else
+					fb_writeq(fb_readq(dst) |
+						  start_mask, dst);
+#endif
+					dst++;
+				}
+
+				for (i = 0; i < n; i++) {
+#if BITS_PER_LONG == 32
+					fb_writel(fg, dst);
+#else
+					fb_writeq(fg, dst);
+#endif
+					dst++;
+				}
+
+				if (end_mask)
+#if BITS_PER_LONG == 32
+					fb_writel(fb_readl(dst) | end_mask,
+						  dst);
+#else
+					fb_writeq(fb_readq(dst) | end_mask,
+						  dst);
+#endif
+				dst1 += linesize;
+			} while (--height);
+			break;
+		case ROP_XOR:
+			do {
+				dst = (unsigned long *) (dst1 - start_index);
+
+				if (start_mask) {
+#if BITS_PER_LONG == 32
+					fb_writel(fb_readl(dst) ^
+						  start_mask, dst);
+#else
+					fb_writeq(fb_readq(dst) ^
+						  start_mask, dst);
+#endif
+					dst++;
+				}
+
+				for (i = 0; i < n; i++) {
+#if BITS_PER_LONG == 32
+					fb_writel(fb_readl(dst) ^ fg, dst);
+#else
+					fb_writeq(fb_readq(dst) ^ fg, dst);
+#endif
+					dst++;
+				}
+
+				if (end_mask) {
+#if BITS_PER_LONG == 32
+					fb_writel(fb_readl(dst) ^ end_mask,
+						  dst);
+#else
+					fb_writeq(fb_readq(dst) ^ end_mask,
+						  dst);
+#endif
+				}
+				dst1 += linesize;
+			} while (--height);
+			break;
+		}
+	} else {
+		/* Odd modes like 24 or 80 bits per pixel */
+		start_mask = fg >> (start_index * p->var.bits_per_pixel);
+		end_mask = fg << (end_index * p->var.bits_per_pixel);
+		/* start_mask =& PFILL24(x1,fg);
+		   end_mask_or = end_mask & PFILL24(x1+width-1,fg); */
+
+		n = (rect->width - start_index - end_index) / ppw;
+
+		switch (rect->rop) {
+		case ROP_COPY:
+			do {
+				dst = (unsigned long *) dst1;
+				if (start_mask)
+					*dst |= start_mask;
+				if ((start_index + rect->width) > ppw)
+					dst++;
+
+				/* XXX: slow */
+				for (i = 0; i < n; i++) {
+					*dst++ = fg;
+				}
+				if (end_mask)
+					*dst |= end_mask;
+				dst1 += linesize;
+			} while (--height);
+			break;
+		case ROP_XOR:
+			do {
+				dst = (unsigned long *) dst1;
+				if (start_mask)
+					*dst ^= start_mask;
+				if ((start_mask + rect->width) > ppw)
+					dst++;
+
+				for (i = 0; i < n; i++) {
+					*dst++ ^= fg;	/* PFILL24(fg,x1+i); */
+				}
+				if (end_mask)
+					*dst ^= end_mask;
+				dst1 += linesize;
+			} while (--height);
+			break;
+		}
+	}
+	return;
+}
diff -Nru a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/video/cfbimgblt.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,133 @@
+/*
+ *  Generic BitBLT function for frame buffer with packed pixels of any depth.
+ *
+ *      Copyright (C)  June 1999 James Simmons
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ * NOTES:
+ *
+ *    This function copys a image from system memory to video memory. The
+ *  image can be a bitmap where each 0 represents the background color and
+ *  each 1 represents the foreground color. Great for font handling. It can
+ *  also be a color image. This is determined by image_depth. The color image
+ *  must be laid out exactly in the same format as the framebuffer. Yes I know
+ *  their are cards with hardware that coverts images of various depths to the
+ *  framebuffer depth. But not every card has this. All images must be rounded
+ *  up to the nearest byte. For example a bitmap 12 bits wide must be two 
+ *  bytes width. 
+ *
+ *  FIXME
+ *  The code for 24 bit is horrible. It copies byte by byte size instead of
+ *  longs like the other sizes. Needs to be optimized.
+ *
+ *  Also need to add code to deal with cards endians that are different than
+ *  the native cpu endians. I also need to deal with MSB position in the word.
+ *
+ */
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+
+#include <video/fbcon.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+void cfb_imageblit(struct fb_info *p, struct fb_image *image)
+{
+	int pad, ppw, shift, shift_right, shift_left, x2, y2, n, i, j, k, l = 7;
+	unsigned long tmp = ~0 << (BITS_PER_LONG - p->var.bits_per_pixel);
+	unsigned long fgx, bgx, fgcolor, bgcolor, eorx;	
+	unsigned long end_index, end_mask;
+	unsigned long *dst = NULL;
+	u8 *dst1, *src;
+
+	/* 
+	 * We could use hardware clipping but on many cards you get around hardware
+	 * clipping by writing to framebuffer directly like we are doing here. 
+	 */
+	x2 = image->dx + image->width;
+	y2 = image->dy + image->height;
+	image->dx = image->dx > 0 ? image->dx : 0;
+	image->dy = image->dy > 0 ? image->dy : 0;
+	x2 = x2 < p->var.xres_virtual ? x2 : p->var.xres_virtual;
+	y2 = y2 < p->var.yres_virtual ? y2 : p->var.yres_virtual;
+	image->width  = x2 - image->dx;
+	image->height = y2 - image->dy;
+  
+	dst1 = p->screen_base + image->dy * p->fix.line_length + 
+		((image->dx * p->var.bits_per_pixel) >> 3);
+  
+	ppw = BITS_PER_LONG/p->var.bits_per_pixel;
+
+	src = image->data;	
+
+	if (image->depth == 1) {
+
+		if (p->fix.visual == FB_VISUAL_TRUECOLOR) {
+			fgx = fgcolor = ((u32 *)(p->pseudo_palette))[image->fg_color];
+			bgx = bgcolor = ((u32 *)(p->pseudo_palette))[image->bg_color];
+		} else {
+			fgx = fgcolor = image->fg_color;
+			bgx = bgcolor = image->bg_color;
+		}	
+ 
+		for (i = 0; i < ppw-1; i++) {
+			fgx <<= p->var.bits_per_pixel;
+			bgx <<= p->var.bits_per_pixel;
+			fgx |= fgcolor;
+			bgx |= bgcolor;
+		}
+		eorx = fgx ^ bgx;
+		n = ((image->width + 7) >> 3);
+		pad = (n << 3) - image->width;
+		n = image->width % ppw;
+
+		for (i = 0; i < image->height; i++) {
+			dst = (unsigned long *) dst1;
+		
+			for (j = image->width/ppw; j > 0; j--) {
+				end_mask = 0;
+		
+				for (k = ppw; k > 0; k--) {	
+					if (test_bit(l, src))
+						end_mask |= (tmp >> (p->var.bits_per_pixel*(k-1)));
+					l--;
+					if (l < 0) { l = 7; src++; }
+				}
+				fb_writel((end_mask & eorx)^bgx, dst);
+				dst++;
+			}
+		
+			if (n) {	
+				for (j = n; j > 0; j--) {
+					end_mask = 0;
+	
+					if (test_bit(l, src))
+						end_mask |= (tmp >> (p->var.bits_per_pixel*(k-1)));
+					l--;
+					if (l < 0) { l = 7; src++; }
+				}
+				fb_writel((end_mask & eorx)^bgx, dst);
+				dst++;
+			}
+			l -= pad;		
+			dst1 += p->fix.line_length;	
+		}	
+	} else {
+		/* Draw the penguin */
+		n = ((image->width * p->var.bits_per_pixel) >> 3);
+		//shift = ((unsigned long) dst1 & (bpl -1));		
+		end_mask = 0;
+	
+	//	n = n/bpl;
+	}
+}
diff -Nru a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
--- a/drivers/video/chipsfb.c	Wed May 29 11:43:03 2002
+++ b/drivers/video/chipsfb.c	Wed May 29 11:43:03 2002
@@ -74,10 +74,10 @@
 
 #define write_ind(num, val, ap, dp)	do { \
 	outb((num), (ap)); outb((val), (dp)); \
-} while (0);
+} while (0)
 #define read_ind(num, var, ap, dp)	do { \
 	outb((num), (ap)); var = inb((dp)); \
-} while (0);
+} while (0)
 
 /* extension registers */
 #define write_xr(num, val)	write_ind(num, val, 0x3d6, 0x3d7)
diff -Nru a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
--- a/drivers/video/clps711xfb.c	Wed May 29 11:43:02 2002
+++ b/drivers/video/clps711xfb.c	Wed May 29 11:43:02 2002
@@ -27,7 +27,6 @@
 #include <linux/proc_fs.h>
 
 #include <video/fbcon.h>
-#include <video/fbcon-cfb4.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
@@ -87,42 +86,13 @@
 
 	return 0;
 }
-		    
+
 /*
- *    Set the User Defined Part of the Display
- */
+ * Validate the purposed mode.
+ */	
 static int
-clps7111fb_set_var(struct fb_var_screeninfo *var, int con,
-		   struct fb_info *info)
+clps7111fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
-	struct display *display;
-	unsigned int lcdcon, syscon;
-	int chgvar = 0;
-
-	if (var->activate & FB_ACTIVATE_TEST)
-		return 0;
-
-	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
-		return -EINVAL;
-
-	if (info->var.xres != var->xres)
-		chgvar = 1;
-	if (info->var.yres != var->yres)
-		chgvar = 1;
-	if (info->var.xres_virtual != var->xres_virtual)
-		chgvar = 1;
-	if (info->var.yres_virtual != var->yres_virtual)
-		chgvar = 1;
-	if (info->var.bits_per_pixel != var->bits_per_pixel)
-		chgvar = 1;
-
-	if (con < 0) {
-		display = info->disp;
-		chgvar = 0;
-	} else {
-		display = fb_display + con;
-	}
-
 	var->transp.msb_right	= 0;
 	var->transp.offset	= 0;
 	var->transp.length	= 0;
@@ -132,70 +102,37 @@
 	var->green		= var->red;
 	var->blue		= var->red;
 
+	if (var->bits_per_pixel > 4) 
+		return -EINVAL;
+}
+
+/*
+ * Set the hardware state.
+ */ 
+static int 
+clps7111fb_set_par(struct fb_info *info)
+{
+	unsigned int lcdcon, syscon;
+
 	switch (var->bits_per_pixel) {
-#ifdef FBCON_HAS_MFB
 	case 1:
 		info->fix.visual	= FB_VISUAL_MONO01;
-		display->dispsw		= &fbcon_mfb;
-		display->dispsw_data	= NULL;
 		break;
-#endif
-#ifdef FBCON_HAS_CFB2
 	case 2:
 		info->fix.visual	= FB_VISUAL_PSEUDOCOLOR;
-		display->dispsw		= &fbcon_cfb2;
-		display->dispsw_data	= NULL;
 		break;
-#endif
-#ifdef FBCON_HAS_CFB4
 	case 4:
 		info->fix.visual	= FB_VISUAL_PSEUDOCOLOR;
-		display->dispsw		= &fbcon_cfb4;
-		display->dispsw_data	= NULL;
 		break;
-#endif
-	default:
-		return -EINVAL;
 	}
 
-	display->next_line	= var->xres_virtual * var->bits_per_pixel / 8;
-
-	info->fix.line_length = display->next_line;
-
-	display->line_length	= info->fix.line_length;
-	display->visual		= info->fix.visual;
-	display->type		= info->fix.type;
-	display->type_aux	= info->fix.type_aux;
-	display->ypanstep	= info->fix.ypanstep;
-	display->ywrapstep	= info->fix.ywrapstep;
-	display->can_soft_blank = 1;
-	display->inverse	= 0;
-
-	info->var		= *var;
-	info->var.activate	&= ~FB_ACTIVATE_ALL;
-
-	/*
-	 * Update the old var.  The fbcon drivers still use this.
-	 * Once they are using cfb->var, this can be dropped.
-	 *                                      --rmk
-	 */
-	display->var		= info->var;
-
-	/*
-	 * If we are setting all the virtual consoles, also set the
-	 * defaults used to create new consoles.
-	 */
-	if (var->activate & FB_ACTIVATE_ALL)
-		info->disp->var = info->var;
-
-	if (chgvar && info && info->changevar)
-		info->changevar(con);
+	info->fix.line_length = info->var.xres_virtual * info->var.bits_per_pixel / 8;
 
 	/*
 	 * LCDCON must only be changed while the LCD is disabled
 	 */
-	lcdcon = (var->xres_virtual * var->yres_virtual * var->bits_per_pixel) / 128 - 1;
-	lcdcon |= ((var->xres_virtual / 16) - 1) << 13;
+	lcdcon = (info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel) / 128 - 1;
+	lcdcon |= ((info->var.xres_virtual / 16) - 1) << 13;
 	lcdcon |= 2 << 19;
 	lcdcon |= 13 << 25;
 	lcdcon |= LCDCON_GSEN;
@@ -205,9 +142,6 @@
 	clps_writel(syscon & ~SYSCON1_LCDEN, SYSCON1);
 	clps_writel(lcdcon, LCDCON);
 	clps_writel(syscon | SYSCON1_LCDEN, SYSCON1);
-
-	fb_set_cmap(&info->cmap, 1, info);
-
 	return 0;
 }
 
@@ -260,7 +194,9 @@
 
 static struct fb_ops clps7111fb_ops = {
 	owner:		THIS_MODULE,
-	fb_set_var:	clps7111fb_set_var,
+	fb_check_var:	clps7111fb_check_var,
+	fb_set_par:	clps7111fb_set_par,
+	fb_set_var:	gen_set_var,
 	fb_set_cmap:	gen_set_cmap,
 	fb_get_fix:	gen_get_fix,
 	fb_get_var:	gen_get_var,
@@ -269,50 +205,6 @@
 	fb_blank:	clps7111fb_blank,
 };
 
-static int clps7111fb_switch(int con, struct fb_info *info)
-{
-	struct display *disp;
-	struct fb_cmap *cmap;
-
-	if (info->currcon >= 0) {
-		disp = fb_display + info->currcon;
-
-		/*
-		 * Save the old colormap and video mode.
-		 */
-		disp->var = info->var;
-		if (disp->cmap.len)
-			fb_copy_cmap(&info->cmap, &disp->cmap, 0);
-	}
-
-	info->currcon = con;
-	disp = fb_display + con;
-
-	/*
-	 * Install the new colormap and change the video mode.  By default,
-	 * fbcon sets all the colormaps and video modes to the default
-	 * values at bootup.
-	 */
-	if (disp->cmap.len)
-		cmap = &disp->cmap;
-	else
-		cmap = fb_default_cmap(CMAP_SIZE);
-
-	fb_copy_cmap(cmap, &info->cmap, 0);
-
-	info->var = disp->var;
-	info->var.activate = FB_ACTIVATE_NOW;
-
-	clps7111fb_set_var(&info->var, con, info);
-
-	return 0;
-}
-
-static int clps7111fb_updatevar(int con, struct fb_info *info)
-{
-	return -EINVAL;
-}
-
 static int 
 clps7111fb_proc_backlight_read(char *page, char **start, off_t off,
 		int count, int *eof, void *data)
@@ -395,8 +287,8 @@
 
 	cfb->fbops		= &clps7111fb_ops;
 	cfb->changevar	= NULL;
-	cfb->switch_con	= clps7111fb_switch;
-	cfb->updatevar	= clps7111fb_updatevar;
+	cfb->switch_con	= gen_switch;
+	cfb->updatevar	= gen_update_var;
 	cfb->flags		= FBINFO_FLAG_DEFAULT;
 	cfb->disp		= (struct display *)(cfb + 1);
 
@@ -439,7 +331,7 @@
 		clps_writeb(clps_readb(PDDR) | EDB_PD3_LCDBL, PDDR);
 	}
 
-	clps7111fb_set_var(&cfb->var, -1, cfb);
+	gen_set_var(&cfb->var, -1, cfb);
 	err = register_framebuffer(cfb);
 
 out:	return err;
diff -Nru a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
--- a/drivers/video/cyber2000fb.c	Wed May 29 11:43:02 2002
+++ b/drivers/video/cyber2000fb.c	Wed May 29 11:43:02 2002
@@ -1729,9 +1729,8 @@
 }
 
 static struct pci_device_id cyberpro_pci_table[] __devinitdata = {
-// Not yet
-//	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
-//		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 },
+	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 },
 	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 },
 	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
diff -Nru a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
--- a/drivers/video/fbcmap.c	Wed May 29 11:43:02 2002
+++ b/drivers/video/fbcmap.c	Wed May 29 11:43:02 2002
@@ -152,7 +152,7 @@
     size = to->len-tooff;
     if (size > from->len-fromoff)
 	size = from->len-fromoff;
-    if (size < 0)
+    if (size <= 0)
 	return;
     size *= sizeof(u16);
     
diff -Nru a/drivers/video/fbcon-accel.c b/drivers/video/fbcon-accel.c
--- a/drivers/video/fbcon-accel.c	Wed May 29 11:43:02 2002
+++ b/drivers/video/fbcon-accel.c	Wed May 29 11:43:02 2002
@@ -158,7 +158,7 @@
 	putcs:		fbcon_accel_putcs,
 	revc:		fbcon_accel_revc,
 	clear_margins:	fbcon_accel_clear_margins,
-	fontwidthmask:	FONTWIDTHRANGE(1, 32)	
+	fontwidthmask:	FONTWIDTHRANGE(1, 16)	
 };
 
 #ifdef MODULE
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	Wed May 29 11:43:01 2002
+++ b/drivers/video/fbmem.c	Wed May 29 11:43:01 2002
@@ -61,6 +61,8 @@
 extern int cyberfb_setup(char*);
 extern int pm2fb_init(void);
 extern int pm2fb_setup(char*);
+extern int pm3fb_init(void);
+extern int pm3fb_setup(char*);
 extern int clps711xfb_init(void);
 extern int cyber2000fb_init(void);
 extern int cyber2000fb_setup(char*);
@@ -120,10 +122,16 @@
 extern int rivafb_setup(char*);
 extern int tdfxfb_init(void);
 extern int tdfxfb_setup(char*);
+extern int tridentfb_init(void);
+extern int tridentfb_setup(char*);
 extern int sisfb_init(void);
 extern int sisfb_setup(char*);
 extern int stifb_init(void);
 extern int stifb_setup(char*);
+extern int pmagbafb_init(void);
+extern int pmagbbfb_init(void);
+extern void maxinefb_init(void);
+extern int tx3912fb_init(void);
 extern int radeonfb_init(void);
 extern int radeonfb_setup(char*);
 extern int e1355fb_init(void);
@@ -172,6 +180,9 @@
 #ifdef CONFIG_FB_PM2
 	{ "pm2fb", pm2fb_init, pm2fb_setup },
 #endif
+#ifdef CONFIG_FB_PM3
+	{ "pm3fb", pm3fb_init, pm3fb_setup },
+#endif           
 #ifdef CONFIG_FB_CLGEN
 	{ "clgen", clgenfb_init, clgenfb_setup },
 #endif
@@ -220,6 +231,9 @@
 #ifdef CONFIG_FB_SIS
 	{ "sisfb", sisfb_init, sisfb_setup },
 #endif
+#ifdef CONFIG_FB_TRIDENT
+	{ "trident", tridentfb_init, tridentfb_setup },
+#endif
 
 	/*
 	 * Generic drivers that are used as fallbacks
@@ -285,12 +299,24 @@
 #ifdef CONFIG_FB_HIT
 	{ "hitfb", hitfb_init, NULL },
 #endif
+#ifdef CONFIG_FB_TX3912
+	{ "tx3912", tx3912fb_init, NULL },
+#endif
 #ifdef CONFIG_FB_E1355
 	{ "e1355fb", e1355fb_init, e1355fb_setup },
 #endif
 #ifdef CONFIG_FB_PVR2
 	{ "pvr2", pvr2fb_init, pvr2fb_setup },
 #endif
+#ifdef CONFIG_FB_PMAG_BA
+	{ "pmagbafb", pmagbafb_init, NULL },
+#endif          
+#ifdef CONFIG_FB_PMAGB_B
+	{ "pmagbbfb", pmagbbfb_init, NULL },
+#endif
+#ifdef CONFIG_FB_MAXINE
+	{ "maxinefb", maxinefb_init, NULL },
+#endif            
 #ifdef CONFIG_FB_VOODOO1
 	{ "sst", sstfb_init, sstfb_setup },
 #endif
diff -Nru a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c
--- a/drivers/video/fm2fb.c	Wed May 29 11:43:02 2002
+++ b/drivers/video/fm2fb.c	Wed May 29 11:43:02 2002
@@ -7,6 +7,7 @@
  *
  *  Written for 2.0.x by Steffen A. Mork
  *  Ported to 2.1.x by Geert Uytterhoeven
+ *  Ported to new api by James Simmons
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License. See the file COPYING in the main directory of this archive for
@@ -18,12 +19,9 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/zorro.h>
-
 #include <asm/io.h>
 
 #include <video/fbcon.h>
-#include <video/fbcon-cfb32.h>
-
 
 /*
  *	Some technical notes:
@@ -117,7 +115,6 @@
  *
  */
 
-
 /*
  *	definitions
  */
@@ -130,29 +127,22 @@
 #define FRAMEMASTER_COMPL	4
 #define FRAMEMASTER_ROM		8
 
-
-struct FrameMaster_fb_par
-{
-	int xres;
-	int yres;
-	int bpp;
-	int pixclock;
-};
-
-static unsigned long fm2fb_mem_phys;
-static void *fm2fb_mem;
-static unsigned long fm2fb_reg_phys;
 static volatile unsigned char *fm2fb_reg;
 
-static struct display disp;
+#define arraysize(x)	(sizeof(x)/sizeof(*(x)))
+
 static struct fb_info fb_info;
-static struct { u_char red, green, blue, pad; } palette[16];
-#ifdef FBCON_HAS_CFB32
-static u32 fbcon_cfb32_cmap[16];
-#endif
+static u32 pseudo_palette[17];
+static struct display display;
 
-static struct fb_fix_screeninfo fb_fix;
-static struct fb_var_screeninfo fb_var;
+static struct fb_fix_screeninfo fb_fix __initdata = {
+	smem_len:	FRAMEMASTER_REG,
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_TRUECOLOR,
+	line_length:	(768 << 2),
+	mmio_len:	(8),
+	accel:		FB_ACCEL_NONE,
+};
 
 static int fm2fb_mode __initdata = -1;
 
@@ -174,125 +164,58 @@
 	33333, 10, 102, 10, 5, 80, 34, FB_SYNC_COMP_HIGH_ACT, 0
     }
 };
-
-
+    
     /*
      *  Interface used by the world
      */
+int fm2fb_init(void);
 
-static int fm2fb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info);
-static int fm2fb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int fm2fb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int fm2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
 static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			   u_int transp, struct fb_info *info);
+                           u_int transp, struct fb_info *info);
 static int fm2fb_blank(int blank, struct fb_info *info);
 
-    /*
-     *  Interface to the low level console driver
-     */
-
-int fm2fb_init(void);
-static int fm2fbcon_switch(int con, struct fb_info *info);
-static int fm2fbcon_updatevar(int con, struct fb_info *info);
-
-    /*
-     *  Internal routines
-     */
-
-static int fm2fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-			   u_int *transp, struct fb_info *info);
-
 static struct fb_ops fm2fb_ops = {
 	owner:		THIS_MODULE,
-	fb_get_fix:	fm2fb_get_fix,
-	fb_get_var:	fm2fb_get_var,
-	fb_set_var:	fm2fb_set_var,
-	fb_get_cmap:	fm2fb_get_cmap,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
 	fb_set_cmap:	gen_set_cmap,
 	fb_setcolreg:	fm2fb_setcolreg,
-	fb_blank:	fm2fb_blank,
+	fb_blank:	fm2fb_blank,	
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
 };
 
     /*
-     *  Get the Fixed Part of the Display
+     *  Blank the display.
      */
-
-static int fm2fb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
+static int fm2fb_blank(int blank, struct fb_info *info)
 {
-    memcpy(fix, &fb_fix, sizeof(fb_fix));
-    return 0;
-}
-
-
-    /*
-     *  Get the User Defined Part of the Display
-     */
+	unsigned char t = FRAMEMASTER_ROM;
 
-static int fm2fb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
-{
-    memcpy(var, &fb_var, sizeof(fb_var));
-    return 0;
+	if (!blank)
+		t |= FRAMEMASTER_ENABLE | FRAMEMASTER_NOLACE;
+	fm2fb_reg[0] = t;
 }
-
-
+    
     /*
-     *  Set the User Defined Part of the Display
+     *  Set a single color register. The values supplied are already
+     *  rounded down to the hardware's capabilities (according to the
+     *  entries in the var structure). Return != 0 for invalid regno.
      */
-
-static int fm2fb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
+static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp, struct fb_info *info)
 {
-    struct display *display;
-    int oldbpp = -1, err;
-
-    if (con >= 0)
-	display = &fb_display[con];
-    else
-	display = &disp;	/* used during initialization */
-
-    if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
-	var->xres_virtual > fb_var.xres_virtual ||
-	var->yres_virtual > fb_var.yres_virtual ||
-	var->bits_per_pixel > fb_var.bits_per_pixel ||
-	var->nonstd ||
-	(var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
-	return -EINVAL;
-    memcpy(var, &fb_var, sizeof(fb_var));
-
-    if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-	oldbpp = display->var.bits_per_pixel;
-	display->var = *var;
-    }
-    if (oldbpp != var->bits_per_pixel) {
-	if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-	    return err;
-	do_install_cmap(con, info);
-    }
-    return 0;
-}
+	if (regno > 15)
+		return 1;
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
 
-
-    /*
-     *  Get the Colormap
-     */
-
-static int fm2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
-{
-    if (con == info->currcon) /* current console? */
-	return fb_get_cmap(cmap, kspc, fm2fb_getcolreg, info);
-    else if (fb_display[con].cmap.len) /* non default colormap? */
-	fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-    else
-	fb_copy_cmap(fb_default_cmap(256), cmap, kspc ? 0 : 2);
-    return 0;
+	((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue;
+	return 0;
 }
 
     /*
@@ -301,194 +224,89 @@
 
 int __init fm2fb_init(void)
 {
-    int is_fm;
-    struct zorro_dev *z = NULL;
-    unsigned long *ptr;
-    int x, y;
-
-    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-	if (z->id == ZORRO_PROD_BSC_FRAMEMASTER_II)
-	    is_fm = 1;
-	else if (z->id == ZORRO_PROD_HELFRICH_RAINBOW_II)
-	    is_fm = 0;
-	else
-	    continue;
-	if (!request_mem_region(z->resource.start, FRAMEMASTER_SIZE, "fm2fb"))
-	    continue;
-
-	/* assigning memory to kernel space */
-	fm2fb_mem_phys = z->resource.start;
-	fm2fb_mem  = ioremap(fm2fb_mem_phys, FRAMEMASTER_SIZE);
-	fm2fb_reg_phys = fm2fb_mem_phys+FRAMEMASTER_REG;
-	fm2fb_reg  = (unsigned char *)(fm2fb_mem+FRAMEMASTER_REG);
-
-	/* make EBU color bars on display */
-	ptr = (unsigned long *)fm2fb_mem;
-	for (y = 0; y < 576; y++) {
-	    for (x = 0; x < 96; x++) *ptr++ = 0xffffff;	/* white */
-	    for (x = 0; x < 96; x++) *ptr++ = 0xffff00;	/* yellow */
-	    for (x = 0; x < 96; x++) *ptr++ = 0x00ffff;	/* cyan */
-	    for (x = 0; x < 96; x++) *ptr++ = 0x00ff00;	/* green */
-	    for (x = 0; x < 96; x++) *ptr++ = 0xff00ff;	/* magenta */
-	    for (x = 0; x < 96; x++) *ptr++ = 0xff0000;	/* red */
-	    for (x = 0; x < 96; x++) *ptr++ = 0x0000ff;	/* blue */
-	    for (x = 0; x < 96; x++) *ptr++ = 0x000000;	/* black */
-	}
-	fm2fb_blank(0, NULL);
-
-	if (fm2fb_mode == -1)
-	    fm2fb_mode = FM2FB_MODE_PAL;
-
-	fb_var = fb_var_modes[fm2fb_mode];
+	struct zorro_dev *z = NULL;
+	unsigned long *ptr;
+	int is_fm;
+	int x, y;
+
+	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+		if (z->id == ZORRO_PROD_BSC_FRAMEMASTER_II)
+			is_fm = 1;
+		else if (z->id == ZORRO_PROD_HELFRICH_RAINBOW_II)
+			is_fm = 0;
+		else
+			continue;
+		
+		if (!request_mem_region(z->resource.start, FRAMEMASTER_SIZE, "fm2fb"))
+			continue;
+
+		/* assigning memory to kernel space */
+		fb_fix.smem_start = z->resource.start;
+		fb_info.screen_base = ioremap(fb_fix.smem_start, FRAMEMASTER_SIZE);
+		fb_fix.mmio_start = fb_fix.smem_start + FRAMEMASTER_REG;
+		fm2fb_reg  = (unsigned char *)(fb_info.screen_base+FRAMEMASTER_REG);
+	
+		strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II");
+
+		/* make EBU color bars on display */
+		ptr = (unsigned long *)fb_fix.smem_start;
+		for (y = 0; y < 576; y++) {
+			for (x = 0; x < 96; x++) *ptr++ = 0xffffff;/* white */
+			for (x = 0; x < 96; x++) *ptr++ = 0xffff00;/* yellow */
+			for (x = 0; x < 96; x++) *ptr++ = 0x00ffff;/* cyan */
+			for (x = 0; x < 96; x++) *ptr++ = 0x00ff00;/* green */
+			for (x = 0; x < 96; x++) *ptr++ = 0xff00ff;/* magenta */
+			for (x = 0; x < 96; x++) *ptr++ = 0xff0000;/* red */
+			for (x = 0; x < 96; x++) *ptr++ = 0x0000ff;/* blue */
+			for (x = 0; x < 96; x++) *ptr++ = 0x000000;/* black */
+		}
+		fm2fb_blank(0, NULL);
+
+		if (fm2fb_mode == -1)
+			fm2fb_mode = FM2FB_MODE_PAL;
+
+		strcpy(fb_info.modename, fb_fix.id);
+		fb_info.node = NODEV;
+		fb_info.fbops = &fm2fb_ops;
+		fb_info.var = fb_var_modes[fm2fb_mode];
+		fb_info.screen_base = (char *)fb_fix.smem_start;
+		fb_info.pseudo_palette = pseudo_palette;
+		fb_info.fix = fb_fix;
+		fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+		/* The below feilds will go away !!!! */
+		fb_info.currcon		= -1;
+		strcpy(fb_info.modename, fb_info.fix.id);
+		fb_info.disp		= &display;
+		fb_info.switch_con	= gen_switch;
+		fb_info.updatevar	= gen_update_var;
+		fb_alloc_cmap(&fb_info.cmap, 16, 0);
 
-	strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II");
-	fb_fix.smem_start = fm2fb_mem_phys;
-	fb_fix.smem_len = FRAMEMASTER_REG;
-	fb_fix.type = FB_TYPE_PACKED_PIXELS;
-	fb_fix.type_aux = 0;
-	fb_fix.visual = FB_VISUAL_TRUECOLOR;
-	fb_fix.line_length = 768<<2;
-	fb_fix.mmio_start = fm2fb_reg_phys;
-	fb_fix.mmio_len = 8;
-	fb_fix.accel = FB_ACCEL_NONE;
-
-	disp.var = fb_var;
-	disp.cmap.start = 0;
-	disp.cmap.len = 0;
-	disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
-	disp.visual = fb_fix.visual;
-	disp.type = fb_fix.type;
-	disp.type_aux = fb_fix.type_aux;
-	disp.ypanstep = 0;
-	disp.ywrapstep = 0;
-	disp.line_length = fb_fix.line_length;
-	disp.can_soft_blank = 1;
-	disp.inverse = 0;
-    #ifdef FBCON_HAS_CFB32
-	disp.dispsw = &fbcon_cfb32;
-	disp.dispsw_data = &fbcon_cfb32_cmap;
-    #else
-	disp.dispsw = &fbcon_dummy;
-    #endif
-	disp.scrollmode = SCROLL_YREDRAW;
-
-	strcpy(fb_info.modename, fb_fix.id);
-	fb_info.node = NODEV;
-	fb_info.fbops = &fm2fb_ops;
-	fb_info.screen_base = (char *)fm2fb_mem;
-	fb_info.currcon = -1;
-	fb_info.disp = &disp;
-	fb_info.fontname[0] = '\0';
-	fb_info.changevar = NULL;
-	fb_info.switch_con = &fm2fbcon_switch;
-	fb_info.updatevar = &fm2fbcon_updatevar;
-	fb_info.flags = FBINFO_FLAG_DEFAULT;
+		gen_set_disp(-1, &fb_info);
 
-	fm2fb_set_var(&fb_var, -1, &fb_info);
+		if (register_framebuffer(&fb_info) < 0)
+			return -EINVAL;
 
-	if (register_framebuffer(&fb_info) < 0)
-	    return -EINVAL;
-
-	printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node),
-	       fb_fix.id);
-	return 0;
-    }
-    return -ENXIO;
+		printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node), fb_fix.id);
+		return 0;
+	}
+	return -ENXIO;
 }
 
 int __init fm2fb_setup(char *options)
 {
-    char *this_opt;
-
-    if (!options || !*options)
-	return 0;
-
-    while ((this_opt = strsep(&options, ",")) != NULL) {
-	if (!strncmp(this_opt, "pal", 3))
-	    fm2fb_mode = FM2FB_MODE_PAL;
-	else if (!strncmp(this_opt, "ntsc", 4))
-	    fm2fb_mode = FM2FB_MODE_NTSC;
-    }
-    return 0;
-}
-
-
-static int fm2fbcon_switch(int con, struct fb_info *info)
-{
-    /* Do we have to save the colormap? */
-    if (fb_display[info->currcon].cmap.len)
-	fb_get_cmap(&fb_display[info->currcon].cmap, 1, fm2fb_getcolreg, info);
-
-    info->currcon = con;
-    /* Install new colormap */
-    do_install_cmap(con, info);
-    return 0;
-}
-
-    /*
-     *  Update the `var' structure (called by fbcon.c)
-     */
-
-static int fm2fbcon_updatevar(int con, struct fb_info *info)
-{
-    /* Nothing */
-    return 0;
-}
-
-    /*
-     *  Blank the display.
-     */
-
-static int fm2fb_blank(int blank, struct fb_info *info)
-{
-    unsigned char t = FRAMEMASTER_ROM;
-
-    if (!blank)
-	t |= FRAMEMASTER_ENABLE | FRAMEMASTER_NOLACE;
-    fm2fb_reg[0] = t;
-    return 0;	
-}
-
-    /*
-     *  Read a single color register and split it into
-     *  colors/transparent. Return != 0 for invalid regno.
-     */
-
-static int fm2fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp, struct fb_info *info)
-{
-    if (regno > 15)
-	return 1;
-    *red = (palette[regno].red<<8) | palette[regno].red;
-    *green = (palette[regno].green<<8) | palette[regno].green;
-    *blue = (palette[regno].blue<<8) | palette[regno].blue;
-    *transp = 0;
-    return 0;
-}
-
+	char *this_opt;
 
-    /*
-     *  Set a single color register. The values supplied are already
-     *  rounded down to the hardware's capabilities (according to the
-     *  entries in the var structure). Return != 0 for invalid regno.
-     */
+	if (!options || !*options)
+		return 0;
 
-static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp, struct fb_info *info)
-{
-    if (regno > 15)
-	return 1;
-    red >>= 8;
-    green >>= 8;
-    blue >>= 8;
-    palette[regno].red = red;
-    palette[regno].green = green;
-    palette[regno].blue = blue;
-
-#ifdef FBCON_HAS_CFB32
-    fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
-#endif
-    return 0;
+	while ((this_opt = strsep(&options, ",")) != NULL) {	
+		if (!strncmp(this_opt, "pal", 3))
+			fm2fb_mode = FM2FB_MODE_PAL;
+		else if (!strncmp(this_opt, "ntsc", 4))
+			fm2fb_mode = FM2FB_MODE_NTSC;
+	}
+	return 0;
 }
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/g364fb.c b/drivers/video/g364fb.c
--- a/drivers/video/g364fb.c	Wed May 29 11:43:01 2002
+++ b/drivers/video/g364fb.c	Wed May 29 11:43:01 2002
@@ -28,22 +28,19 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/selection.h>
-#include <linux/console.h>
 #include <asm/io.h>
 #include <asm/jazz.h>
 
 #include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
 
 /* 
  * Various defines for the G364
  */
 #define G364_MEM_BASE   0xe4400000
 #define G364_PORT_BASE  0xe4000000
-#define ID_REG 		0xe4000000  	/* Read only */
+#define ID_REG 		0xe4000000	/* Read only */
 #define BOOT_REG 	0xe4080000
-#define TIMING_REG 	0xe4080108 	/* to 0x080170 - DON'T TOUCH! */
+#define TIMING_REG 	0xe4080108	/* to 0x080170 - DON'T TOUCH! */
 #define DISPLAY_REG 	0xe4080118
 #define VDISPLAY_REG 	0xe4080150
 #define MASK_REG 	0xe4080200
@@ -67,155 +64,90 @@
 #define OP_MODE		0x000008
 #define INTL_STAND	0x000004
 #define SCRN_FORM	0x000002
-#define ENABLE_VTG	0x000001	
+#define ENABLE_VTG	0x000001
 #define TOP_REG 	0xe4080400
-#define CURS_PAL_REG 	0xe4080508 	/* to 0x080518 */
-#define CHKSUM_REG 	0xe4080600 	/* to 0x080610 - unused */
+#define CURS_PAL_REG 	0xe4080508	/* to 0x080518 */
+#define CHKSUM_REG 	0xe4080600	/* to 0x080610 - unused */
 #define CURS_POS_REG 	0xe4080638
 #define CLR_PAL_REG 	0xe4080800	/* to 0x080ff8 */
 #define CURS_PAT_REG 	0xe4081000	/* to 0x081ff8 */
-#define MON_ID_REG 	0xe4100000 	/* unused */
-#define RESET_REG 	0xe4180000  	/* Write only */
+#define MON_ID_REG 	0xe4100000	/* unused */
+#define RESET_REG 	0xe4180000	/* Write only */
 
 static struct display disp;
 static struct fb_info fb_info;
-static struct { u_char red, green, blue, pad; } palette[256];
 
-static struct fb_fix_screeninfo fb_fix = { { "G364 8plane", } };
-static struct fb_var_screeninfo fb_var = { 0, };
+static struct fb_fix_screeninfo fb_fix __initdata = {
+	id:		"G364 8plane",
+	smem_start:	0x40000000,	/* physical address */
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_PSEUDOCOLOR,
+	ypanstep:	1,
+	accel:		FB_ACCEL_NONE,
+};
 
+static struct fb_var_screeninfo fb_var __initdata = {
+	bits_per_pixel:	8,
+	red:		{ 0, 8, 0 },
+      	green:		{ 0, 8, 0 },
+      	blue:		{ 0, 8, 0 },
+      	activate:	FB_ACTIVATE_NOW,
+      	height:		-1,
+      	width:		-1,
+      	pixclock:	39722,
+      	left_margin:	40,
+      	right_margin:	24,
+      	upper_margin:	32,
+      	lower_margin:	11,
+      	hsync_len:	96,
+      	vsync_len:	2,
+      	vmode:		FB_VMODE_NONINTERLACED,
+};
 
 /*
  *  Interface used by the world
  */
-static int g364fb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			  struct fb_info *info);
-static int g364fb_get_var(struct fb_var_screeninfo *var, int con,
-			  struct fb_info *info);
-static int g364fb_set_var(struct fb_var_screeninfo *var, int con,
-			  struct fb_info *info);
+int g364fb_init(void);
+
 static int g364fb_pan_display(struct fb_var_screeninfo *var, int con,
 			      struct fb_info *info);
-static int g364fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			   struct fb_info *info);
-static int g364fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			    u_int transp, struct fb_info *info);
+static int g364fb_setcolreg(u_int regno, u_int red, u_int green,
+			    u_int blue, u_int transp,
+			    struct fb_info *info);
 static int g364fb_blank(int blank, struct fb_info *info);
 
-
-/*
- *  Interface to the low level console driver
- */
-int g364fb_init(void);
-static int g364fbcon_switch(int con, struct fb_info *info);
-static int g364fbcon_updatevar(int con, struct fb_info *info);
-
-/*
- *  Internal routines
- */
-static int g364fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-			    u_int *transp, struct fb_info *info);
-
 static struct fb_ops g364fb_ops = {
 	owner:		THIS_MODULE,
-	fb_get_fix:	g364fb_get_fix,
-	fb_get_var:	g364fb_get_var,
-	fb_set_var:	g364fb_set_var,
-	fb_get_cmap:	g364fb_get_cmap,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
 	fb_set_cmap:	gen_set_cmap,
 	fb_setcolreg:	g364fb_setcolreg,
 	fb_pan_display:	g364fb_pan_display,
 	fb_blank:	g364fb_blank,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
 };
 
-
 void fbcon_g364fb_cursor(struct display *p, int mode, int x, int y)
 {
-    switch (mode) {
-     case CM_ERASE:
-	*(unsigned int *) CTLA_REG |= CURS_TOGGLE;
-	break;
-
-     case CM_MOVE:
-     case CM_DRAW:
-	*(unsigned int *) CTLA_REG &= ~CURS_TOGGLE;
-	*(unsigned int *) CURS_POS_REG = ((x * fontwidth(p)) << 12) | ((y * fontheight(p))-p->var.yoffset);
-	break;
-    }
+	switch (mode) {
+	case CM_ERASE:
+		*(unsigned int *) CTLA_REG |= CURS_TOGGLE;
+		break;
+
+	case CM_MOVE:
+	case CM_DRAW:
+		*(unsigned int *) CTLA_REG &= ~CURS_TOGGLE;
+		*(unsigned int *) CURS_POS_REG =
+		    ((x * fontwidth(p)) << 12) | ((y * fontheight(p)) -
+						  p->var.yoffset);
+		break;
+	}
 }
 
-
-static struct display_switch fbcon_g364cfb8 = {
-    setup:		fbcon_cfb8_setup,
-    bmove:		fbcon_cfb8_bmove,
-    clear:		fbcon_cfb8_clear,
-    putc:		fbcon_cfb8_putc,
-    putcs:		fbcon_cfb8_putcs,
-    revc:		fbcon_cfb8_revc,
-    cursor:		fbcon_g364fb_cursor,
-    clear_margins:	fbcon_cfb8_clear_margins,
-    fontwidthmask:	FONTWIDTH(8)
-};
-
-/*
- *  Get the Fixed Part of the Display
- */
-static int g364fb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			  struct fb_info *info)
-{
-    memcpy(fix, &fb_fix, sizeof(fb_fix));
-    return 0;
-}
-
-
-/*
- *  Get the User Defined Part of the Display
- */
-static int g364fb_get_var(struct fb_var_screeninfo *var, int con,
-			  struct fb_info *info)
-{
-    memcpy(var, &fb_var, sizeof(fb_var));
-    return 0;
-}
-
-
-/*
- *  Set the User Defined Part of the Display
- */
-static int g364fb_set_var(struct fb_var_screeninfo *var, int con,
-			  struct fb_info *info)
-{
-    struct display *display;
-    int oldbpp = -1, err;
-
-    if (con >= 0)
-	display = &fb_display[con];
-    else
-	display = &disp;	/* used during initialization */
-
-    if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
-	var->xres_virtual > fb_var.xres_virtual ||
-	var->yres_virtual > fb_var.yres_virtual ||
-	var->bits_per_pixel > fb_var.bits_per_pixel ||
-	var->nonstd ||
-	(var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
-	return -EINVAL;
-    memcpy(var, &fb_var, sizeof(fb_var));
-    
-    if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-	oldbpp = display->var.bits_per_pixel;
-	display->var = *var;
-	*(unsigned int *)TOP_REG = var->yoffset * var->xres;	
-    }
-    if (oldbpp != var->bits_per_pixel) {
-	if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-	    return err;
-	do_install_cmap(con, info);
-    }
-    return 0;
-}
-
-
 /*
  *  Pan or Wrap the Display
  *
@@ -224,232 +156,115 @@
 static int g364fb_pan_display(struct fb_var_screeninfo *var, int con,
 			      struct fb_info *info)
 {
-    if (var->xoffset || var->yoffset+var->yres > var->yres_virtual)
-	return -EINVAL;
-    
-    *(unsigned int *)TOP_REG = var->yoffset * var->xres;
-    return 0;
-}
+	if (var->xoffset || var->yoffset + var->yres > var->yres_virtual)
+		return -EINVAL;
 
-/*
- *  Get the Colormap
- */
-static int g364fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			   struct fb_info *info)
-{
-    if (con == info->currcon) /* current console? */
-	return fb_get_cmap(cmap, kspc, g364fb_getcolreg, info);
-    else if (fb_display[con].cmap.len) /* non default colormap? */
-	fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-    else
-	fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-		     cmap, kspc ? 0 : 2);
-    return 0;
+	*(unsigned int *) TOP_REG = var->yoffset * var->xres;
+	return 0;
 }
 
 /*
- *  Initialisation
+ *  Blank the display.
  */
-int __init g364fb_init(void)
-{
-    int i,j;
-    volatile unsigned int *pal_ptr = (volatile unsigned int *) CLR_PAL_REG;
-    volatile unsigned int *curs_pal_ptr = (volatile unsigned int *) CURS_PAL_REG;
-    unsigned int xres, yres;
-    int mem;
-
-    /* TBD: G364 detection */
-    
-    /* get the resolution set by ARC console */
-    *(volatile unsigned int *)CTLA_REG &= ~ENABLE_VTG;
-    xres = (*((volatile unsigned int*)DISPLAY_REG) & 0x00ffffff) * 4;
-    yres = (*((volatile unsigned int*)VDISPLAY_REG) & 0x00ffffff) / 2;
-    *(volatile unsigned int *)CTLA_REG |= ENABLE_VTG;    
-
-    /* initialise color palette */
-    for (i = 0; i < 16; i++) {
-	j = color_table[i];
-	palette[i].red=default_red[j];
-	palette[i].green=default_grn[j];
-	palette[i].blue=default_blu[j];
-	pal_ptr[i << 1] = (palette[i].red << 16) | (palette[i].green << 8) | palette[i].blue;
-    }
-    
-    /* setup cursor */
-    curs_pal_ptr[0] |= 0x00ffffff;
-    curs_pal_ptr[2] |= 0x00ffffff;
-    curs_pal_ptr[4] |= 0x00ffffff;
-
-    /*
-     * first set the whole cursor to transparent
-     */
-    for (i = 0; i < 512; i++)
-	*(unsigned short *)(CURS_PAT_REG+i*8) = 0;
-
-    /*
-     * switch the last two lines to cursor palette 3
-     * we assume here, that FONTSIZE_X is 8
-     */
-    *(unsigned short *)(CURS_PAT_REG + 14*64) = 0xffff;
-    *(unsigned short *)(CURS_PAT_REG + 15*64) = 0xffff;			    
-
-    fb_var.bits_per_pixel = 8;
-    fb_var.xres = fb_var.xres_virtual = xres;
-    fb_var.yres = yres;
-
-    fb_fix.line_length = (xres / 8) * fb_var.bits_per_pixel;
-    fb_fix.smem_start = 0x40000000; /* physical address */
-    /* get size of video memory; this is special for the JAZZ hardware */
-    mem = (r4030_read_reg32(JAZZ_R4030_CONFIG) >> 8) & 3;
-    fb_fix.smem_len = (1 << (mem*2)) * 512 * 1024;
-    fb_fix.type = FB_TYPE_PACKED_PIXELS;
-    fb_fix.type_aux = 0;
-    fb_fix.visual = FB_VISUAL_PSEUDOCOLOR;    
-    fb_fix.xpanstep = 0;
-    fb_fix.ypanstep = 1;
-    fb_fix.ywrapstep = 0;
-    fb_fix.mmio_start = 0;
-    fb_fix.mmio_len = 0;
-    fb_fix.accel = FB_ACCEL_NONE;
-    
-    fb_var.yres_virtual = fb_fix.smem_len / xres;
-    fb_var.xoffset = fb_var.yoffset = 0;
-    fb_var.grayscale = 0;
-
-    fb_var.red.offset = 0;
-    fb_var.green.offset = 0;
-    fb_var.blue.offset = 0;
-
-    fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
-    fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
-    fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
-    fb_var.nonstd = 0;
-    fb_var.activate = 0;
-    fb_var.height = fb_var.width = -1;
-    fb_var.accel_flags = 0;
-    fb_var.pixclock = 39722;
-    fb_var.left_margin = 40;
-    fb_var.right_margin = 24;
-    fb_var.upper_margin = 32;
-    fb_var.lower_margin = 11;
-    fb_var.hsync_len = 96;
-    fb_var.vsync_len = 2;
-    fb_var.sync = 0;
-    fb_var.vmode = FB_VMODE_NONINTERLACED;
-
-    disp.var = fb_var;
-    disp.cmap.start = 0;
-    disp.cmap.len = 0;
-    disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
-    disp.visual = fb_fix.visual;
-    disp.type = fb_fix.type;
-    disp.type_aux = fb_fix.type_aux;
-    disp.ypanstep = fb_fix.ypanstep;
-    disp.ywrapstep = fb_fix.ywrapstep;
-    disp.line_length = fb_fix.line_length;
-    disp.can_soft_blank = 1;
-    disp.inverse = 0;
-    disp.dispsw = &fbcon_g364cfb8;
-
-    strcpy(fb_info.modename, fb_fix.id);
-    fb_info.node = NODEV;
-    fb_info.fbops = &g364fb_ops;
-    fb_info.screen_base = (char *)G364_MEM_BASE; /* virtual kernel address */
-    fb_info.disp = &disp;
-    fb_info.currcon = -1;	
-    fb_info.fontname[0] = '\0';
-    fb_info.changevar = NULL;
-    fb_info.switch_con = &g364fbcon_switch;
-    fb_info.updatevar = &g364fbcon_updatevar;
-    fb_info.flags = FBINFO_FLAG_DEFAULT;
-
-    g364fb_set_var(&fb_var, -1, &fb_info);
-
-    if (register_framebuffer(&fb_info) < 0)
-	return -EINVAL;
-
-    printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node),
-	   fb_fix.id);
-    return 0;
-}
-
-
-static int g364fbcon_switch(int con, struct fb_info *info)
+static int g364fb_blank(int blank, struct fb_info *info)
 {
-    /* Do we have to save the colormap? */
-    if (fb_display[info->currcon].cmap.len)
-	fb_get_cmap(&fb_display[info->currcon].cmap, 1, g364fb_getcolreg, info);
-
-    info->currcon = con;
-    /* Install new colormap */
-    do_install_cmap(con, info);
-    g364fbcon_updatevar(con, info);    
-    return 0;
+	if (blank)
+		*(unsigned int *) CTLA_REG |= FORCE_BLANK;
+	else
+		*(unsigned int *) CTLA_REG &= ~FORCE_BLANK;
+	return 0;
 }
 
 /*
- *  Update the `var' structure (called by fbcon.c)
+ *  Set a single color register. Return != 0 for invalid regno.
  */
-static int g364fbcon_updatevar(int con, struct fb_info *info)
+static int g364fb_setcolreg(u_int regno, u_int red, u_int green,
+			    u_int blue, u_int transp, struct fb_info *info)
 {
-    if (con == info->currcon) {
-	struct fb_var_screeninfo *var = &fb_display[info->currcon].var;
+	volatile unsigned int *ptr = (volatile unsigned int *) CLR_PAL_REG;
 
-	/* hardware scrolling */
-	*(unsigned int *)TOP_REG = var->yoffset * var->xres;	
-    }
-    return 0;
-}
+	if (regno > 255)
+		return 1;
 
-/*
- *  Blank the display.
- */
-static int g364fb_blank(int blank, struct fb_info *info)
-{
-    if (blank)
-	*(unsigned int *) CTLA_REG |= FORCE_BLANK;	
-    else
-	*(unsigned int *) CTLA_REG &= ~FORCE_BLANK;	
-    return 0;	
-}
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
 
-/*
- *  Read a single color register and split it into
- *  colors/transparent. Return != 0 for invalid regno.
- */
-static int g364fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-			    u_int *transp, struct fb_info *info)
-{
-    if (regno > 255)
-	return 1;
-    *red = (palette[regno].red << 8) | palette[regno].red;
-    *green = (palette[regno].green << 8) | palette[regno].green;
-    *blue = (palette[regno].blue << 8) | palette[regno].blue;
-    *transp = 0;
-    return 0;
+	ptr[regno << 1] = (red << 16) | (green << 8) | blue;
+
+	return 0;
 }
 
 /*
- *  Set a single color register. Return != 0 for invalid regno.
+ *  Initialisation
  */
-static int g364fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			    u_int transp, struct fb_info *info)
+int __init g364fb_init(void)
 {
-    volatile unsigned int *ptr = (volatile unsigned int *) CLR_PAL_REG;
-
-    if (regno > 255)
-	return 1;
-
-    red >>= 8;
-    green >>= 8;
-    blue >>=8;
-    palette[regno].red = red;
-    palette[regno].green = green;
-    palette[regno].blue = blue;
-    
-    ptr[regno << 1] = (red << 16) | (green << 8) | blue;
-
-    return 0;
+	volatile unsigned int *pal_ptr =
+	    (volatile unsigned int *) CLR_PAL_REG;
+	volatile unsigned int *curs_pal_ptr =
+	    (volatile unsigned int *) CURS_PAL_REG;
+	int mem, i, j;
+
+	/* TBD: G364 detection */
+
+	/* get the resolution set by ARC console */
+	*(volatile unsigned int *) CTLA_REG &= ~ENABLE_VTG;
+	fb_var.xres =
+	    (*((volatile unsigned int *) DISPLAY_REG) & 0x00ffffff) * 4;
+	fb_var.yres =
+	    (*((volatile unsigned int *) VDISPLAY_REG) & 0x00ffffff) / 2;
+	*(volatile unsigned int *) CTLA_REG |= ENABLE_VTG;
+
+	/* setup cursor */
+	curs_pal_ptr[0] |= 0x00ffffff;
+	curs_pal_ptr[2] |= 0x00ffffff;
+	curs_pal_ptr[4] |= 0x00ffffff;
+
+	/*
+	 * first set the whole cursor to transparent
+	 */
+	for (i = 0; i < 512; i++)
+		*(unsigned short *) (CURS_PAT_REG + i * 8) = 0;
+
+	/*
+	 * switch the last two lines to cursor palette 3
+	 * we assume here, that FONTSIZE_X is 8
+	 */
+	*(unsigned short *) (CURS_PAT_REG + 14 * 64) = 0xffff;
+	*(unsigned short *) (CURS_PAT_REG + 15 * 64) = 0xffff;
+	fb_var.xres_virtual = fbvar.xres;
+	fb_fix.line_length = (xres / 8) * fb_var.bits_per_pixel;
+	fb_fix.smem_start = 0x40000000;	/* physical address */
+	/* get size of video memory; this is special for the JAZZ hardware */
+	mem = (r4030_read_reg32(JAZZ_R4030_CONFIG) >> 8) & 3;
+	fb_fix.smem_len = (1 << (mem * 2)) * 512 * 1024;
+	fb_var.yres_virtual = fb_fix.smem_len / fb_var.xres;
+
+	strcpy(fb_info.modename, fb_fix.id);
+	fb_info.node = NODEV;
+	fb_info.fbops = &g364fb_ops;
+	fb_info.screen_base = (char *) G364_MEM_BASE;	/* virtual kernel address */
+	fb_info.var = fb_var;
+	fb_info.fix = fb_fix;
+	fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+	fb_info.disp = &disp;
+	fb_info.currcon = -1;
+	fb_info.fontname[0] = '\0';
+	fb_info.changevar = NULL;
+	fb_info.switch_con = gen_switch;
+	fb_info.updatevar = gen_update_var;
+
+	fb_alloc_cmap(&fb_info.cmap, 255, 0);
+	gen_set_disp(-1, &fb_info);
+
+	if (register_framebuffer(&fb_info) < 0)
+		return -EINVAL;
+
+	printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node),
+	       fb_info.fix.id);
+	return 0;
 }
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/hgafb.c b/drivers/video/hgafb.c
--- a/drivers/video/hgafb.c	Wed May 29 11:43:02 2002
+++ b/drivers/video/hgafb.c	Wed May 29 11:43:02 2002
@@ -387,44 +387,6 @@
  * ------------------------------------------------------------------------- */
 
 /**
- *	hga_get_fix - get the fixed part of the display
- *	@fix:struct fb_fix_screeninfo to fill in
- *	@con:unused
- *	@info:pointer to fb_info object containing info for current hga board
- *
- *	This wrapper function copies @info->fix to @fix.
- *	A zero is returned on success and %-EINVAL for failure.
- */
-
-int hga_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
-{
-	CHKINFO(-EINVAL);
-	DPRINTK("hga_get_fix: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info);
-
-	*fix = info->fix;
-	return 0;
-}
-
-/**
- *	hga_get_var - get the user defined part of the display
- *	@var:struct fb_var_screeninfo to fill in
- *	@con:unused
- *	@info:pointer to fb_info object containing info for current hga board
- *
- *	This wrapper function copies @info->var to @var.
- *	A zero is returned on success and %-EINVAL for failure.
- */
-
-int hga_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
-{
-	CHKINFO(-EINVAL);
-	DPRINTK("hga_get_var: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info);
-
-	*var = info->var;
-	return 0;
-}
-
-/**
  *	hga_set_var - set the user defined part of the display
  *	@var:new video mode
  *	@con:unused
@@ -596,8 +558,8 @@
 
 static struct fb_ops hgafb_ops = {
 	owner:		THIS_MODULE,
-	fb_get_fix:	hga_get_fix,
-	fb_get_var:	hga_get_var,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
 	fb_set_var:	hga_set_var,
 	fb_get_cmap:	hga_get_cmap,
 	fb_set_cmap:	gen_set_cmap,
diff -Nru a/drivers/video/hitfb.c b/drivers/video/hitfb.c
--- a/drivers/video/hitfb.c	Wed May 29 11:43:01 2002
+++ b/drivers/video/hitfb.c	Wed May 29 11:43:01 2002
@@ -21,6 +21,7 @@
 #include <linux/delay.h>
 #include <linux/nubus.h>
 #include <linux/init.h>
+#include <linux/fb.h>
 
 #include <asm/machvec.h>
 #include <asm/uaccess.h>
@@ -28,347 +29,165 @@
 #include <asm/io.h>
 #include <asm/hd64461.h>
 
-#include <linux/fb.h>
-
 #include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
 
-
-struct hitfb_par
-{
-    int x, y;
-    int bpp;
+static struct fb_var_screeninfo hitfb_var __initdata = {
+	activate:	FB_ACTIVATE_NOW,
+	height:		-1,
+	width:		-1,
+	vmode:		FB_VMODE_NONINTERLACED,
 };
 
-
-struct hitfb_info {
-    struct fb_info_gen gen;
-    struct display disp;
-    struct hitfb_par current_par;
-    struct fb_var_screeninfo default_var;
-    int current_par_valid;
-    unsigned long hit_videobase, hit_videosize;
-    union {
-#ifdef FBCON_HAS_CFB16
-	u16 cfb16[16];
-#endif
-    } fbcon_cmap;
-} fb_info = {
-    {},
-    {},
-    {},
-    {},
-    0, 0, 0,
-    {},
+static struct fb_fix_screeninfo hitfb_fix __initdata = {
+	id:		"Hitachi HD64461",
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_TRUECOLOR,
+	accel_flags:	FB_ACCEL_NONE,
 };
 
-
-static void hitfb_set_par(const void *fb_par, struct fb_info_gen *info);
-static int hitfb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
-			    struct fb_info_gen *info);
-
-
-static void hitfb_detect(void)
-{
-    struct hitfb_par par;
-    unsigned short lcdclor, ldr3, ldvntr;
-
-    fb_info.hit_videobase = CONFIG_HD64461_IOBASE + 0x02000000;
-    fb_info.hit_videosize = (MACH_HP680 || MACH_HP690) ? 1024*1024 : 512*1024;
-
-    lcdclor = inw(HD64461_LCDCLOR);
-    ldvntr = inw(HD64461_LDVNTR);
-    ldr3 = inw(HD64461_LDR3);
-
-    switch(ldr3&15) {
-    default:
-    case 4:
-        par.bpp = 8;
-	par.x = lcdclor;
-	break;
-    case 8:
-        par.bpp = 16;
-	par.x = lcdclor/2;
-	break;
-    }
-
-    par.y = ldvntr+1;
-
-    hitfb_set_par(&par, NULL);
-    hitfb_encode_var(&fb_info.default_var, &par, NULL);
-}
-
-
-static int hitfb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par,
-			     struct fb_info_gen *info)
-{
-    const struct hitfb_par *par = fb_par;
-
-    memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-
-    strcpy(fix->id, "Hitachi HD64461");
-    fix->smem_start = fb_info.hit_videobase;
-    fix->smem_len = fb_info.hit_videosize;
-    fix->type = FB_TYPE_PACKED_PIXELS;
-    fix->type_aux = 0;
-    fix->visual = (par->bpp == 8) ?
-	FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
-    fix->xpanstep = 0;
-    fix->ypanstep = 0;
-    fix->ywrapstep = 0;
-
-    switch(par->bpp) {
-    default:
-    case 8:
-	fix->line_length = par->x;
-	break;
-    case 16:
-	fix->line_length = par->x*2;
-	break;
-    }
-
-    return 0;
-}
-
-
-static int hitfb_decode_var(const struct fb_var_screeninfo *var, void *fb_par,
-			     struct fb_info_gen *info)
-{
-    struct hitfb_par *par = fb_par;
-
-    par->x = var->xres;
-    par->y = var->yres;
-    par->bpp = var->bits_per_pixel;
-    return 0;
-}
-
-
-static int hitfb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
-			     struct fb_info_gen *info)
-{
-    const struct hitfb_par *par = fb_par;
-
-    memset(var, 0, sizeof(*var));
-
-    var->xres = par->x;
-    var->yres = par->y;
-    var->xres_virtual = var->xres;
-    var->yres_virtual = var->yres;
-    var->xoffset = 0;
-    var->yoffset = 0;
-    var->bits_per_pixel = par->bpp;
-    var->grayscale = 0;
-    var->transp.offset = 0;
-    var->transp.length = 0;
-    var->transp.msb_right = 0;
-    var->nonstd = 0;
-    var->activate = 0;
-    var->height = -1;
-    var->width = -1;
-    var->vmode = FB_VMODE_NONINTERLACED;
-    var->pixclock = 0;
-    var->sync = 0;
-    var->left_margin = 0;
-    var->right_margin = 0;
-    var->upper_margin = 0;
-    var->lower_margin = 0;
-    var->hsync_len = 0;
-    var->vsync_len = 0;
-
-    switch (var->bits_per_pixel) {
-
-	case 8:
-	    var->red.offset = 0;
-	    var->red.length = 8;
-	    var->green.offset = 0;
-	    var->green.length = 8;
-	    var->blue.offset = 0;
-	    var->blue.length = 8;
-	    var->transp.offset = 0;
-	    var->transp.length = 0;
-	    break;
-
-	case 16:	/* RGB 565 */
-	    var->red.offset = 11;
-	    var->red.length = 5;
-	    var->green.offset = 5;
-	    var->green.length = 6;
-	    var->blue.offset = 0;
-	    var->blue.length = 5;
-	    var->transp.offset = 0;
-	    var->transp.length = 0;
-	    break;
-    }
-
-    var->red.msb_right = 0;
-    var->green.msb_right = 0;
-    var->blue.msb_right = 0;
-    var->transp.msb_right = 0;
-
-    return 0;
-}
-
-
-static void hitfb_get_par(void *par, struct fb_info_gen *info)
-{
-    *(struct hitfb_par *)par = fb_info.current_par;
-}
-
-
-static void hitfb_set_par(const void *fb_par, struct fb_info_gen *info)
-{
-    const struct hitfb_par *par = fb_par;
-    fb_info.current_par = *par;
-    fb_info.current_par_valid = 1;
+static u16 pseudo_palette[17];
+static struct display display;
+struct fb_info fb_info;
+
+static int hitfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;
+
+	switch (var->bits_per_pixel) {
+		case 8:
+			var->red.offset = 0;
+			var->red.length = 8;
+			var->green.offset = 0;
+			var->green.length = 8;
+			var->blue.offset = 0;
+			var->blue.length = 8;
+			var->transp.offset = 0;
+			var->transp.length = 0;
+			break;
+		case 16:	/* RGB 565 */
+			var->red.offset = 11;
+			var->red.length = 5;
+			var->green.offset = 5;
+			var->green.length = 6;
+			var->blue.offset = 0;
+			var->blue.length = 5;
+			var->transp.offset = 0;
+			var->transp.length = 0;
+			break;
+	}
+	return 0;
 }
 
-
-static int hitfb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
-			   unsigned *blue, unsigned *transp,
-			   struct fb_info *info)
+static int hitfb_set_par(struct fb_info *info)
 {
-    if (regno > 255)
-	return 1;	
+	info->fix.visual = (info->var.bits_per_pixel == 8) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
 
-    outw(regno<<8, HD64461_CPTRAR);
-    *red = inw(HD64461_CPTRDR)<<10;
-    *green = inw(HD64461_CPTRDR)<<10;
-    *blue = inw(HD64461_CPTRDR)<<10;
-    *transp = 0;
-    
-    return 0;
+	switch(info->var.bits_per_pixel) {
+		default:
+		case 8:
+			info->fix.line_length = info->var.xres;
+			break;
+		case 16:
+			info->fix.line_length = info->var.xres*2;
+			break;
+	}
+	return 0;
 }
 
-
 static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
 			   unsigned blue, unsigned transp,
 			   struct fb_info *info)
 {
-    if (regno > 255)
-	return 1;
+	if (regno > 255)
+		return 1;
     
-    outw(regno<<8, HD64461_CPTWAR);
-    outw(red>>10, HD64461_CPTWDR);
-    outw(green>>10, HD64461_CPTWDR);
-    outw(blue>>10, HD64461_CPTWDR);
+	outw(regno << 8, HD64461_CPTWAR);
+	outw(red >> 10, HD64461_CPTWDR);
+	outw(green >> 10, HD64461_CPTWDR);
+	outw(blue >> 10, HD64461_CPTWDR);
     
-    if(regno<16) {
-	switch(fb_info.current_par.bpp) {
+	if (regno < 16) {
+		switch(info->var.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB16
-	case 16:
-	    fb_info.fbcon_cmap.cfb16[regno] =
-		((red   & 0xf800)      ) |
-		((green & 0xfc00) >>  5) |
-		((blue  & 0xf800) >> 11);
-	    break;
+		case 16:
+			((u16 *)(info->pseudo_palette))[regno] =
+					((red   & 0xf800)      ) |
+					((green & 0xfc00) >>  5) |
+					((blue  & 0xf800) >> 11);
+			break;
 #endif
+		}
 	}
-    }
-
-    return 0;
+	return 0;
 }
 
-
-static int hitfb_pan_display(const struct fb_var_screeninfo *var,
-			     struct fb_info_gen *info)
-{
-    if (!fb_info.current_par_valid)
-	return -EINVAL;
-
-    return 0;
-}
-
-
-static int hitfb_blank(int blank_mode, struct fb_info_gen *info)
-{
-    if (!fb_info.current_par_valid)
-	return 1;
-
-    return 0;
-}
-
-
-static void hitfb_set_disp(const void *fb_par, struct display *disp,
-			    struct fb_info_gen *info)
-{
-    const struct hitfb_par *par = fb_par;
-
-    disp->scrollmode = SCROLL_YREDRAW;
-
-    switch(((struct hitfb_par *)par)->bpp) {
-#ifdef FBCON_HAS_CFB8
-    case 8:
-	disp->dispsw = &fbcon_cfb8;
-	break;
-#endif
-#ifdef FBCON_HAS_CFB16
-    case 16:
-	disp->dispsw = &fbcon_cfb16;
-	disp->dispsw_data = fb_info.fbcon_cmap.cfb16;
-	break;
-#endif
-    default:
-	disp->dispsw = &fbcon_dummy;
-    }
-}
-
-
-struct fbgen_hwswitch hitfb_switch = {
-    hitfb_detect,
-    hitfb_encode_fix,
-    hitfb_decode_var,
-    hitfb_encode_var,
-    hitfb_get_par,
-    hitfb_set_par,
-    hitfb_getcolreg,
-    hitfb_pan_display,
-    hitfb_blank,
-    hitfb_set_disp
-};
-
-
 static struct fb_ops hitfb_ops = {
-    owner:		THIS_MODULE,
-    fb_get_fix:		fbgen_get_fix,
-    fb_get_var:		fbgen_get_var,
-    fb_set_var:		fbgen_set_var,
-    fb_get_cmap:	fbgen_get_cmap,
-    fb_set_cmap:	fbgen_set_cmap,
-    fb_setcolreg:	hitfb_setcolreg,	
-    fb_pan_display:	fbgen_pan_display,
-    fb_blank:		fbgen_blank,	
+	owner:		THIS_MODULE,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
+	fb_set_cmap:	gen_set_cmap,
+	fb_check_var:	hitfb_check_var,
+	fb_set_par:	hitfb_set_par,
+	fb_setcolreg:	hitfb_setcolreg,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
 };
 
-
 int __init hitfb_init(void)
 {
-    strcpy(fb_info.gen.info.modename, "Hitachi HD64461");
-    fb_info.gen.info.node = NODEV;
-    fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
-    fb_info.gen.info.fbops = &hitfb_ops;
-    fb_info.gen.info.disp = &fb_info.disp;
-    fb_info.gen.info.currcon = 1;	
-    fb_info.gen.info.changevar = NULL;
-    fb_info.gen.info.switch_con = &fbgen_switch;
-    fb_info.gen.info.updatevar = &fbgen_update_var;
-    fb_info.gen.parsize = sizeof(struct hitfb_par);
-    fb_info.gen.fbhw = &hitfb_switch;
-    fb_info.gen.fbhw->detect();
-    fb_info.screen_base = (void *)fb_info.hit_videobase;
-    
-    fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
-    fb_info.disp.var.activate = FB_ACTIVATE_NOW;
-    fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen);
-    fbgen_set_disp(-1, &fb_info.gen);
-    do_install_cmap(0, &fb_info.gen);
-    
-    if(register_framebuffer(&fb_info.gen.info)<0) return -EINVAL;
-    
-    printk(KERN_INFO "fb%d: %s frame buffer device\n",
-	   GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename);
-    
-    return 0;
+	unsigned short lcdclor, ldr3, ldvntr;
+
+	hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000;
+	hitfb_fix.smem_len = (MACH_HP680 || MACH_HP690) ? 1024*1024 : 512*1024;
+
+	lcdclor = inw(HD64461_LCDCLOR);
+	ldvntr = inw(HD64461_LDVNTR);
+	ldr3 = inw(HD64461_LDR3);
+
+	switch (ldr3&15) {
+		default:
+		case 4:
+			hitfb_var.bits_per_pixel = 8;
+			hitfb_var.xres = lcdclor;
+			break;
+		case 8:
+			hitfb_var.bits_per_pixel = 16;
+			hitfb_var.xres = lcdclor/2;
+			break;
+	}
+	hitfb_var.yres = ldvntr+1;
+
+	fb_info.node		= NODEV;
+	fb_info.fbops 		= &hitfb_ops;
+	fb_info.var 		= hitfb_var;
+	fb_info.fix 		= hitfb_fix;
+	fb_info.pseudo_palette 	= pseudo_palette;	
+	fb_info.flags 		= FBINFO_FLAG_DEFAULT;
+    	
+	strcpy(fb_info.modename, fb_info.fix.id);
+	fb_info.currcon = -1;
+	fb_info.disp = &display;
+	fb_info.changevar = NULL;
+	fb_info.switch_con = gen_switch;
+	fb_info.updatevar = gen_update_var;
+	fb_info.screen_base = (void *) hitfb_fix.smem_start;
+
+	size = (fb_info.var.bits_per_pixel == 8) ? 256 : 16;
+	fb_alloc_cmap(&fb_info.cmap, size, 0); 	
+
+	gen_set_var(&fb_info.var, -1, &fb_info);
+    
+	if (register_framebuffer(&fb_info) < 0)
+		return -EINVAL;
+    
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+			GET_FB_IDX(fb_info.node), fb_info.fix.id);
+	return 0;
 }
 
 
@@ -391,7 +210,6 @@
   hitfb_cleanup(void);
 }
 #endif
-
 
 /*
  * Local variables:
diff -Nru a/drivers/video/hpfb.c b/drivers/video/hpfb.c
--- a/drivers/video/hpfb.c	Wed May 29 11:43:03 2002
+++ b/drivers/video/hpfb.c	Wed May 29 11:43:03 2002
@@ -1,9 +1,6 @@
 /*
  *	HP300 Topcat framebuffer support (derived from macfb of all things)
  *	Phil Blundell <philb@gnu.org> 1998
- * 
- * Should this be moved to drivers/dio/video/ ? -- Peter Maydell
- * No! -- Jes
  */
 
 #include <linux/module.h>
@@ -23,15 +20,9 @@
 #include <asm/hwtest.h>
 
 #include <video/fbcon.h>
-#include <video/fbcon-mfb.h>
-#include <video/fbcon-cfb2.h>
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
 
-static struct display disp;
 static struct fb_info fb_info;
 
-unsigned long fb_start, fb_size = 1024*768, fb_line_length = 1024;
 unsigned long fb_regs;
 unsigned char fb_bitmask;
 
@@ -51,216 +42,77 @@
 #define WWIDTH		0x4102
 #define WMOVE		0x409c
 
-static struct fb_var_screeninfo hpfb_defined = {
-	0,0,0,0,	/* W,H, W, H (virtual) load xres,xres_virtual*/
-	0,0,		/* virtual -> visible no offset */
-	0,		/* depth -> load bits_per_pixel */
-	0,		/* greyscale ? */
-	{0,2,0},	/* R */
-	{0,2,0},	/* G */
-	{0,2,0},	/* B */
-	{0,0,0},	/* transparency */
-	0,		/* standard pixel format */
-	FB_ACTIVATE_NOW,
-	274,195,	/* 14" monitor */
-	FB_ACCEL_NONE,
-	0L,0L,0L,0L,0L,
-	0L,0L,0,	/* No sync info */
-	FB_VMODE_NONINTERLACED,
-	{0,0,0,0,0,0}
-};
+static struct fb_fix_screeninfo hpfb_fix __initdata = {
+	id:		"HP300 Topcat",
+	smem_len:	1024*768,
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_PSEUDOCOLOR,
+	line_length:	1024,
+	accel:		FB_ACCEL_NONE,
 
-struct hpfb_par
-{
+static struct fb_var_screeninfo hpfb_defined = {
+	xres:		1024,
+	yres:		768,
+	xres_virtual:	1024,
+	yres_virtual:	786,
+	bits_per_pixel:	1,
+	red:		{0,2,0},	/* R */
+	green:		{0,2,0},	/* G */
+	blue:		{0,2,0},	/* B */
+	activate:	FB_ACTIVATE_NOW,
+	height:		274,
+	width:		195,	/* 14" monitor */
+	accel_flags:	FB_ACCEL_NONE,
+	vmode:		FB_VMODE_NONINTERLACED,
 };
 
-struct hpfb_par current_par;
-
-static void hpfb_encode_var(struct fb_var_screeninfo *var, 
-				struct hpfb_par *par)
-{
-	int i=0;
-	var->xres=1024;
-	var->yres=768;
-	var->xres_virtual=1024;
-	var->yres_virtual=768;
-	var->xoffset=0;
-	var->yoffset=0;
-	var->bits_per_pixel = 1;
-	var->grayscale=0;
-	var->transp.offset=0;
-	var->transp.length=0;
-	var->transp.msb_right=0;
-	var->nonstd=0;
-	var->activate=0;
-	var->height= -1;
-	var->width= -1;
-	var->vmode=FB_VMODE_NONINTERLACED;
-	var->pixclock=0;
-	var->sync=0;
-	var->left_margin=0;
-	var->right_margin=0;
-	var->upper_margin=0;
-	var->lower_margin=0;
-	var->hsync_len=0;
-	var->vsync_len=0;
-	for(i=0;i<ARRAY_SIZE(var->reserved);i++)
-		var->reserved[i]=0;
-}
-
-static void hpfb_get_par(struct hpfb_par *par)
-{
-	*par=current_par;
-}
-
-static int fb_update_var(int con, struct fb_info *info)
-{
-	return 0;
-}
-
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
-	struct hpfb_par par;
-	
-	hpfb_get_par(&par);
-	hpfb_encode_var(var, &par);
-	return 0;
-}
-
-static int hpfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
-{
-	return 0;
-}
+static struct display display;
 
 /*
- * Set the palette.  This may not work on all boards but only experimentation will tell.
+ * Set the palette.  This may not work on all boards but only experimentation 
+ * will tell.
  * XXX Doesn't work at all.
  */
-
-static int hpfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
-{
-	unsigned int i;
-	for (i = 0; i < cmap->len; i++)
-	{
-		while (readw(fb_regs + 0x6002) & 0x4) udelay(1);
-		writew(0, fb_regs + 0x60f0);
-		writew(cmap->start + i, fb_regs + 0x60b8);
-		writew(cmap->red[i], fb_regs + 0x60b2);
-		writew(cmap->green[i], fb_regs + 0x60b4);
-		writew(cmap->blue[i], fb_regs + 0x60b6);
-		writew(0xff, fb_regs + 0x60f0);
-		udelay(100);
-	}
+static int hpfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                           unsigned blue, unsigned transp,
+                           struct fb_info *info)
+{
+	while (readw(fb_regs + 0x6002) & 0x4) udelay(1);
+	writew(0, fb_regs + 0x60f0);
+	writew(regno, fb_regs + 0x60b8);
+	writew(red, fb_regs + 0x60b2);
+	writew(green, fb_regs + 0x60b4);
+	writew(blue, fb_regs + 0x60b6);
+	writew(0xff, fb_regs + 0x60f0);
+	udelay(100);
 	writew(0xffff, fb_regs + 0x60ba);
 	return 0;
 }
 
-static int hpfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
-{
-	struct hpfb_par par;
-	if(con==-1)
-	{
-		hpfb_get_par(&par);
-		hpfb_encode_var(var, &par);
-	}
-	else
-		*var=fb_display[con].var;
-	return 0;
-}
-
-static int hpfb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
-{
-	int err;
-	
-	if ((err=do_fb_set_var(var, 1)))
-		return err;
-	return 0;
-}
-
-static void hpfb_encode_fix(struct fb_fix_screeninfo *fix, 
-				struct hpfb_par *par)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, "HP300 Topcat");
-
-	/*
-	 * X works, but screen wraps ... 
-	 */
-	fix->smem_start=fb_start;
-	fix->smem_len=fb_size;
-	fix->type = FB_TYPE_PACKED_PIXELS;
-	fix->visual = FB_VISUAL_PSEUDOCOLOR;
-	fix->xpanstep=0;
-	fix->ypanstep=0;
-	fix->ywrapstep=0;
-	fix->line_length=fb_line_length;
-}
-
-static int hpfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
-{
-	struct hpfb_par par;
-	hpfb_get_par(&par);
-	hpfb_encode_fix(fix, &par);
-	return 0;
-}
-
-static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h)
+void hpfb_copyarea(struct fb_info *info, struct fb_copyarea *area) 
 {
 	while (readb(fb_regs + BUSY) & fb_bitmask);
 	writeb(0x3, fb_regs + WMRR);
-	writew(x0, fb_regs + SOURCE_X);
-	writew(y0, fb_regs + SOURCE_Y);
-	writew(x1, fb_regs + DEST_X);
-	writew(y1, fb_regs + DEST_Y);
-	writew(h, fb_regs + WHEIGHT);
-	writew(w, fb_regs + WWIDTH);
+	writew(area->sx, fb_regs + SOURCE_X);
+	writew(area->sy, fb_regs + SOURCE_Y);
+	writew(area->dx, fb_regs + DEST_X);
+	writew(area->dy, fb_regs + DEST_Y);
+	writew(area->height, fb_regs + WHEIGHT);
+	writew(area->width, fb_regs + WWIDTH);
 	writeb(fb_bitmask, fb_regs + WMOVE);
 }
 
-static int hpfb_switch(int con, struct fb_info *info)
-{
-	do_fb_set_var(&fb_display[con].var,1);
-	info->currcon = con;
-	return 0;
-}
-
-static void hpfb_set_disp(int con)
-{
-	struct fb_fix_screeninfo fix;
-	struct display *display;
-	
-	if (con >= 0)
-		display = &fb_display[con];
-	else
-		display = &disp;	/* used during initialization */
-
-	hpfb_get_fix(&fix, con, 0);
-
-	display->visual = fix.visual;
-	display->type = fix.type;
-	display->type_aux = fix.type_aux;
-	display->ypanstep = fix.ypanstep;
-	display->ywrapstep = fix.ywrapstep;
-	display->line_length = fix.line_length;
-	display->next_line = fix.line_length;
-	display->can_soft_blank = 0;
-	display->inverse = 0;
-
-	display->dispsw = &fbcon_cfb8;
-}
-
 static struct fb_ops hpfb_ops = {
 	owner:		THIS_MODULE,
-	fb_get_fix:	hpfb_get_fix,
-	fb_get_var:	hpfb_get_var,
-	fb_set_var:	hpfb_set_var,
-	fb_get_cmap:	hpfb_get_cmap,
-	fb_set_cmap:	hpfb_set_cmap,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
+	fb_set_cmap:	gen_set_cmap,
+	fb_setcolreg:	hpfb_setcolreg,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	hpfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
 };
 
 #define TOPCAT_FBOMSB	0x5d
@@ -273,7 +125,7 @@
 	fboff = (readb(base + TOPCAT_FBOMSB) << 8) 
 		| readb(base + TOPCAT_FBOLSB);
 
-	fb_start = 0xf0000000 | (readb(base + fboff) << 16);
+	hpfb_fix.smem_start = 0xf0000000 | (readb(base + fboff) << 16);
 	fb_regs = base;
 
 #if 0
@@ -285,17 +137,6 @@
 	writeb(0, base+0x4516);
 	writeb(0x90, base+0x4206);
 #endif
-
-	/*
-	 *	Fill in the available video resolution
-	 */
-	 
-	hpfb_defined.xres = 1024;
-	hpfb_defined.yres = 768;
-	hpfb_defined.xres_virtual = 1024;
-	hpfb_defined.yres_virtual = 768;
-	hpfb_defined.bits_per_pixel = 8;
-
 	/* 
 	 *	Give the hardware a bit of a prod and work out how many bits per
 	 *	pixel are supported.
@@ -303,8 +144,8 @@
 	
 	writeb(0xff, base + TC_WEN);
 	writeb(0xff, base + TC_FBEN);
-	writeb(0xff, fb_start);
-	fb_bitmask = readb(fb_start);
+	writeb(0xff, hpfb_fix.smem_start);
+	fb_bitmask = readb(hpfb_fix.smem_start);
 
 	/*
 	 *	Enable reading/writing of all the planes.
@@ -317,24 +158,25 @@
 	/*
 	 *	Let there be consoles..
 	 */
-	strcpy(fb_info.modename, "Topcat");
-	fb_info.changevar = NULL;
-	fb_info.node = NODEV;
+	fb_info.node  = NODEV;
 	fb_info.fbops = &hpfb_ops;
-	fb_info.screen_base = fb_start;
-	fb_info.disp = &disp;
-	fb_info.currcon = -1;
-	fb_info.switch_con = &hpfb_switch;
-	fb_info.updatevar = &fb_update_var;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;
-	do_fb_set_var(&hpfb_defined, 1);
+	fb_info.var   = hpfb_defined;
+	fb_info.fix   = hpfb_fix;
+	fb_info.screen_base = hpfb_fix.smem_start;
+
+	/* The below feilds will go away !!!! */
+	fb_info.currcon		= -1;
+        strcpy(fb_info.modename, fb_info.fix.id);
+        fb_info.disp		= &display;
+        fb_info.switch_con	= gen_switch;
+        fb_info.updatevar	= gen_update_var;
+	fb_alloc_cmap(&fb_info.cmap, 256, 0);
 
-	hpfb_get_var(&disp.var, -1, &fb_info);
-	hpfb_set_disp(-1);
+	gen_set_disp(-1, &fb_info);
 
 	if (register_framebuffer(&fb_info) < 0)
 		return 1;
-
 	return 0;
 }
 
@@ -364,29 +206,25 @@
 	 */
 #define INTFBADDR 0xf0560000
 
-	if (hwreg_present((void *)INTFBADDR) && (DIO_ID(INTFBADDR) == DIO_ID_FBUFFER)
-		&& topcat_sid_ok(sid = DIO_SECID(INTFBADDR)))
-	{
+	if (hwreg_present((void *)INTFBADDR) && 
+	   (DIO_ID(INTFBADDR) == DIO_ID_FBUFFER) &&
+	    topcat_sid_ok(sid = DIO_SECID(INTFBADDR))) {
 		printk("Internal Topcat found (secondary id %02x)\n", sid); 
 		hpfb_init_one(INTFBADDR);
-	}
-	else
-	{
+	} else {
 		int sc = dio_find(DIO_ID_FBUFFER);
-		if (sc)
-		{
+
+		if (sc) {
 			unsigned long addr = (unsigned long)dio_scodetoviraddr(sc);
 			unsigned int sid = DIO_SECID(addr);
 
-			if (topcat_sid_ok(sid))
-			{
+			if (topcat_sid_ok(sid)) {
 				printk("Topcat found at DIO select code %02x "
-				       "(secondary id %02x)\n", sc, sid);
+					"(secondary id %02x)\n", sc, sid);
 				hpfb_init_one(addr);
 			}
 		}
 	}
-
 	return 0;
 }
 
diff -Nru a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
--- a/drivers/video/matrox/matroxfb_accel.c	Wed May 29 11:43:03 2002
+++ b/drivers/video/matrox/matroxfb_accel.c	Wed May 29 11:43:03 2002
@@ -143,6 +143,8 @@
 	ACCESS_FBINFO(accel.m_opmode) = mopmode;
 }
 
+EXPORT_SYMBOL(matrox_cfbX_init);
+
 static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
 	int pixx = p->var.xres_virtual, start, end;
 	CRITFLAGS
@@ -943,7 +945,7 @@
 	CRITEND
 }
 
-void matrox_text_createcursor(WPMINFO struct display* p) {
+static void matrox_text_createcursor(WPMINFO struct display* p) {
 	CRITFLAGS
 
 	if (ACCESS_FBINFO(currcon_display) != p)
@@ -1029,6 +1031,8 @@
 	var->xres_virtual = vxres * hf;
 }
 
+EXPORT_SYMBOL(matrox_text_round);
+
 static int matrox_text_setfont(struct display* p, int width, int height) {
 	DBG("matrox_text_setfont");
 
@@ -1223,6 +1227,8 @@
 	}
 }
 
+EXPORT_SYMBOL(initMatrox);
+
 void matrox_init_putc(WPMINFO struct display* p, void (*dac_createcursor)(WPMINFO struct display* p)) {
 	int i;
 
@@ -1245,4 +1251,7 @@
 		ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs;
 	}
 }
+
+EXPORT_SYMBOL(matrox_init_putc);
+
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/matrox/matroxfb_accel.h b/drivers/video/matrox/matroxfb_accel.h
--- a/drivers/video/matrox/matroxfb_accel.h	Wed May 29 11:43:02 2002
+++ b/drivers/video/matrox/matroxfb_accel.h	Wed May 29 11:43:02 2002
@@ -5,7 +5,6 @@
 
 void matrox_init_putc(WPMINFO struct display* p, void (*)(WPMINFO struct display *p));
 void matrox_cfbX_init(WPMINFO struct display* p);
-void matrox_text_createcursor(WPMINFO struct display* p);
 void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p);
 void initMatrox(WPMINFO struct display* p);
 
diff -Nru a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
--- a/drivers/video/pm2fb.c	Wed May 29 11:43:03 2002
+++ b/drivers/video/pm2fb.c	Wed May 29 11:43:03 2002
@@ -67,9 +67,6 @@
 #define DPRINTK(a,b...)
 #endif 
 
-#define PICOS2KHZ(a) (1000000000UL/(a))
-#define KHZ2PICOS(a) (1000000000UL/(a))
-
 /*
  * The _DEFINITIVE_ memory mapping/unmapping functions.
  * This is due to the fact that they're changing soooo often...
diff -Nru a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/video/pm3fb.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,3832 @@
+/*
+ *  linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device
+ *  
+ *  Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr>
+ *  Based on code written by:
+ *           Sven Luther, <luther@dpt-info.u-strasbg.fr>
+ *           Alan Hourihane, <alanh@fairlite.demon.co.uk>
+ *           Russel King, <rmk@arm.linux.org.uk>
+ *  Based on linux/drivers/video/skeletonfb.c:
+ *	Copyright (C) 1997 Geert Uytterhoeven
+ *  Based on linux/driver/video/pm2fb.c:
+ *      Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ *      Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ *  $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $
+ *
+ *  CHANGELOG:
+ *  Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update.
+ *  Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2.
+ *  Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16.
+ *  Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings.
+ *  Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes.
+ *  Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix.
+ *  Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG.
+ *  Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL.
+ *  Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning.
+ *  Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option.
+ *  Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support.
+ *  Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates.
+ *  Fri Apr  6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup
+ *  Thu Mar 29 10:56:50 MET DST 2001, v 1.4.0: Module & module options support (note: linux patch changed, 2.2.19 added).
+ *  Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian.
+ *  Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov).
+ *  Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes.
+ *  Thu Mar  8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option.
+ *  Tue Mar  6 21:25:04 CET 2001, v 1.2.1: Better acceleration support.
+ *  Mon Mar  5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove)
+ *  Mon Mar  5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix.
+ *  Sun Mar  4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes.
+ *  Fri Mar  2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4
+ *  Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested)
+ *  Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode
+ *  Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up
+ *  Mon Feb 26 23:17:36 CET 2001, v 1.0.4: preliminary 2.4.x support, dropped (useless on pm3) partial product, more OF fix
+ *  Mon Feb 26 20:59:05 CET 2001, v 1.0.3: No more shadow register (and wasted memory), endianess fix, use OF-preset resolution by default
+ *  Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix
+ *  Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning
+ *  Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb2.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_FB_OF
+#include <asm/prom.h>
+#endif
+
+#include "pm3fb.h"
+
+/* ************************************* */
+/* ***** The various "global" data ***** */
+/* ************************************* */
+
+/* those will need a rework for multiple board support */
+/* Driver name */
+static const char permedia3_name[16] = "Permedia3";
+
+/* the fb_par struct, mandatory */
+struct pm3fb_par {
+	u32 pixclock;		/* pixclock in KHz */
+
+	u32 width;		/* width of virtual screen */
+	u32 height;		/* height of virtual screen */
+
+	u32 hsstart;		/* horiz. sync start */
+	u32 hsend;		/* horiz. sync end */
+	u32 hbend;		/* horiz. blank end (also gate end) */
+	u32 htotal;		/* total width (w/ sync & blank) */
+
+	u32 vsstart;		/* vert. sync start */
+	u32 vsend;		/* vert. sync end */
+	u32 vbend;		/* vert. blank end */
+	u32 vtotal;		/* total height (w/ sync & blank) */
+
+	u32 stride;		/* screen stride */
+	u32 base;		/* screen base (xoffset+yoffset) in 128 bits unit */
+	/* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */
+	u32 depth;		/* screen depth (8, 12, 15, 16 or 32) */
+	u32 video;		/* video control (hsync,vsync) */
+};
+
+/* memory timings */
+struct pm3fb_timings
+{
+	unsigned long caps;
+	unsigned long timings;
+	unsigned long control;
+	unsigned long refresh;
+	unsigned long powerdown;
+};
+typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result;
+#define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1)
+#define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE }
+
+/* the fb_info struct, mandatory */
+struct pm3fb_info {
+	struct fb_info_gen gen;
+	unsigned long board_num; /* internal board number */
+	unsigned long use_current;
+	struct pm3fb_par *current_par;
+	struct pci_dev *dev;    /* PCI device */
+#ifdef SUPPORT_FB_OF
+	struct device_node *dn; /* OF node for the PCI device */
+#endif /* SUPPORT_FB_OF */
+	unsigned long board_type; /* index in the cardbase */
+	unsigned char *fb_base;	/* framebuffer memory base */
+	u32 fb_size;		/* framebuffer memory size */
+	unsigned char *p_fb;	/* physical address of frame buffer */
+	unsigned char *v_fb;	/* virtual address of frame buffer */
+	unsigned char *pIOBase;	/* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */
+	unsigned char *vIOBase;	/* address of registers after ioremap() */
+	struct {
+		u8 transp;
+		u8 red;
+		u8 green;
+		u8 blue;
+	} palette[256];
+	union {
+#ifdef FBCON_HAS_CFB16
+		u16 cmap12[16]; /* RGBA 4444 */
+		u16 cmap15[16]; /* RGBA 5551 */
+		u16 cmap16[16]; /* RGBA 5650 */
+#endif
+#ifdef FBCON_HAS_CFB32
+		u32 cmap32[16];
+#endif
+	} cmap;
+	struct pm3fb_timings memt;
+};
+
+/* regular resolution database*/
+static struct {
+	char name[16];
+	struct pm3fb_par user_mode;
+} mode_base[] __initdata = {
+	{
+		"default-800x600", {
+	49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
+			    800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}}, {
+		"1024x768-74", {
+	78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
+			    806, 1024, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}}, {
+		"1024x768-74-32", {
+			78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
+			806, 1024, 0, 32,
+			PM3VideoControl_ENABLE |
+			PM3VideoControl_HSYNC_ACTIVE_HIGH
+			|
+			PM3VideoControl_VSYNC_ACTIVE_HIGH
+			| PM3VideoControl_PIXELSIZE_32BIT}},
+/* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/
+	{
+		"SGI1600SW", {
+			108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32,
+			1056, 1600, 0, 8,
+			PM3VideoControl_ENABLE|
+			PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW|
+			PM3VideoControl_PIXELSIZE_32BIT}}, 
+/* ##### auto-generated mode, by fbtimings2pm3 */
+/* Generated mode : "640x480-60" */
+	{
+		"640x480-60", {
+	25174, 640, 480, 16, 112, 160, 800, 10, 12, 45,
+			    525, 640, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "640x480-72" */
+	{
+		"640x480-72", {
+	31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520,
+			    640, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "640x480-75" */
+	{
+		"640x480-75", {
+	31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500,
+			    640, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "640x480-90" */
+	{
+		"640x480-90", {
+	39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533,
+			    640, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "640x480-100" */
+	{
+		"640x480-100", {
+	44899, 640, 480, 32, 160, 208, 848, 22, 34, 51,
+			    531, 640, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-48-lace" */
+/* INTERLACED NOT SUPPORTED
+  {"800x600-48-lace", {35999, 800, 600, 80, 208, 264, 1064, 11, 23, 102, 702, 800, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
+   INTERLACED NOT SUPPORTED */
+/* Generated mode : "800x600-56" */
+	{
+		"800x600-56", {
+	35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625,
+			    800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-60" */
+	{
+		"800x600-60", {
+	40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628,
+			    800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-70" */
+	{
+		"800x600-70", {
+	44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36,
+			    636, 800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-72" */
+	{
+		"800x600-72", {
+	50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66,
+			    666, 800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-75" */
+	{
+		"800x600-75", {
+	49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
+			    800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-90" */
+	{
+		"800x600-90", {
+	56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635,
+			    800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-100", from /etc/fb.modes */
+/* DISABLED, hsstart == 0
+	{
+		"800x600-100", {
+	67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625,
+			    800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+*/
+/* Generated mode : "800x600-100", from ??? */
+	{
+		"800x600-100", {
+			69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8,
+			PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
+			PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1024x768-43-lace" */
+/* INTERLACED NOT SUPPORTED
+  {"1024x768-43-lace", {44899, 1024, 768, 8, 184, 240, 1264, 1, 9, 49, 817, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
+   INTERLACED NOT SUPPORTED */
+/* Generated mode : "1024x768-60" */
+	{
+		"1024x768-60", {
+	64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38,
+			    806, 1024, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1024x768-70" */
+	{
+		"1024x768-70", {
+	74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38,
+			    806, 1024, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1024x768-72" */
+	{
+		"1024x768-72", {
+	74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38,
+			    806, 10224, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1024x768-75" */
+	{
+		"1024x768-75", {
+	78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32,
+			    800, 1024, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1024x768-90" */
+	{
+		"1024x768-90", {
+	100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77,
+			    845, 1024, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1024x768-100", from /etc/fb.modes */
+/* DISABLED, vsstart == 0
+	{
+		"1024x768-100", {
+	109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792,
+			    1024, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+*/
+/* Generated mode : "1024x768-100", from ??? */
+	{
+		"1024x768-100", {
+			115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8,
+			PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
+			PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1152x864-43-lace" */
+/* INTERLACED NOT SUPPORTED
+  {"1152x864-43-lace", {64998, 1152, 864, 72, 200, 264, 1416, 78, 87, 191, 1055, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
+   INTERLACED NOT SUPPORTED */
+/* Generated mode : "1152x864-47-lace" */
+/* INTERLACED NOT SUPPORTED
+  {"1152x864-47-lace", {64998, 1152, 864, 88, 216, 296, 1448, 30, 39, 83, 947, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
+   INTERLACED NOT SUPPORTED */
+/* Generated mode : "1152x864-60" */
+	{
+		"1152x864-60", {
+	80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52,
+			    916, 1152, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1152x864-70" */
+	{
+		"1152x864-70", {
+	100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81,
+			    945, 1152, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1152x864-75" */
+	{
+		"1152x864-75", {
+	109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138,
+			    1002, 1152, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1152x864-80" */
+	{
+		"1152x864-80", {
+	109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94,
+			    958, 1152, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1280x1024-43-lace" */
+/* INTERLACED NOT SUPPORTED
+  {"1280x1024-43-lace", {80000, 1024, 1024, 80, 160, 320, 1344, 50, 60, 125, 1149, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
+   INTERLACED NOT SUPPORTED */
+/* Generated mode : "1280x1024-47-lace" */
+/* INTERLACED NOT SUPPORTED
+  {"1280x1024-47-lace", {80000, 1280, 1024, 80, 160, 320, 1600, 1, 11, 29, 1053, 1280, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
+   INTERLACED NOT SUPPORTED */
+/* Generated mode : "1280x1024-60" */
+	{
+		"1280x1024-60", {
+	107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42,
+			    1066, 1280, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1280x1024-70" */
+	{
+		"1280x1024-70", {
+	125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42,
+			    1066, 1280, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1280x1024-74" */
+	{
+		"1280x1024-74", {
+	134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40,
+			    1064, 1280, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1280x1024-75" */
+	{
+		"1280x1024-75", {
+	134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42,
+			    1066, 1280, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1600x1200-60" */
+	{
+		"1600x1200-60", {
+	155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70,
+			    1270, 1600, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1600x1200-66" */
+	{
+		"1600x1200-66", {
+	171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53,
+			    1253, 1600, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1600x1200-76" */
+	{
+		"1600x1200-76", {
+	197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50,
+			    1250, 1600, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* ##### end of auto-generated mode */
+	{
+	"\0",}
+};
+
+/* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */
+static struct pm3fb_info fb_info[PM3_MAX_BOARD];
+static struct pm3fb_par current_par[PM3_MAX_BOARD];
+static int current_par_valid[PM3_MAX_BOARD];
+/* to allow explicit filtering of board */
+short bus[PM3_MAX_BOARD];
+short slot[PM3_MAX_BOARD];
+short func[PM3_MAX_BOARD];
+short disable[PM3_MAX_BOARD];
+short noaccel[PM3_MAX_BOARD];
+char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE];
+short depth[PM3_MAX_BOARD];
+short flatpanel[PM3_MAX_BOARD];
+static struct display disp[PM3_MAX_BOARD];
+static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy";
+short printtimings = 0;
+short forcesize[PM3_MAX_BOARD];
+
+/* ********************* */
+/* ***** prototype ***** */
+/* ********************* */
+/* card-specific */
+static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info);
+/* permedia3-specific */
+static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info);
+static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info);
+static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info);
+static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
+					unsigned long r);
+static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock,	/* In kHz units */
+					  unsigned long refclock,	/* In kHz units */
+					  unsigned char *prescale,	/* ClkPreScale */
+					  unsigned char *feedback,	/* ClkFeedBackScale */
+					  unsigned char *postscale
+					  /* ClkPostScale */ );
+static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc);
+static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b);
+static void pm3fb_common_init(struct pm3fb_info *l_fb_info);
+static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
+			  unsigned long depth, int v);
+static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
+			    unsigned long depth, int v);
+static void pm3fb_mapIO(struct pm3fb_info *l_fb_info);
+static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info);
+#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
+static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info);
+#endif
+static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info);
+static void pm3fb_write_mode(struct pm3fb_info *l_fb_info);
+static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
+			    struct pm3fb_par *curpar);
+static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info);
+/* accelerated permedia3-specific */
+#ifdef PM3FB_USE_ACCEL
+static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info);
+static void pm3fb_init_engine(struct pm3fb_info *l_fb_info);
+#ifdef FBCON_HAS_CFB32
+static void pm3fb_cfb32_clear(struct vc_data *conp,
+			      struct display *p,
+			      int sy, int sx, int height, int width);
+static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
+				      struct display *p, int bottom_only);
+#endif /* FBCON_HAS_CFB32 */
+#ifdef FBCON_HAS_CFB16
+static void pm3fb_cfb16_clear(struct vc_data *conp,
+			      struct display *p,
+			      int sy, int sx, int height, int width);
+static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
+				      struct display *p, int bottom_only);
+#endif /* FBCON_HAS_CFB16 */
+#ifdef FBCON_HAS_CFB8
+static void pm3fb_cfb8_clear(struct vc_data *conp,
+			     struct display *p,
+			     int sy, int sx, int height, int width);
+static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
+				     struct display *p, int bottom_only);
+#endif /* FBCON_HAS_CFB8 */
+#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
+static void pm3fb_cfbX_bmove(struct display *p,
+			     int sy, int sx,
+			     int dy, int dx, int height, int width);
+static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
+			    int c, int yy, int xx);
+static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
+			     const unsigned short *s, int count, int yy,
+			     int xx);
+static void pm3fb_cfbX_revc(struct display *p, int xx, int yy);
+#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
+#endif /* PM3FB_USE_ACCEL */
+/* pre-init */
+static void pm3fb_mode_setup(char *mode, unsigned long board_num);
+static void pm3fb_pciid_setup(char *pciid, unsigned long board_num);
+static char *pm3fb_boardnum_setup(char *options, unsigned long *bn);
+static void pm3fb_real_setup(char *options);
+/* fbdev */
+static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
+			    const void *par, struct fb_info_gen *info);
+static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
+			    void *par, struct fb_info_gen *info);
+static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d);
+static int pm3fb_encode_var(struct fb_var_screeninfo *var,
+			    const void *par, struct fb_info_gen *info);
+static void pm3fb_get_par(void *par, struct fb_info_gen *info);
+static void pm3fb_set_par(const void *par, struct fb_info_gen *info);
+static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
+			    unsigned char regno, unsigned char r,
+			    unsigned char g, unsigned char b);
+static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			   unsigned *blue, unsigned *transp,
+			   struct fb_info *info);
+static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info);
+static int pm3fb_blank(int blank_mode, struct fb_info_gen *info);
+static void pm3fb_set_disp(const void *par, struct display *disp,
+			   struct fb_info_gen *info);
+static void pm3fb_detect(void);
+static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
+			     struct fb_info_gen *info);
+static int pm3fb_ioctl(struct inode *inode, struct file *file,
+                       u_int cmd, u_long arg, int con,
+		       struct fb_info *info);
+
+
+/* the struct that hold them together */
+#ifdef KERNEL_2_2
+struct fbgen_hwswitch pm3fb_switch = {
+	pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
+	pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, pm3fb_setcolreg,
+	pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp
+};
+
+static struct fb_ops pm3fb_ops = {
+	fbgen_get_fix, fbgen_get_var, fbgen_set_var,
+	fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display, pm3fb_ioctl,
+	    NULL, NULL
+};
+#endif /* KERNEL_2_2 */
+#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
+struct fbgen_hwswitch pm3fb_switch = {
+	pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
+	pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, 
+	pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp
+};
+
+static struct fb_ops pm3fb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	fbgen_get_fix,
+	fb_get_var:	fbgen_get_var,
+	fb_set_var:	fbgen_set_var,
+	fb_get_cmap:	fbgen_get_cmap,
+	fb_set_cmap:	fbgen_set_cmap,
+	fb_setcolreg:	pm3fb_setcolreg,
+	fb_pan_display:	fbgen_pan_display,
+	fb_blank:	fbgen_blank,
+	fb_ioctl:	pm3fb_ioctl,
+};
+#endif /* KERNEL_2_4 or KERNEL_2_5 */
+#ifdef PM3FB_USE_ACCEL
+#ifdef FBCON_HAS_CFB32
+static struct display_switch pm3fb_cfb32 = {
+	fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear,
+	pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
+	NULL /* cursor() */ , NULL /* set_font() */ ,
+	pm3fb_cfb32_clear_margins,
+	FONTWIDTHRANGE(1, 16)	/* true only if accelerated... */
+};
+#endif /* FBCON_HAS_CFB32 */
+#ifdef FBCON_HAS_CFB16
+static struct display_switch pm3fb_cfb16 = {
+	fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear,
+	pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
+	NULL /* cursor() */ , NULL /* set_font() */ ,
+	pm3fb_cfb16_clear_margins,
+	FONTWIDTHRANGE(1, 16)	/* true only if accelerated... */
+};
+#endif /* FBCON_HAS_CFB16 */
+#ifdef FBCON_HAS_CFB8
+static struct display_switch pm3fb_cfb8 = {
+	fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear,
+	pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
+	NULL /* cursor() */ , NULL /* set_font() */ ,
+	pm3fb_cfb8_clear_margins,
+	FONTWIDTHRANGE(1, 16)	/* true only if accelerated... */
+};
+#endif /* FBCON_HAS_CFB8 */
+#endif /* PM3FB_USE_ACCEL */
+
+/* ****************************** */
+/* ***** card-specific data ***** */
+/* ****************************** */
+struct pm3fb_card_timings {
+	unsigned long memsize; /* 0 for last value (i.e. default) */
+	struct pm3fb_timings memt;
+};
+
+static struct pm3fb_card_timings t_FormacProFormance3[] = {
+	{ 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} },
+	{ 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */
+};
+
+static struct pm3fb_card_timings t_AppianJeronimo2000[] = {
+	{ 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} },
+	{ 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */
+};
+
+static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = {
+	{ 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} },
+	{ 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */
+};
+
+static struct {
+		char cardname[32]; /* recognized card name */
+		u16 subvendor; /* subvendor of the card */
+		u16 subdevice; /* subdevice of the card */
+		u8  func; /* function of the card to which the extra init apply */
+		void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */
+	struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */
+} cardbase[] = {
+	{ "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL },
+	{ "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL,
+	  t_AppianJeronimo2000
+	},
+	{ "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup,
+	  t_AppianJeronimo2000
+	},
+	{ "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */
+	  t_FormacProFormance3
+	},
+	{ "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL },
+	{ "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL,
+	  t_3DLabsOxygenVX1
+	},
+	{ "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL },
+	{ "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL },
+	{ "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL },
+	{ "\0", 0x0, 0x0, 0, NULL, NULL }
+};
+
+/* ********************************** */
+/* ***** card-specific function ***** */
+/* ********************************** */
+static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info)
+{       /* the appian j2000 require more initialization of the second head */
+	/* l_fb_info must point to the _second_ head of the J2000 */
+	
+	DTRACE;
+
+	l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */
+	
+	pm3fb_write_memory_timings(l_fb_info);
+}
+
+/* *************************************** */
+/* ***** permedia3-specific function ***** */
+/* *************************************** */
+static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info)
+{
+	l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps);
+	l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings);
+	l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl);
+	l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh);
+	l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown);
+
+	if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) ||
+	    (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) ||
+	    (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) ||
+	    (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) ||
+	    (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE))
+	{
+		printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num);
+		return(pm3fb_try_memory_timings(l_fb_info));
+	}
+	return(pm3fb_timing_ok);
+}
+
+static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info)
+{
+	if (cardbase[l_fb_info->board_type].c_memt)
+	{
+		int i = 0, done = 0;
+		while (!done)
+		{
+			if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size)
+			    || !(cardbase[l_fb_info->board_type].c_memt[i].memsize))
+			{ /* will use the 0-sized timings by default */
+				done = 1;
+				l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt;
+				printk(KERN_WARNING  "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n",
+				       l_fb_info->board_num,
+				       cardbase[l_fb_info->board_type].cardname,
+				       cardbase[l_fb_info->board_type].c_memt[i].memsize);
+				pm3fb_write_memory_timings(l_fb_info);
+				return(pm3fb_timing_retry);
+			}
+			i++;
+		}
+	} else
+		return(pm3fb_timing_problem);
+	return(pm3fb_timing_ok);
+}
+
+static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info)
+{
+	unsigned char m, n, p;
+	unsigned long clockused;
+	
+	PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps);
+	PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings);
+	PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control);
+	PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh);
+	PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown);
+
+	clockused =
+	    pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m,
+				 &n, &p);
+
+	PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m);
+	PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n);
+	PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p);
+	PM3_WRITE_DAC_REG(PM3RD_KClkControl,
+			  PM3RD_KClkControl_STATE_RUN |
+			  PM3RD_KClkControl_SOURCE_PLL |
+			  PM3RD_KClkControl_ENABLE);
+	PM3_WRITE_DAC_REG(PM3RD_MClkControl,
+			  PM3RD_MClkControl_STATE_RUN |
+			  PM3RD_MClkControl_SOURCE_KCLK |
+			  PM3RD_MClkControl_ENABLE);
+	PM3_WRITE_DAC_REG(PM3RD_SClkControl,
+			  PM3RD_SClkControl_STATE_RUN |
+			  PM3RD_SClkControl_SOURCE_PCLK |
+			  PM3RD_SClkControl_ENABLE);
+}
+
+static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
+					unsigned long r)
+{
+	DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)),
+		"l_fb_info->vIOBase mapped in read dac reg\n");
+	PM3_SET_INDEX(r);
+	mb();
+	return (PM3_READ_REG(PM3RD_IndexedData));
+}
+
+/* Calculating various clock parameter */
+static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock,	/* In kHz units */
+					  unsigned long refclock,	/* In kHz units */
+					  unsigned char *prescale,	/* ClkPreScale */
+					  unsigned char *feedback,	/* ClkFeedBackScale */
+					  unsigned char *postscale
+					  /* ClkPostScale */ )
+{
+	int f, pre, post;
+	unsigned long freq;
+	long freqerr = 1000;
+	unsigned long actualclock = 0;
+
+	DTRACE;
+
+	for (f = 1; f < 256; f++) {
+		for (pre = 1; pre < 256; pre++) {
+			for (post = 0; post < 5; post++) {
+				freq =
+				    ((2 * refclock * f) /
+				     (pre * (1 << post)));
+				if ((reqclock > freq - freqerr)
+				    && (reqclock < freq + freqerr)) {
+					freqerr =
+					    (reqclock >
+					     freq) ? reqclock -
+					    freq : freq - reqclock;
+					*feedback = f;
+					*prescale = pre;
+					*postscale = post;
+					actualclock = freq;
+				}
+			}
+		}
+	}
+
+	return (actualclock);
+}
+
+static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
+			  unsigned long depth, int v)
+{
+	DTRACE;
+	
+	switch (depth) {
+	case 8:
+		return (v >> 4);
+	case 12:
+	case 15:
+	case 16:
+		return (v >> 3);
+	case 32:
+		return (v >> 2);
+	}
+	DPRINTK(1, "Unsupported depth %ld\n", depth);
+	return (0);
+}
+
+static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
+			    unsigned long depth, int v)
+{
+	DTRACE;
+
+	switch (depth) {
+	case 8:
+		return (v << 4);
+	case 12:	
+	case 15:
+	case 16:
+		return (v << 3);
+	case 32:
+		return (v << 2);
+	}
+	DPRINTK(1, "Unsupported depth %ld\n", depth);
+	return (0);
+}
+
+static void pm3fb_mapIO(struct pm3fb_info *l_fb_info)
+{
+	DTRACE;
+
+	l_fb_info->vIOBase =
+	    ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE);
+	l_fb_info->v_fb =
+	    ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size);
+	DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n",
+		(unsigned long) l_fb_info->pIOBase,
+		(unsigned long) l_fb_info->vIOBase,
+		(unsigned long) l_fb_info->p_fb,
+		(unsigned long) l_fb_info->v_fb);
+}
+
+static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info)
+{
+	DTRACE;
+
+	iounmap(l_fb_info->vIOBase);
+	iounmap(l_fb_info->v_fb);
+	l_fb_info->vIOBase = (unsigned char *) -1;
+	l_fb_info->v_fb = (unsigned char *) -1;
+}
+
+#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
+static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info)
+{
+	DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0));
+	DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1));
+	DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n",
+		PM3_READ_REG(PM3ByAperture1Mode));
+	DPRINTK(2, "PM3ByAperture2Mode: 0x%08x\n",
+		PM3_READ_REG(PM3ByAperture2Mode));
+	DPRINTK(2, "PM3ChipConfig: 0x%08x\n", PM3_READ_REG(PM3ChipConfig));
+	DPRINTK(2, "PM3FIFODis: 0x%08x\n", PM3_READ_REG(PM3FIFODis));
+	DPRINTK(2, "PM3HTotal: 0x%08x\n", PM3_READ_REG(PM3HTotal));
+	DPRINTK(2, "PM3HbEnd: 0x%08x\n", PM3_READ_REG(PM3HbEnd));
+	DPRINTK(2, "PM3HgEnd: 0x%08x\n", PM3_READ_REG(PM3HgEnd));
+	DPRINTK(2, "PM3HsEnd: 0x%08x\n", PM3_READ_REG(PM3HsEnd));
+	DPRINTK(2, "PM3HsStart: 0x%08x\n", PM3_READ_REG(PM3HsStart));
+	DPRINTK(2, "PM3MemBypassWriteMask: 0x%08x\n",
+		PM3_READ_REG(PM3MemBypassWriteMask));
+	DPRINTK(2, "PM3RD_IndexControl: 0x%08x\n",
+		PM3_READ_REG(PM3RD_IndexControl));
+	DPRINTK(2, "PM3ScreenBase: 0x%08x\n", PM3_READ_REG(PM3ScreenBase));
+	DPRINTK(2, "PM3ScreenStride: 0x%08x\n",
+		PM3_READ_REG(PM3ScreenStride));
+	DPRINTK(2, "PM3VClkCtl: 0x%08x\n", PM3_READ_REG(PM3VClkCtl));
+	DPRINTK(2, "PM3VTotal: 0x%08x\n", PM3_READ_REG(PM3VTotal));
+	DPRINTK(2, "PM3VbEnd: 0x%08x\n", PM3_READ_REG(PM3VbEnd));
+	DPRINTK(2, "PM3VideoControl: 0x%08x\n",
+		PM3_READ_REG(PM3VideoControl));
+	DPRINTK(2, "PM3VsEnd: 0x%08x\n", PM3_READ_REG(PM3VsEnd));
+	DPRINTK(2, "PM3VsStart: 0x%08x\n", PM3_READ_REG(PM3VsStart));
+
+	DPRINTK(2, "PM3RD_ColorFormat: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_ColorFormat));
+	DPRINTK(2, "PM3RD_DACControl: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_DACControl));
+	DPRINTK(2, "PM3RD_DClk0FeedbackScale: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale));
+	DPRINTK(2, "PM3RD_DClk0PostScale: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_DClk0PostScale));
+	DPRINTK(2, "PM3RD_DClk0PreScale: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_DClk0PreScale));
+	DPRINTK(2, "[not set] PM3RD_IndexControl: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_IndexControl));
+	DPRINTK(2, "PM3RD_MiscControl: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_MiscControl));
+	DPRINTK(2, "PM3RD_PixelSize: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_PixelSize));
+	DPRINTK(2, "PM3RD_SyncControl: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_SyncControl));
+}
+
+#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) */
+static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info)
+{
+	u16 subvendor, subdevice;
+
+	if ((!pci_read_config_word
+	     (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
+	    &&
+	    (!pci_read_config_word
+	     (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
+		/* well, nothing... */
+	} else {
+		subvendor = subdevice = (u16)-1;
+	}
+
+	printk(KERN_INFO "pm3fb: memory timings for board #%ld (subvendor: 0x%hx, subdevice: 0x%hx)\n", l_fb_info->board_num, subvendor, subdevice);
+	printk(KERN_INFO " PM3LocalMemCaps: 0x%08x\n",
+	       PM3_READ_REG(PM3LocalMemCaps));
+	printk(KERN_INFO " PM3LocalMemTimings: 0x%08x\n",
+	       PM3_READ_REG(PM3LocalMemTimings));
+	printk(KERN_INFO " PM3LocalMemControl: 0x%08x\n",
+	       PM3_READ_REG(PM3LocalMemControl));
+	printk(KERN_INFO " PM3LocalMemRefresh: 0x%08x\n",
+	       PM3_READ_REG(PM3LocalMemRefresh));
+	printk(KERN_INFO " PM3LocalMemPowerDown: 0x%08x\n",
+	       PM3_READ_REG(PM3LocalMemPowerDown));
+}
+
+/* write the mode to registers */
+static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
+{
+	char tempsync = 0x00, tempmisc = 0x00;
+	DTRACE;
+
+	PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff);
+	PM3_SLOW_WRITE_REG(PM3Aperture0, 0x00000000);
+	PM3_SLOW_WRITE_REG(PM3Aperture1, 0x00000000);
+	PM3_SLOW_WRITE_REG(PM3FIFODis, 0x00000007);
+
+	PM3_SLOW_WRITE_REG(PM3HTotal,
+			   pm3fb_Shiftbpp(l_fb_info,
+					  l_fb_info->current_par->depth,
+					  l_fb_info->current_par->htotal -
+					  1));
+	PM3_SLOW_WRITE_REG(PM3HsEnd,
+			   pm3fb_Shiftbpp(l_fb_info,
+					  l_fb_info->current_par->depth,
+					  l_fb_info->current_par->hsend));
+	PM3_SLOW_WRITE_REG(PM3HsStart,
+			   pm3fb_Shiftbpp(l_fb_info,
+					  l_fb_info->current_par->depth,
+					  l_fb_info->current_par->
+					  hsstart));
+	PM3_SLOW_WRITE_REG(PM3HbEnd,
+			   pm3fb_Shiftbpp(l_fb_info,
+					  l_fb_info->current_par->depth,
+					  l_fb_info->current_par->hbend));
+	PM3_SLOW_WRITE_REG(PM3HgEnd,
+			   pm3fb_Shiftbpp(l_fb_info,
+					  l_fb_info->current_par->depth,
+					  l_fb_info->current_par->hbend));
+	PM3_SLOW_WRITE_REG(PM3ScreenStride,
+			   pm3fb_Shiftbpp(l_fb_info,
+					  l_fb_info->current_par->depth,
+					  l_fb_info->current_par->stride));
+	PM3_SLOW_WRITE_REG(PM3VTotal, l_fb_info->current_par->vtotal - 1);
+	PM3_SLOW_WRITE_REG(PM3VsEnd, l_fb_info->current_par->vsend - 1);
+	PM3_SLOW_WRITE_REG(PM3VsStart,
+			   l_fb_info->current_par->vsstart - 1);
+	PM3_SLOW_WRITE_REG(PM3VbEnd, l_fb_info->current_par->vbend);
+
+	switch (l_fb_info->current_par->depth) {
+	case 8:
+		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+				   PM3ByApertureMode_PIXELSIZE_8BIT);
+		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+				   PM3ByApertureMode_PIXELSIZE_8BIT);
+		break;
+
+	case 12:
+	case 15:
+	case 16:
+#ifndef __BIG_ENDIAN
+		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+				   PM3ByApertureMode_PIXELSIZE_16BIT);
+		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+				   PM3ByApertureMode_PIXELSIZE_16BIT);
+#else
+		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+				   PM3ByApertureMode_PIXELSIZE_16BIT |
+				   PM3ByApertureMode_BYTESWAP_BADC);
+		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+				   PM3ByApertureMode_PIXELSIZE_16BIT |
+				   PM3ByApertureMode_BYTESWAP_BADC);
+#endif /* ! __BIG_ENDIAN */
+		break;
+
+	case 32:
+#ifndef __BIG_ENDIAN
+		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+				   PM3ByApertureMode_PIXELSIZE_32BIT);
+		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+				   PM3ByApertureMode_PIXELSIZE_32BIT);
+#else
+		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+				   PM3ByApertureMode_PIXELSIZE_32BIT |
+				   PM3ByApertureMode_BYTESWAP_DCBA);
+		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+				   PM3ByApertureMode_PIXELSIZE_32BIT |
+				   PM3ByApertureMode_BYTESWAP_DCBA);
+#endif /* ! __BIG_ENDIAN */
+		break;
+
+	default:
+		DPRINTK(1, "Unsupported depth %d\n",
+			l_fb_info->current_par->depth);
+		break;
+	}
+
+	/*
+	 * Oxygen VX1 - it appears that setting PM3VideoControl and
+	 * then PM3RD_SyncControl to the same SYNC settings undoes
+	 * any net change - they seem to xor together.  Only set the
+	 * sync options in PM3RD_SyncControl.  --rmk
+	 */
+	{
+		unsigned int video = l_fb_info->current_par->video;
+
+		video &= ~(PM3VideoControl_HSYNC_MASK |
+			   PM3VideoControl_VSYNC_MASK);
+		video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
+			 PM3VideoControl_VSYNC_ACTIVE_HIGH;
+		PM3_SLOW_WRITE_REG(PM3VideoControl, video);
+	}
+	PM3_SLOW_WRITE_REG(PM3VClkCtl,
+			   (PM3_READ_REG(PM3VClkCtl) & 0xFFFFFFFC));
+	PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
+	PM3_SLOW_WRITE_REG(PM3ChipConfig,
+			   (PM3_READ_REG(PM3ChipConfig) & 0xFFFFFFFD));
+
+	{
+		unsigned char m;	/* ClkPreScale */
+		unsigned char n;	/* ClkFeedBackScale */
+		unsigned char p;	/* ClkPostScale */
+		(void)pm3fb_CalculateClock(l_fb_info, l_fb_info->current_par->pixclock, PM3_REF_CLOCK, &m, &n, &p);
+
+		DPRINTK(2,
+			"Pixclock: %d, Pre: %d, Feedback: %d, Post: %d\n",
+			l_fb_info->current_par->pixclock, (int) m, (int) n,
+			(int) p);
+
+		PM3_WRITE_DAC_REG(PM3RD_DClk0PreScale, m);
+		PM3_WRITE_DAC_REG(PM3RD_DClk0FeedbackScale, n);
+		PM3_WRITE_DAC_REG(PM3RD_DClk0PostScale, p);
+	}
+	/*
+	   PM3_WRITE_DAC_REG(PM3RD_IndexControl, 0x00);
+	 */
+	/*
+	   PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00);
+	 */
+	if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) ==
+	    PM3VideoControl_HSYNC_ACTIVE_HIGH)
+		tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
+	if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) ==
+	    PM3VideoControl_VSYNC_ACTIVE_HIGH)
+		tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
+	
+	PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync);
+	DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync);
+	
+	if (flatpanel[l_fb_info->board_num])
+	{
+		PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE);
+		PM3_WAIT(2);
+		PM3_WRITE_REG(PM3VSConfiguration, 0x06);
+		PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */
+		tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE;
+	}
+	else
+		PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00);
+
+	switch (l_fb_info->current_par->depth) {
+	case 8:
+		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+				  PM3RD_PixelSize_8_BIT_PIXELS);
+		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+				  PM3RD_ColorFormat_CI8_COLOR |
+				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
+		tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
+		break;
+	case 12:
+		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+				  PM3RD_PixelSize_16_BIT_PIXELS);
+		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+				  PM3RD_ColorFormat_4444_COLOR |
+				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
+				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
+		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
+			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
+		break;		
+	case 15:
+		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+				  PM3RD_PixelSize_16_BIT_PIXELS);
+		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+				  PM3RD_ColorFormat_5551_FRONT_COLOR |
+				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
+				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
+		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
+			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
+		break;		
+	case 16:
+		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+				  PM3RD_PixelSize_16_BIT_PIXELS);
+		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+				  PM3RD_ColorFormat_565_FRONT_COLOR |
+				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
+				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
+		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
+			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
+		break;
+	case 32:
+		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+				  PM3RD_PixelSize_32_BIT_PIXELS);
+		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+				  PM3RD_ColorFormat_8888_COLOR |
+				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
+		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
+			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
+		break;
+	}
+	PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc);
+	
+	PM3_SHOW_CUR_MODE;
+}
+
+static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
+			    struct pm3fb_par *curpar)
+{
+	unsigned long pixsize1, pixsize2, clockused;
+	unsigned long pre, feedback, post;
+
+	DTRACE;
+
+	clockused = PM3_READ_REG(PM3VClkCtl);
+
+	switch (clockused) {
+	case 3:
+		pre = PM3_READ_DAC_REG(PM3RD_DClk3PreScale);
+		feedback = PM3_READ_DAC_REG(PM3RD_DClk3FeedbackScale);
+		post = PM3_READ_DAC_REG(PM3RD_DClk3PostScale);
+
+		DPRINTK(2,
+			"DClk3 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
+			pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
+								feedback,
+								post));
+		break;
+	case 2:
+		pre = PM3_READ_DAC_REG(PM3RD_DClk2PreScale);
+		feedback = PM3_READ_DAC_REG(PM3RD_DClk2FeedbackScale);
+		post = PM3_READ_DAC_REG(PM3RD_DClk2PostScale);
+
+		DPRINTK(2,
+			"DClk2 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
+			pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
+								feedback,
+								post));
+		break;
+	case 1:
+		pre = PM3_READ_DAC_REG(PM3RD_DClk1PreScale);
+		feedback = PM3_READ_DAC_REG(PM3RD_DClk1FeedbackScale);
+		post = PM3_READ_DAC_REG(PM3RD_DClk1PostScale);
+
+		DPRINTK(2,
+			"DClk1 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
+			pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
+								feedback,
+								post));
+		break;
+	case 0:
+		pre = PM3_READ_DAC_REG(PM3RD_DClk0PreScale);
+		feedback = PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale);
+		post = PM3_READ_DAC_REG(PM3RD_DClk0PostScale);
+
+		DPRINTK(2,
+			"DClk0 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
+			pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
+								feedback,
+								post));
+		break;
+	default:
+		pre = feedback = post = 0;
+		DPRINTK(1, "Unknowk D clock used : %ld\n", clockused);
+		break;
+	}
+
+	curpar->pixclock = PM3_SCALE_TO_CLOCK(pre, feedback, post);
+
+	pixsize1 =
+	    PM3ByApertureMode_PIXELSIZE_MASK &
+	    (PM3_READ_REG(PM3ByAperture1Mode));
+	pixsize2 =
+	    PM3ByApertureMode_PIXELSIZE_MASK &
+	    (PM3_READ_REG(PM3ByAperture2Mode));
+
+	DASSERT((pixsize1 == pixsize2),
+		"pixsize the same in both aperture\n");
+
+	if (pixsize1 & PM3ByApertureMode_PIXELSIZE_32BIT)
+		curpar->depth = 32;
+	else if (pixsize1 & PM3ByApertureMode_PIXELSIZE_16BIT)
+	{
+		curpar->depth = 16;
+	}
+	else
+		curpar->depth = 8;
+
+	/* not sure if I need to add one on the next ; it give better result with */
+	curpar->htotal =
+	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
+			     1 + PM3_READ_REG(PM3HTotal));
+	curpar->hsend =
+	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
+			     PM3_READ_REG(PM3HsEnd));
+	curpar->hsstart =
+	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
+			     PM3_READ_REG(PM3HsStart));
+	curpar->hbend =
+	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
+			     PM3_READ_REG(PM3HbEnd));
+
+	curpar->stride =
+	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
+			     PM3_READ_REG(PM3ScreenStride));
+
+	curpar->vtotal = 1 + PM3_READ_REG(PM3VTotal);
+	curpar->vsend = 1 + PM3_READ_REG(PM3VsEnd);
+	curpar->vsstart = 1 + PM3_READ_REG(PM3VsStart);
+	curpar->vbend = PM3_READ_REG(PM3VbEnd);
+
+	curpar->video = PM3_READ_REG(PM3VideoControl);
+
+	curpar->base = PM3_READ_REG(PM3ScreenBase);
+	curpar->width = curpar->htotal - curpar->hbend; /* make virtual == displayed resolution */
+	curpar->height = curpar->vtotal - curpar->vbend;
+
+	DPRINTK(2, "Found : %d * %d, %d Khz, stride is %08x\n",
+		curpar->width, curpar->height, curpar->pixclock,
+		curpar->stride);
+}
+
+static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info)
+{
+	unsigned long memsize = 0, tempBypass, i, temp1, temp2;
+	u16 subvendor, subdevice;
+	pm3fb_timing_result ptr;
+
+	DTRACE;
+
+	l_fb_info->fb_size = 64 * 1024 * 1024;	/* pm3 aperture always 64 MB */
+	pm3fb_mapIO(l_fb_info);	/* temporary map IO */
+
+	DASSERT((l_fb_info->vIOBase != NULL),
+		"IO successfully mapped before mem detect\n");
+	DASSERT((l_fb_info->v_fb != NULL),
+		"FB successfully mapped before mem detect\n");
+
+	/* card-specific stuff, *before* accessing *any* FB memory */
+	if ((!pci_read_config_word
+	     (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
+	    &&
+	    (!pci_read_config_word
+	     (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
+		i = 0; l_fb_info->board_type = 0;
+		while ((cardbase[i].cardname[0]) && !(l_fb_info->board_type)) {
+			if ((cardbase[i].subvendor == subvendor) &&
+			    (cardbase[i].subdevice == subdevice) &&
+			    (cardbase[i].func == PCI_FUNC(l_fb_info->dev->devfn))) {
+				DPRINTK(2, "Card #%ld is an %s\n",
+					l_fb_info->board_num,
+					cardbase[i].cardname);
+				if (cardbase[i].specific_setup)
+					cardbase[i].specific_setup(l_fb_info);
+				l_fb_info->board_type = i;
+			}
+			i++;
+		}
+		if (!l_fb_info->board_type) {
+			DPRINTK(1, "Card #%ld is an unknown 0x%04x / 0x%04x\n",
+				l_fb_info->board_num, subvendor, subdevice);
+		}
+	} else {
+		printk(KERN_ERR "pm3fb: Error: pci_read_config_word failed, board #%ld\n",
+		       l_fb_info->board_num);
+	}
+
+	if (printtimings)
+		pm3fb_show_cur_timing(l_fb_info);
+	
+	/* card-specific setup is done, we preserve the final
+           memory timing for future reference */
+	if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */
+		return(0);
+	}
+	
+	tempBypass = PM3_READ_REG(PM3MemBypassWriteMask);
+
+	DPRINTK(2, "PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
+
+	PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xFFFFFFFF);
+
+	/* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
+	for (i = 0; i < 32; i++) {
+#ifdef KERNEL_2_2
+#ifdef MUST_BYTESWAP
+		writel(__swab32(i * 0x00345678),
+		       (l_fb_info->v_fb + (i * 1048576)));
+#else
+		writel(i * 0x00345678, (l_fb_info->v_fb + (i * 1048576)));
+#endif
+		mb();
+#ifdef MUST_BYTESWAP
+		temp1 = __swab32(readl((l_fb_info->v_fb + (i * 1048576))));
+#else
+		temp1 = readl((l_fb_info->v_fb + (i * 1048576)));
+#endif
+#endif	/* KERNEL_2_2 */
+#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
+		fb_writel(i * 0x00345678,
+			  (l_fb_info->v_fb + (i * 1048576)));
+		mb();
+		temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576)));
+#endif /* KERNEL_2_4 or KERNEL_2_5 */
+		/* Let's check for wrapover, write will fail at 16MB boundary */
+		if (temp1 == (i * 0x00345678))
+			memsize = i;
+		else
+			break;
+	}
+
+	DPRINTK(2, "First detect pass already got %ld MB\n", memsize + 1);
+
+	if (memsize == i) {
+		for (i = 0; i < 32; i++) {
+			/* Clear first 32MB ; 0 is 0, no need to byteswap */
+			writel(0x0000000,
+			       (l_fb_info->v_fb + (i * 1048576)));
+			mb();
+		}
+
+		for (i = 32; i < 64; i++) {
+#ifdef KERNEL_2_2
+#ifdef MUST_BYTESWAP
+			writel(__swab32(i * 0x00345678),
+			       (l_fb_info->v_fb + (i * 1048576)));
+#else
+			writel(i * 0x00345678,
+			       (l_fb_info->v_fb + (i * 1048576)));
+#endif
+			mb();
+#ifdef MUST_BYTESWAP
+			temp1 =
+			    __swab32(readl
+				     ((l_fb_info->v_fb + (i * 1048576))));
+			temp2 =
+			    __swab32(readl
+				     ((l_fb_info->v_fb +
+				       ((i - 32) * 1048576))));
+#else
+			temp1 = readl((l_fb_info->v_fb + (i * 1048576)));
+			temp2 =
+			    readl((l_fb_info->v_fb +
+				   ((i - 32) * 1048576)));
+#endif
+#endif /* KERNEL_2_2 */
+#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
+			fb_writel(i * 0x00345678,
+				  (l_fb_info->v_fb + (i * 1048576)));
+			mb();
+			temp1 =
+			    fb_readl((l_fb_info->v_fb + (i * 1048576)));
+			temp2 =
+			    fb_readl((l_fb_info->v_fb +
+				      ((i - 32) * 1048576)));
+#endif /* KERNEL_2_4 or KERNEL_2_5 */
+			if ((temp1 == (i * 0x00345678)) && (temp2 == 0))	/* different value, different RAM... */
+				memsize = i;
+			else
+				break;
+		}
+	}
+
+	DPRINTK(2, "Second detect pass got %ld MB\n", memsize + 1);
+
+	PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, tempBypass);
+
+	pm3fb_unmapIO(l_fb_info);
+	memsize = 1048576 * (memsize + 1);
+
+	DPRINTK(2, "Returning 0x%08lx bytes\n", memsize);
+
+	if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize))
+	{
+		printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]);
+		memsize = 1048576 * forcesize[l_fb_info->board_num];
+	}
+	
+	l_fb_info->fb_size = memsize;
+	
+	if (ptr == pm3fb_timing_retry)
+	{
+		printk(KERN_WARNING "pm3fb: retrying memory timings check");
+		if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem)
+			return(0);
+	}
+	
+	return (memsize);
+}
+
+static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc)
+{
+	int i;
+
+	DTRACE;
+
+	for (i = 0; i < (l_fb_info->fb_size / sizeof(u32)) ; i++) /* clear entire FB memory to black */
+	{
+#ifdef KERNEL_2_2
+#ifdef MUST_BYTESWAP
+		writel(__swab32(cc), (l_fb_info->v_fb + (i * sizeof(u32))));
+#else
+		writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
+#endif
+#endif
+#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
+		fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
+#endif
+	}
+}
+
+static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b)
+{
+	int i;
+
+	DTRACE;
+
+	for (i = 0; i < 256 ; i++) /* fill color map with white */
+		pm3fb_set_color(l_fb_info, i, r, g, b);
+
+}
+
+/* common initialisation */
+static void pm3fb_common_init(struct pm3fb_info *l_fb_info)
+{
+	DTRACE;
+
+	DPRINTK(2, "Initializing board #%ld @ %lx\n", l_fb_info->board_num,
+		(unsigned long) l_fb_info);
+
+	strcpy(l_fb_info->gen.info.modename, permedia3_name);
+	disp[l_fb_info->board_num].scrollmode = 0;	/* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */
+	l_fb_info->gen.parsize = sizeof(struct pm3fb_par);
+	l_fb_info->gen.info.changevar = NULL;
+	l_fb_info->gen.info.node = B_FREE;
+	l_fb_info->gen.info.fbops = &pm3fb_ops;
+	l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]);
+	if (fontn[l_fb_info->board_num][0])
+		strcpy(l_fb_info->gen.info.fontname,
+		       fontn[l_fb_info->board_num]);
+	l_fb_info->gen.info.switch_con = &fbgen_switch;
+	l_fb_info->gen.info.updatevar = &fbgen_update_var;	/* */
+	l_fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT;
+
+	pm3fb_mapIO(l_fb_info);
+
+	pm3fb_clear_memory(l_fb_info, 0);
+	pm3fb_clear_colormap(l_fb_info, 0, 0, 0);
+
+	(void) fbgen_get_var(&(disp[l_fb_info->board_num]).var, -1,
+			     &l_fb_info->gen.info);
+
+	if (depth[l_fb_info->board_num]) /* override mode-defined depth */
+	{
+		pm3fb_encode_depth(&(disp[l_fb_info->board_num]).var, depth[l_fb_info->board_num]);
+		(disp[l_fb_info->board_num]).var.bits_per_pixel = depth2bpp(depth[l_fb_info->board_num]);
+	}
+
+	(void) fbgen_do_set_var(&(disp[l_fb_info->board_num]).var, 1,
+				&l_fb_info->gen);
+
+	fbgen_set_disp(-1, &l_fb_info->gen);
+
+	do_install_cmap(0, &l_fb_info->gen.info);
+
+	if (register_framebuffer(&l_fb_info->gen.info) < 0) {
+		DPRINTK(1, "Couldn't register framebuffer\n");
+		return;
+	}
+
+	PM3_WRITE_DAC_REG(PM3RD_CursorMode,
+			  PM3RD_CursorMode_CURSOR_DISABLE);
+	
+	PM3_SHOW_CUR_MODE;
+	
+	pm3fb_write_mode(l_fb_info);
+	
+	printk("fb%d: %s, using %uK of video memory (%s)\n",
+	       GET_FB_IDX(l_fb_info->gen.info.node),
+	       permedia3_name, (u32) (l_fb_info->fb_size >> 10),
+	       cardbase[l_fb_info->board_type].cardname);
+}
+
+/* **************************************************** */
+/* ***** accelerated permedia3-specific functions ***** */
+/* **************************************************** */
+#ifdef PM3FB_USE_ACCEL
+static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info)
+{
+	DTRACE;
+
+	PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
+	PM3_SLOW_WRITE_REG(PM3Sync, 0);
+	mb();
+	do {
+		while ((PM3_READ_REG(PM3OutFIFOWords)) == 0);
+		rmb();
+	} while ((PM3_READ_REG(PM3OutputFifo)) != PM3Sync_Tag);
+}
+
+static void pm3fb_init_engine(struct pm3fb_info *l_fb_info)
+{
+	PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
+	PM3_SLOW_WRITE_REG(PM3StatisticMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3DeltaMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3RasterizerMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3ScissorMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3LineStippleMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3AreaStippleMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3GIDMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3DepthMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3StencilMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3StencilData, 0x0);
+	PM3_SLOW_WRITE_REG(PM3ColorDDAMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureCoordMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureIndexMode0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureIndexMode1, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureReadMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3LUTMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureFilterMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureCompositeMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureApplicationMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode1, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode1, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FogMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3ChromaTestMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3AlphaTestMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3AntialiasMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3YUVMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3AlphaBlendColorMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3AlphaBlendAlphaMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3DitherMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3LogicalOpMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3RouterMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3Window, 0x0);
+
+	PM3_SLOW_WRITE_REG(PM3Config2D, 0x0);
+
+	PM3_SLOW_WRITE_REG(PM3SpanColorMask, 0xffffffff);
+
+	PM3_SLOW_WRITE_REG(PM3XBias, 0x0);
+	PM3_SLOW_WRITE_REG(PM3YBias, 0x0);
+	PM3_SLOW_WRITE_REG(PM3DeltaControl, 0x0);
+
+	PM3_SLOW_WRITE_REG(PM3BitMaskPattern, 0xffffffff);
+
+	PM3_SLOW_WRITE_REG(PM3FBDestReadEnables,
+			   PM3FBDestReadEnables_E(0xff) |
+			   PM3FBDestReadEnables_R(0xff) |
+			   PM3FBDestReadEnables_ReferenceAlpha(0xff));
+	PM3_SLOW_WRITE_REG(PM3FBDestReadBufferAddr0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FBDestReadBufferOffset0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FBDestReadBufferWidth0,
+			   PM3FBDestReadBufferWidth_Width(l_fb_info->
+							  current_par->
+							  width));
+
+	PM3_SLOW_WRITE_REG(PM3FBDestReadMode,
+			   PM3FBDestReadMode_ReadEnable |
+			   PM3FBDestReadMode_Enable0);
+	PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferAddr, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferOffset, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferWidth,
+			   PM3FBSourceReadBufferWidth_Width(l_fb_info->
+							    current_par->
+							    width));
+	PM3_SLOW_WRITE_REG(PM3FBSourceReadMode,
+			   PM3FBSourceReadMode_Blocking |
+			   PM3FBSourceReadMode_ReadEnable);
+
+	{
+		unsigned long rm = 1;
+		switch (l_fb_info->current_par->depth) {
+		case 8:
+			PM3_SLOW_WRITE_REG(PM3PixelSize,
+					   PM3PixelSize_GLOBAL_8BIT);
+			break;
+		case 12:
+		case 15:
+		case 16:
+			PM3_SLOW_WRITE_REG(PM3PixelSize,
+					   PM3PixelSize_GLOBAL_16BIT);
+			break;
+		case 32:
+			PM3_SLOW_WRITE_REG(PM3PixelSize,
+					   PM3PixelSize_GLOBAL_32BIT);
+			break;
+		default:
+			DPRINTK(1, "Unsupported depth %d\n",
+				l_fb_info->current_par->depth);
+			break;
+		}
+		PM3_SLOW_WRITE_REG(PM3RasterizerMode, rm);
+	}
+
+	PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff);
+	PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff);
+	PM3_SLOW_WRITE_REG(PM3FBWriteMode,
+			   PM3FBWriteMode_WriteEnable |
+			   PM3FBWriteMode_OpaqueSpan |
+			   PM3FBWriteMode_Enable0);
+	PM3_SLOW_WRITE_REG(PM3FBWriteBufferAddr0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FBWriteBufferOffset0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FBWriteBufferWidth0,
+			   PM3FBWriteBufferWidth_Width(l_fb_info->
+						       current_par->
+						       width));
+
+	PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 0x0);
+	{
+		unsigned long sofb = (8UL * l_fb_info->fb_size) /
+			((depth2bpp(l_fb_info->current_par->depth))
+			 * l_fb_info->current_par->width);	/* size in lines of FB */
+		if (sofb > 4095)
+			PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095);
+		else
+			PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb);
+		
+		switch (l_fb_info->current_par->depth) {
+		case 8:
+			PM3_SLOW_WRITE_REG(PM3DitherMode,
+					   (1 << 10) | (2 << 3));
+			break;
+		case 12:
+		case 15:
+		case 16:
+			PM3_SLOW_WRITE_REG(PM3DitherMode,
+					   (1 << 10) | (1 << 3));
+			break;
+		case 32:
+			PM3_SLOW_WRITE_REG(PM3DitherMode,
+					   (1 << 10) | (0 << 3));
+			break;
+		default:
+			DPRINTK(1, "Unsupported depth %d\n",
+				l_fb_info->current_par->depth);
+			break;
+		}
+	}
+
+	PM3_SLOW_WRITE_REG(PM3dXDom, 0x0);
+	PM3_SLOW_WRITE_REG(PM3dXSub, 0x0);
+	PM3_SLOW_WRITE_REG(PM3dY, (1 << 16));
+	PM3_SLOW_WRITE_REG(PM3StartXDom, 0x0);
+	PM3_SLOW_WRITE_REG(PM3StartXSub, 0x0);
+	PM3_SLOW_WRITE_REG(PM3StartY, 0x0);
+	PM3_SLOW_WRITE_REG(PM3Count, 0x0);
+	
+/* Disable LocalBuffer. better safe than sorry */
+	PM3_SLOW_WRITE_REG(PM3LBDestReadMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3LBDestReadEnables, 0x0);
+	PM3_SLOW_WRITE_REG(PM3LBSourceReadMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3LBWriteMode, 0x0);
+	
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+#ifdef FBCON_HAS_CFB32
+static void pm3fb_cfb32_clear(struct vc_data *conp,
+			      struct display *p,
+			      int sy, int sx, int height, int width)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	u32 c;
+
+	DTRACE;
+
+	sx = sx * fontwidth(p);
+	width = width * fontwidth(p);
+	sy = sy * fontheight(p);
+	height = height * fontheight(p);
+	c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
+
+	/* block fills in 32bpp are hard, but in low res (width <= 1600 :-)
+	   we can use 16bpp operations, but not if NoWriteMask is on (SDRAM)  */
+	if ((l_fb_info->current_par->width > 1600) ||
+	    (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) {
+		PM3_WAIT(4);
+
+		PM3_WRITE_REG(PM3Config2D,
+					  PM3Config2D_UseConstantSource |
+					  PM3Config2D_ForegroundROPEnable |
+					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+					  PM3Config2D_FBWriteEnable);
+
+		PM3_WRITE_REG(PM3ForegroundColor, c);
+
+		PM3_WRITE_REG(PM3RectanglePosition,
+			      (PM3RectanglePosition_XOffset(sx)) |
+			      (PM3RectanglePosition_YOffset(sy)));
+
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      PM3Render2D_SpanOperation |
+			      (PM3Render2D_Width(width)) |
+			      (PM3Render2D_Height(height)));
+	} else {
+		PM3_WAIT(8);
+
+		PM3_WRITE_REG(PM3FBBlockColor, c);
+
+		PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_16BIT);
+
+		PM3_WRITE_REG(PM3FBWriteBufferWidth0,
+			      PM3FBWriteBufferWidth_Width(l_fb_info->
+							  current_par->
+							  width << 1));
+
+		PM3_WRITE_REG(PM3Config2D,
+					  PM3Config2D_UseConstantSource |
+					  PM3Config2D_ForegroundROPEnable |
+					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+					  PM3Config2D_FBWriteEnable);
+
+		PM3_WRITE_REG(PM3RectanglePosition,
+			      (PM3RectanglePosition_XOffset(sx << 1)) |
+			      (PM3RectanglePosition_YOffset(sy)));
+
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      (PM3Render2D_Width(width << 1)) |
+			      (PM3Render2D_Height(height)));
+
+		PM3_WRITE_REG(PM3FBWriteBufferWidth0,
+			      PM3FBWriteBufferWidth_Width(l_fb_info->
+							  current_par->
+							  width));
+
+		PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_32BIT);
+	}
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
+				      struct display *p, int bottom_only)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	int sx, sy;
+	u32 c;
+
+	DTRACE;
+
+	sx = conp->vc_cols * fontwidth(p);	/* right margin */
+	sy = conp->vc_rows * fontheight(p);	/* bottom margin */
+	c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
+
+	if (!bottom_only) {	/* right margin top->bottom */
+		PM3_WAIT(4);
+
+		PM3_WRITE_REG(PM3Config2D,
+					  PM3Config2D_UseConstantSource |
+					  PM3Config2D_ForegroundROPEnable |
+					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+					  PM3Config2D_FBWriteEnable);
+
+		PM3_WRITE_REG(PM3ForegroundColor, c);
+
+		PM3_WRITE_REG(PM3RectanglePosition,
+			      (PM3RectanglePosition_XOffset
+			       (p->var.xoffset +
+				sx)) | (PM3RectanglePosition_YOffset(p->
+								     var.
+								     yoffset)));
+
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      PM3Render2D_SpanOperation |
+			      (PM3Render2D_Width(p->var.xres - sx)) |
+			      (PM3Render2D_Height(p->var.yres)));
+	}
+
+	/* bottom margin left -> right */
+	PM3_WAIT(4);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable);
+
+	PM3_WRITE_REG(PM3ForegroundColor, c);
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(p->var.xoffset)) |
+		      (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
+
+	PM3_WRITE_REG(PM3Render2D,
+		      PM3Render2D_XPositive |
+		      PM3Render2D_YPositive |
+		      PM3Render2D_Operation_Normal |
+		      PM3Render2D_SpanOperation |
+		      (PM3Render2D_Width(p->var.xres)) |
+		      (PM3Render2D_Height(p->var.yres - sy)));
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+#endif /* FBCON_HAS_CFB32 */
+#ifdef FBCON_HAS_CFB16
+static void pm3fb_cfb16_clear(struct vc_data *conp,
+			      struct display *p,
+			      int sy, int sx, int height, int width)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	u32 c;
+
+	DTRACE;
+
+	sx = sx * fontwidth(p);
+	width = width * fontwidth(p);
+	sy = sy * fontheight(p);
+	height = height * fontheight(p);
+	c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	c = c | (c << 16);
+
+	PM3_WAIT(4);
+
+	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+		PM3_WRITE_REG(PM3ForegroundColor, c);
+	else
+		PM3_WRITE_REG(PM3FBBlockColor, c);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable);
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(sx)) |
+		      (PM3RectanglePosition_YOffset(sy)));
+	
+	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      PM3Render2D_SpanOperation |
+			      (PM3Render2D_Width(width)) |
+			      (PM3Render2D_Height(height)));
+	else
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      (PM3Render2D_Width(width)) |
+			      (PM3Render2D_Height(height)));
+	
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
+				      struct display *p, int bottom_only)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	int sx, sy;
+	u32 c;
+
+	DTRACE;
+
+	sx = conp->vc_cols * fontwidth(p);	/* right margin */
+	sy = conp->vc_rows * fontheight(p);	/* bottom margin */
+	c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	c = c | (c << 16);
+
+	if (!bottom_only) {	/* right margin top->bottom */
+		PM3_WAIT(4);
+
+		PM3_WRITE_REG(PM3Config2D,
+					  PM3Config2D_UseConstantSource |
+					  PM3Config2D_ForegroundROPEnable |
+					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+					  PM3Config2D_FBWriteEnable);
+		
+		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+			PM3_WRITE_REG(PM3ForegroundColor, c);
+		else
+			PM3_WRITE_REG(PM3FBBlockColor, c);
+		
+		PM3_WRITE_REG(PM3RectanglePosition,
+			      (PM3RectanglePosition_XOffset
+			       (p->var.xoffset +
+				sx)) | (PM3RectanglePosition_YOffset(p->
+								     var.
+								     yoffset)));
+		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+			PM3_WRITE_REG(PM3Render2D,
+				      PM3Render2D_XPositive |
+				      PM3Render2D_YPositive |
+				      PM3Render2D_Operation_Normal |
+				      PM3Render2D_SpanOperation |
+				      (PM3Render2D_Width(p->var.xres - sx)) |
+				      (PM3Render2D_Height(p->var.yres)));
+		else
+			PM3_WRITE_REG(PM3Render2D,
+				      PM3Render2D_XPositive |
+				      PM3Render2D_YPositive |
+				      PM3Render2D_Operation_Normal |
+				      (PM3Render2D_Width(p->var.xres - sx)) |
+				      (PM3Render2D_Height(p->var.yres)));
+	}
+	
+	/* bottom margin left -> right */
+	PM3_WAIT(4);
+	
+	PM3_WRITE_REG(PM3Config2D,
+		      PM3Config2D_UseConstantSource |
+		      PM3Config2D_ForegroundROPEnable |
+		      (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+		      PM3Config2D_FBWriteEnable);
+	
+	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+		PM3_WRITE_REG(PM3ForegroundColor, c);
+	else
+		PM3_WRITE_REG(PM3FBBlockColor, c);
+	
+	
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(p->var.xoffset)) |
+		      (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
+	
+	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      PM3Render2D_SpanOperation |
+			      (PM3Render2D_Width(p->var.xres)) |
+			      (PM3Render2D_Height(p->var.yres - sy)));
+	else
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      (PM3Render2D_Width(p->var.xres)) |
+			      (PM3Render2D_Height(p->var.yres - sy)));
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+#endif /* FBCON_HAS_CFB16 */
+#ifdef FBCON_HAS_CFB8
+static void pm3fb_cfb8_clear(struct vc_data *conp,
+			     struct display *p,
+			     int sy, int sx, int height, int width)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	u32 c;
+
+	DTRACE;
+
+	sx = sx * fontwidth(p);
+	width = width * fontwidth(p);
+	sy = sy * fontheight(p);
+	height = height * fontheight(p);
+
+	c = attr_bgcol_ec(p, conp);
+	c |= c << 8;
+	c |= c << 16;
+
+	PM3_WAIT(4);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable);
+
+	PM3_WRITE_REG(PM3ForegroundColor, c);
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(sx)) |
+		      (PM3RectanglePosition_YOffset(sy)));
+
+	PM3_WRITE_REG(PM3Render2D,
+		      PM3Render2D_XPositive |
+		      PM3Render2D_YPositive |
+		      PM3Render2D_Operation_Normal |
+		      PM3Render2D_SpanOperation |
+		      (PM3Render2D_Width(width)) |
+		      (PM3Render2D_Height(height)));
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
+				     struct display *p, int bottom_only)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	int sx, sy;
+	u32 c;
+
+	DTRACE;
+
+	sx = conp->vc_cols * fontwidth(p);	/* right margin */
+	sy = conp->vc_rows * fontheight(p);	/* bottom margin */
+	c = attr_bgcol_ec(p, conp);
+	c |= c << 8;
+	c |= c << 16;
+
+	if (!bottom_only) {	/* right margin top->bottom */
+		PM3_WAIT(4);
+
+		PM3_WRITE_REG(PM3Config2D,
+					  PM3Config2D_UseConstantSource |
+					  PM3Config2D_ForegroundROPEnable |
+					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+					  PM3Config2D_FBWriteEnable);
+
+		PM3_WRITE_REG(PM3ForegroundColor, c);
+
+		PM3_WRITE_REG(PM3RectanglePosition,
+			      (PM3RectanglePosition_XOffset
+			       (p->var.xoffset +
+				sx)) | (PM3RectanglePosition_YOffset(p->
+								     var.
+								     yoffset)));
+
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      PM3Render2D_SpanOperation |
+			      (PM3Render2D_Width(p->var.xres - sx)) |
+			      (PM3Render2D_Height(p->var.yres)));
+	}
+
+	/* bottom margin left -> right */
+	PM3_WAIT(4);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable);
+
+	PM3_WRITE_REG(PM3ForegroundColor, c);
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(p->var.xoffset)) |
+		      (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
+
+	PM3_WRITE_REG(PM3Render2D,
+		      PM3Render2D_XPositive |
+		      PM3Render2D_YPositive |
+		      PM3Render2D_Operation_Normal |
+		      PM3Render2D_SpanOperation |
+		      (PM3Render2D_Width(p->var.xres)) |
+		      (PM3Render2D_Height(p->var.yres - sy)));
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+#endif /* FBCON_HAS_CFB8 */
+#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
+static void pm3fb_cfbX_bmove(struct display *p,
+			     int sy, int sx,
+			     int dy, int dx, int height, int width)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	int x_align, o_x, o_y;
+
+	DTRACE;
+
+	sx = sx * fontwidth(p);
+	dx = dx * fontwidth(p);
+	width = width * fontwidth(p);
+	sy = sy * fontheight(p);
+	dy = dy * fontheight(p);
+	height = height * fontheight(p);
+
+	o_x = sx - dx;		/*(sx > dx ) ? (sx - dx) : (dx - sx); */
+	o_y = sy - dy;		/*(sy > dy ) ? (sy - dy) : (dy - sy); */
+
+	x_align = (sx & 0x1f);
+
+	PM3_WAIT(6);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UserScissorEnable |
+				  PM3Config2D_ForegroundROPEnable |
+				  PM3Config2D_Blocking |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable);
+
+	PM3_WRITE_REG(PM3ScissorMinXY,
+		      ((dy & 0x0fff) << 16) | (dx & 0x0fff));
+	PM3_WRITE_REG(PM3ScissorMaxXY,
+				  (((dy + height) & 0x0fff) << 16) |
+				  ((dx + width) & 0x0fff));
+
+	PM3_WRITE_REG(PM3FBSourceReadBufferOffset,
+		      PM3FBSourceReadBufferOffset_XOffset(o_x) |
+		      PM3FBSourceReadBufferOffset_YOffset(o_y));
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(dx - x_align)) |
+		      (PM3RectanglePosition_YOffset(dy)));
+
+	PM3_WRITE_REG(PM3Render2D,
+		      ((sx > dx) ? PM3Render2D_XPositive : 0) |
+		      ((sy > dy) ? PM3Render2D_YPositive : 0) |
+		      PM3Render2D_Operation_Normal |
+		      PM3Render2D_SpanOperation |
+		      PM3Render2D_FBSourceReadEnable |
+		      (PM3Render2D_Width(width + x_align)) |
+		      (PM3Render2D_Height(height)));
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
+			    int c, int yy, int xx)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
+	u32 fgx, bgx, ldat;
+	int sx, sy, i;
+
+	DTRACE;
+
+	if (l_fb_info->current_par->depth == 8)
+		fgx = attr_fgcol(p, c);
+	else if (depth2bpp(l_fb_info->current_par->depth) == 16)
+		fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
+	else
+		fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
+
+	PM3_COLOR(fgx);
+
+	if (l_fb_info->current_par->depth == 8)
+		bgx = attr_bgcol(p, c);
+	else if (depth2bpp(l_fb_info->current_par->depth) == 16)
+		bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
+	else
+		bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
+
+	PM3_COLOR(bgx);
+
+	PM3_WAIT(4);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable | PM3Config2D_OpaqueSpan);
+
+	PM3_WRITE_REG(PM3ForegroundColor, fgx);
+	PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
+
+	/* WARNING : adress select X need to specify 8 bits for fontwidth <= 8 */
+	/* and 16 bits for fontwidth <= 16 */
+	/* same in _putcs, same for Y and fontheight */
+	if (fontwidth(p) <= 8)
+		asx = 2;
+	else if (fontwidth(p) <= 16)
+		asx = 3;	/* look OK */
+	if (fontheight(p) <= 8)
+		asy = 2;
+	else if (fontheight(p) <= 16)
+		asy = 3;	/* look OK */
+	else if (fontheight(p) <= 32)
+		asy = 4;	/* look OK */
+
+	sx = xx * fontwidth(p);
+	sy = yy * fontheight(p);
+
+	if (fontwidth(p) <= 8)
+		o_x = (8 - (sx & 0x7)) & 0x7;
+	else if (fontwidth(p) <= 16)
+		o_x = (16 - (sx & 0xF)) & 0xF;
+	if (fontheight(p) <= 8)
+		o_y = (8 - (sy & 0x7)) & 0x7;
+	else if (fontheight(p) <= 16)
+		o_y = (16 - (sy & 0xF)) & 0xF;
+	else if (fontheight(p) <= 32)
+		o_y = (32 - (sy & 0x1F)) & 0x1F;
+
+	PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) |	/* x_offset, y_offset in pattern */
+		      (1 << 18) |	/* BE */
+		      1 | (asx << 1) | (asy << 4) |	/* address select x/y */
+		      (1 << 20));	/* OpaqueSpan */
+
+	if (fontwidth(p) <= 8) {
+		cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+	} else {
+		cdat =
+		    p->fontdata +
+		    ((c & p->charmask) * (fontheight(p) << 1));
+	}
+
+	PM3_WAIT(2 + fontheight(p));
+
+	for (i = 0; i < fontheight(p); i++) {	/* assume fontheight <= 32 */
+		if (fontwidth(p) <= 8) {
+			ldat = *cdat++;
+		} else {	/* assume fontwidth <= 16 ATM */
+
+			ldat = ((*cdat++) << 8);
+			ldat |= *cdat++;
+		}
+		PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
+	}
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(sx)) |
+		      (PM3RectanglePosition_YOffset(sy)));
+
+	PM3_WRITE_REG(PM3Render2D,
+		      PM3Render2D_AreaStippleEnable |
+		      PM3Render2D_XPositive |
+		      PM3Render2D_YPositive |
+		      PM3Render2D_Operation_Normal |
+		      PM3Render2D_SpanOperation |
+		      (PM3Render2D_Width(fontwidth(p))) |
+		      (PM3Render2D_Height(fontheight(p))));
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
+			     const unsigned short *s, int count, int yy,
+			     int xx)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
+	u32 fgx, bgx, ldat;
+	int sx, sy, i, j;
+	u16 sc;
+
+	DTRACE;
+
+	sc = scr_readw(s);
+	if (l_fb_info->current_par->depth == 8)
+		fgx = attr_fgcol(p, sc);
+	else if (depth2bpp(l_fb_info->current_par->depth) == 16)
+		fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, sc)];
+	else
+		fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, sc)];
+	
+	PM3_COLOR(fgx);
+	
+	if (l_fb_info->current_par->depth == 8)
+		bgx = attr_bgcol(p, sc);
+	else if (depth2bpp(l_fb_info->current_par->depth) == 16)
+		bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, sc)];
+	else
+		bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, sc)];
+	
+	PM3_COLOR(bgx);
+
+	PM3_WAIT(4);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable |
+				  PM3Config2D_OpaqueSpan);
+
+	PM3_WRITE_REG(PM3ForegroundColor, fgx);
+	PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
+
+	/* WARNING : adress select X need to specify 8 bits for fontwidth <= 8 */
+	/* and 16 bits for fontwidth <= 16 */
+	/* same in _putc, same for Y and fontheight */
+	if (fontwidth(p) <= 8)
+		asx = 2;
+	else if (fontwidth(p) <= 16)
+		asx = 3;	/* look OK */
+	if (fontheight(p) <= 8)
+		asy = 2;
+	else if (fontheight(p) <= 16)
+		asy = 3;	/* look OK */
+	else if (fontheight(p) <= 32)
+		asy = 4;	/* look OK */
+
+	sy = yy * fontheight(p);
+
+	if (fontheight(p) <= 8)
+		o_y = (8 - (sy & 0x7)) & 0x7;
+	else if (fontheight(p) <= 16)
+		o_y = (16 - (sy & 0xF)) & 0xF;
+	else if (fontheight(p) <= 32)
+		o_y = (32 - (sy & 0x1F)) & 0x1F;
+
+	for (j = 0; j < count; j++) {
+		sc = scr_readw(s + j);
+		if (fontwidth(p) <= 8)
+			cdat = p->fontdata +
+				(sc & p->charmask) * fontheight(p);
+		else
+			cdat = p->fontdata +
+				((sc & p->charmask) * fontheight(p) << 1);
+		
+		sx = (xx + j) * fontwidth(p);
+
+		if (fontwidth(p) <= 8)
+			o_x = (8 - (sx & 0x7)) & 0x7;
+		else if (fontwidth(p) <= 16)
+			o_x = (16 - (sx & 0xF)) & 0xF;
+
+		PM3_WAIT(3 + fontheight(p));
+
+		PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */
+			      (1 << 18) | /* BE */
+			      1 | (asx << 1) | (asy << 4) | /* address select x/y */
+			      (1 << 20)); /* OpaqueSpan */
+
+		for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */
+			if (fontwidth(p) <= 8) {
+				ldat = *cdat++;
+			} else { /* assume fontwidth <= 16 ATM */
+				ldat = ((*cdat++) << 8);
+				ldat |= *cdat++;
+			}
+			PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
+		}
+
+		PM3_WRITE_REG(PM3RectanglePosition,
+			      (PM3RectanglePosition_XOffset(sx)) |
+			      (PM3RectanglePosition_YOffset(sy)));
+
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_AreaStippleEnable |
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      PM3Render2D_SpanOperation |
+			      (PM3Render2D_Width(fontwidth(p))) |
+			      (PM3Render2D_Height(fontheight(p))));
+	}
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+static void pm3fb_cfbX_revc(struct display *p, int xx, int yy)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+
+	xx = xx * fontwidth(p);
+	yy = yy * fontheight(p);
+
+	if (l_fb_info->current_par->depth == 8)
+	{
+		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+			PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F);
+		else
+			PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F);
+	}
+
+	PM3_WAIT(3);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0xa)) |	/* Oxa is GXinvert */
+				  PM3Config2D_FBDestReadEnable |
+				  PM3Config2D_FBWriteEnable);
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(xx)) |
+		      (PM3RectanglePosition_YOffset(yy)));
+
+	PM3_WRITE_REG(PM3Render2D,
+		      PM3Render2D_XPositive |
+		      PM3Render2D_YPositive |
+		      PM3Render2D_Operation_Normal |
+		      PM3Render2D_SpanOperation |
+		      (PM3Render2D_Width(fontwidth(p))) |
+		      (PM3Render2D_Height(fontheight(p))));
+
+	pm3fb_wait_pm3(l_fb_info);
+
+	if (l_fb_info->current_par->depth == 8)
+	{
+		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+			PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF);
+		else
+			PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF);
+	}
+}
+
+#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
+#endif /* PM3FB_USE_ACCEL */
+/* *********************************** */
+/* ***** pre-init board(s) setup ***** */
+/* *********************************** */
+
+static void pm3fb_mode_setup(char *mode, unsigned long board_num)
+{
+	struct pm3fb_info *l_fb_info = &(fb_info[board_num]);
+	struct pm3fb_par *l_fb_par = &(current_par[board_num]);
+	unsigned long i = 0;
+
+	current_par_valid[board_num] = 0;
+
+	if (!strncmp(mode, "current", 7)) {
+		l_fb_info->use_current = 1;	/* default w/ OpenFirmware */
+	} else {
+		while ((mode_base[i].name[0])
+		       && (!current_par_valid[board_num])) {
+			if (!
+			    (strncmp
+			     (mode, mode_base[i].name,
+			      strlen(mode_base[i].name)))) {
+				memcpy(l_fb_par, &(mode_base[i].user_mode),
+				       sizeof(struct pm3fb_par));
+				current_par_valid[board_num] = 1;
+				DPRINTK(2, "Mode set to %s\n",
+					mode_base[i].name);
+			}
+			i++;
+		}
+		DASSERT(current_par_valid[board_num],
+			"Valid mode on command line\n");
+	}
+}
+
+static void pm3fb_pciid_setup(char *pciid, unsigned long board_num)
+{
+	short l_bus = -1, l_slot = -1, l_func = -1;
+	char *next;
+
+	if (pciid) {
+		l_bus = simple_strtoul(pciid, &next, 10);
+		if (next && (next[0] == ':')) {
+			pciid = next + 1;
+			l_slot = simple_strtoul(pciid, &next, 10);
+			if (next && (next[0] == ':')) {
+				pciid = next + 1;
+				l_func =
+				    simple_strtoul(pciid, (char **) NULL,
+						   10);
+			}
+		}
+	} else
+		return;
+
+	if ((l_bus >= 0) && (l_slot >= 0) && (l_func >= 0)) {
+		bus[board_num] = l_bus;
+		slot[board_num] = l_slot;
+		func[board_num] = l_func;
+		DPRINTK(2, "Board #%ld will be PciId: %hd:%hd:%hd\n",
+			board_num, l_bus, l_slot, l_func);
+	} else {
+		DPRINTK(1, "Invalid PciId: %hd:%hd:%hd for board #%ld\n",
+			l_bus, l_slot, l_func, board_num);
+	}
+}
+
+static void pm3fb_font_setup(char *lf, unsigned long board_num)
+{
+	unsigned long lfs = strlen(lf);
+
+	if (lfs > (PM3_FONTNAME_SIZE - 1)) {
+		DPRINTK(1, "Fontname %s too long\n", lf);
+		return;
+	}
+	strncpy(fontn[board_num], lf, lfs);
+	fontn[board_num][lfs] = '\0';
+}
+
+static void pm3fb_bootdepth_setup(char *bds, unsigned long board_num)
+{
+	unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
+
+	if (!(depth_supported(bd))) {
+		printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n",
+		       bds, board_num);
+		return;
+	}
+	depth[board_num] = bd;
+}
+
+static void pm3fb_forcesize_setup(char *bds, unsigned long board_num)
+{
+	unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
+
+	if (bd > 64) {
+		printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n",
+		       bds, board_num);
+		return;
+	}
+	forcesize[board_num] = bd;
+}
+
+static char *pm3fb_boardnum_setup(char *options, unsigned long *bn)
+{
+	char *next;
+
+	if (!(CHAR_IS_NUM(options[0]))) {
+		(*bn) = 0;
+		return (options);
+	}
+
+	(*bn) = simple_strtoul(options, &next, 10);
+
+	if (next && (next[0] == ':') && ((*bn) >= 0)
+	    && ((*bn) <= PM3_MAX_BOARD)) {
+		DPRINTK(2, "Board_num seen as %ld\n", (*bn));
+		return (next + 1);
+	} else {
+		(*bn) = 0;
+		DPRINTK(2, "Board_num default to %ld\n", (*bn));
+		return (options);
+	}
+}
+
+static void pm3fb_real_setup(char *options)
+{
+	char *next;
+	unsigned long i, bn;
+	struct pm3fb_info *l_fb_info;
+
+	DTRACE;
+
+	DPRINTK(2, "Options : %s\n", options);
+
+	for (i = 0; i < PM3_MAX_BOARD; i++) {
+		l_fb_info = &(fb_info[i]);
+		memset(l_fb_info, 0, sizeof(struct pm3fb_info));
+		l_fb_info->gen.fbhw = &pm3fb_switch;
+		l_fb_info->board_num = i;
+		current_par_valid[i] = 0;
+		slot[i] = -1;
+		func[i] = -1;
+		bus[i] = -1;
+		disable[i] = 0;
+		noaccel[i] = 0;
+		fontn[i][0] = '\0';
+		depth[i] = 0;
+		l_fb_info->current_par = &(current_par[i]);
+	}
+
+	/* eat up prefix pm3fb and whatever is used as separator i.e. :,= */
+	if (!strncmp(options, "pm3fb", 5)) {
+		options += 5;
+		while (((*options) == ',') || ((*options) == ':')
+		       || ((*options) == '='))
+			options++;
+	}
+
+	while (options) {
+		bn = 0;
+		if ((next = strchr(options, ','))) {
+			(*next) = '\0';
+			next++;
+		}
+
+		if (!strncmp(options, "mode:", 5)) {
+			options = pm3fb_boardnum_setup(options + 5, &bn);
+			DPRINTK(2, "Setting mode for board #%ld\n", bn);
+			pm3fb_mode_setup(options, bn);
+		} else if (!strncmp(options, "off:", 4)) {
+			options = pm3fb_boardnum_setup(options + 4, &bn);
+			DPRINTK(2, "Disabling board #%ld\n", bn);
+			disable[bn] = 1;
+		} else if (!strncmp(options, "off", 3)) {	/* disable everything */
+			for (i = 0; i < PM3_MAX_BOARD; i++)
+				disable[i] = 1;
+		} else if (!strncmp(options, "disable:", 8)) {
+			options = pm3fb_boardnum_setup(options + 8, &bn);
+			DPRINTK(2, "Disabling board #%ld\n", bn);
+			disable[bn] = 1;
+		} else if (!strncmp(options, "pciid:", 6)) {
+			options = pm3fb_boardnum_setup(options + 6, &bn);
+			DPRINTK(2, "Setting PciID for board #%ld\n", bn);
+			pm3fb_pciid_setup(options, bn);
+		} else if (!strncmp(options, "noaccel:", 8)) {
+			options = pm3fb_boardnum_setup(options + 8, &bn);
+			noaccel[bn] = 1;
+		} else if (!strncmp(options, "font:", 5)) {
+			options = pm3fb_boardnum_setup(options + 5, &bn);
+			pm3fb_font_setup(options, bn);
+		} else if (!strncmp(options, "depth:", 6)) {
+			options = pm3fb_boardnum_setup(options + 6, &bn);
+			pm3fb_bootdepth_setup(options, bn);
+		} else if (!strncmp(options, "printtimings", 12)) {
+			printtimings = 1;
+		} else if (!strncmp(options, "flatpanel:", 10)) {
+			options = pm3fb_boardnum_setup(options + 10, &bn);
+			flatpanel[bn] = 1;
+		} else if (!strncmp(options, "forcesize:", 10)) {
+			options = pm3fb_boardnum_setup(options + 10, &bn);
+			pm3fb_forcesize_setup(options, bn);
+		}
+		options = next;
+	}
+}
+
+/* ********************************************** */
+/* ***** framebuffer API standard functions ***** */
+/* ********************************************** */
+
+static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
+			    const void *par, struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+	struct pm3fb_par *p = (struct pm3fb_par *) par;
+
+	DTRACE;
+
+	strcpy(fix->id, permedia3_name);
+	fix->smem_start = (unsigned long)l_fb_info->p_fb;
+	fix->smem_len = l_fb_info->fb_size;
+	fix->mmio_start = (unsigned long)l_fb_info->pIOBase;
+	fix->mmio_len = PM3_REGS_SIZE;
+#ifdef PM3FB_USE_ACCEL
+	if (!(noaccel[l_fb_info->board_num]))
+		fix->accel = FB_ACCEL_3DLABS_PERMEDIA3;
+	else
+#endif /* PM3FB_USE_ACCEL */
+		fix->accel = FB_ACCEL_NONE;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->visual =
+	    (p->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	if (current_par_valid[l_fb_info->board_num])
+		fix->line_length =
+			l_fb_info->current_par->width *
+			depth2ByPP(l_fb_info->current_par->depth);
+	else
+		fix->line_length = 0;
+	fix->xpanstep = 64 / depth2bpp(p->depth);
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	return (0);
+}
+
+static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
+			    void *par, struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+	struct pm3fb_par *p = (struct pm3fb_par *) par;
+	struct pm3fb_par temp_p;
+	u32 xres;
+
+	DTRACE;
+
+	DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
+	DASSERT((p != NULL), "pm3fb_par* not NULL");
+	DASSERT((l_fb_info != NULL), "pm3fb_info* not NULL");
+
+	memset(&temp_p, 0, sizeof(struct pm3fb_par));
+	temp_p.width = (var->xres_virtual + 7) & ~7;
+	temp_p.height = var->yres_virtual;
+
+	if (!(depth_supported(var->bits_per_pixel))) /* round unsupported up to a multiple of 8 */
+		temp_p.depth = depth2bpp(var->bits_per_pixel);
+	else
+		temp_p.depth = var->bits_per_pixel;
+
+	temp_p.depth = (temp_p.depth > 32) ? 32 : temp_p.depth; /* max 32 */
+	temp_p.depth = (temp_p.depth == 24) ? 32 : temp_p.depth; /* 24 unsupported, round-up to 32 */
+
+	if ((temp_p.depth == 16) && (var->red.length == 5) && (var->green.length == 5) && (var->blue.length == 5))
+		temp_p.depth = 15; /* RGBA 5551 is stored as depth 15 */
+
+	if ((temp_p.depth == 16) && (var->red.length == 4) && (var->green.length == 4) && (var->blue.length == 4))
+		temp_p.depth = 12; /* RGBA 4444  is stored as depth 12 */
+
+
+	DPRINTK(2,
+		"xres: %d, yres: %d, vxres: %d, vyres: %d ; xoffset:%d, yoffset: %d\n",
+		var->xres, var->yres, var->xres_virtual, var->yres_virtual,
+		var->xoffset, var->yoffset);
+
+	xres = (var->xres + 31) & ~31;
+	if (temp_p.width < xres + var->xoffset)
+		temp_p.width = xres + var->xoffset;
+	if (temp_p.height < var->yres + var->yoffset)
+		temp_p.height = var->yres + var->yoffset;
+
+	if (temp_p.width > 2048) {
+		DPRINTK(1, "virtual width not supported: %u\n",
+			temp_p.width);
+		return (-EINVAL);
+	}
+	if (var->yres < 200) {
+		DPRINTK(1, "height not supported: %u\n", (u32) var->yres);
+		return (-EINVAL);
+	}
+	if (temp_p.height < 200 || temp_p.height > 4095) {
+		DPRINTK(1, "virtual height not supported: %u\n",
+			temp_p.height);
+		return (-EINVAL);
+	}
+	if (!(depth_supported(temp_p.depth))) {
+		DPRINTK(1, "depth not supported: %u\n", temp_p.depth);
+		return (-EINVAL);
+	}
+	if ((temp_p.width * temp_p.height * depth2ByPP(temp_p.depth)) >
+	    l_fb_info->fb_size) {
+		DPRINTK(1, "no memory for screen (%ux%ux%u)\n",
+			temp_p.width, temp_p.height, temp_p.depth);
+		return (-EINVAL);
+	}
+
+	if ((!var->pixclock) ||
+	    (!var->right_margin) ||
+	    (!var->hsync_len) ||
+	    (!var->left_margin) ||
+	    (!var->lower_margin) ||
+	    (!var->vsync_len) || (!var->upper_margin)
+	    ) {
+		unsigned long i = 0, done = 0;
+		printk(KERN_WARNING "pm3fb: refusing to use a likely wrong timing\n");
+
+		while ((mode_base[i].user_mode.width) && !done) {
+			if ((mode_base[i].user_mode.width == temp_p.width)
+			    && (mode_base[i].user_mode.height ==
+				temp_p.height)) {
+				printk(KERN_NOTICE "pm3fb: using close match %s\n",
+				       mode_base[i].name);
+				temp_p = mode_base[i].user_mode;
+				done = 1;
+			}
+			i++;
+		}
+		if (!done)
+			return (-EINVAL);
+	} else {
+		temp_p.pixclock = PICOS2KHZ(var->pixclock);
+		if (temp_p.pixclock > PM3_MAX_PIXCLOCK) {
+			DPRINTK(1, "pixclock too high (%uKHz)\n",
+				temp_p.pixclock);
+			return (-EINVAL);
+		}
+
+		temp_p.hsstart = var->right_margin;
+		temp_p.hsend = var->right_margin + var->hsync_len;
+		temp_p.hbend =
+		    var->right_margin + var->hsync_len + var->left_margin;
+		temp_p.htotal = xres + temp_p.hbend;
+
+		temp_p.vsstart = var->lower_margin;
+		temp_p.vsend = var->lower_margin + var->vsync_len;
+		temp_p.vbend =
+		    var->lower_margin + var->vsync_len + var->upper_margin;
+		temp_p.vtotal = var->yres + temp_p.vbend;
+
+		temp_p.stride = temp_p.width;
+
+		DPRINTK(2, "Using %d * %d, %d Khz, stride is %08x\n",
+			temp_p.width, temp_p.height, temp_p.pixclock,
+			temp_p.stride);
+
+		temp_p.base =
+		    pm3fb_Shiftbpp(l_fb_info, temp_p.depth,
+				   (var->yoffset * xres) + var->xoffset);
+
+		temp_p.video = 0;
+
+		if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+			temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
+		else
+			temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
+
+		if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+			temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
+		else
+			temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
+
+		if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+			DPRINTK(1, "Interlaced mode not supported\n\n");
+			return (-EINVAL);
+		}
+
+		if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
+			temp_p.video |= PM3VideoControl_LINE_DOUBLE_ON;
+		else
+			temp_p.video |= PM3VideoControl_LINE_DOUBLE_OFF;
+
+		if (var->activate == FB_ACTIVATE_NOW)
+			temp_p.video |= PM3VideoControl_ENABLE;
+		else {
+			temp_p.video |= PM3VideoControl_DISABLE;
+			DPRINTK(2, "PM3Video disabled\n");
+		}
+
+		switch (temp_p.depth) {
+		case 8:
+			temp_p.video |= PM3VideoControl_PIXELSIZE_8BIT;
+			break;
+		case 12:
+		case 15:
+		case 16:
+			temp_p.video |= PM3VideoControl_PIXELSIZE_16BIT;
+			break;
+		case 32:
+			temp_p.video |= PM3VideoControl_PIXELSIZE_32BIT;
+			break;
+		default:
+			DPRINTK(1, "Unsupported depth\n");
+			break;
+		}
+	}
+	(*p) = temp_p;
+
+#ifdef PM3FB_USE_ACCEL
+	if (var->accel_flags & FB_ACCELF_TEXT)
+		noaccel[l_fb_info->board_num] = 0;
+	else
+		noaccel[l_fb_info->board_num] = 1;
+#endif /* PM3FB_USE_ACCEL */
+
+	return (0);
+}
+
+static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d)
+{
+	switch (d) {
+	case 8:
+		var->red.length = var->green.length = var->blue.length = 8;
+		var->red.offset = var->green.offset = var->blue.offset = 0;
+		var->transp.offset = var->transp.length = 0;
+		break;
+
+	case 12:
+		var->red.offset = 8;
+		var->red.length = 4;
+		var->green.offset = 4;
+		var->green.length = 4;
+		var->blue.offset = 0;
+		var->blue.length = 4;
+		var->transp.offset = 12;
+		var->transp.length = 4;
+		break;
+
+	case 15:
+		var->red.offset = 10;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 5;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 15;
+		var->transp.length = 1;
+		break;
+
+	case 16:
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = var->transp.length = 0;
+		break;
+
+	case 32:
+		var->transp.offset = 24;
+		var->red.offset = 16;
+		var->green.offset = 8;
+		var->blue.offset = 0;
+		var->red.length = var->green.length =
+			var->blue.length = var->transp.length = 8;
+		break;
+
+	default:
+		DPRINTK(1, "Unsupported depth %ld\n", d);
+		break;
+	}
+}
+
+static int pm3fb_encode_var(struct fb_var_screeninfo *var,
+			    const void *par, struct fb_info_gen *info)
+{
+	struct pm3fb_par *p = (struct pm3fb_par *) par;
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+
+	u32 base;
+
+	DTRACE;
+
+	DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
+	DASSERT((p != NULL), "pm3fb_par* not NULL");
+	DASSERT((info != NULL), "fb_info_gen* not NULL");
+
+	memset(var, 0, sizeof(struct fb_var_screeninfo));
+
+#ifdef PM3FB_USE_ACCEL
+	if (!(noaccel[l_fb_info->board_num]))
+		var->accel_flags |= FB_ACCELF_TEXT;
+#endif /* PM3FB_USE_ACCEL */
+
+	var->xres_virtual = p->width;
+	var->yres_virtual = p->height;
+	var->xres = p->htotal - p->hbend;
+	var->yres = p->vtotal - p->vbend;
+
+	DPRINTK(2, "xres = %d, yres : %d\n", var->xres, var->yres);
+
+	var->right_margin = p->hsstart;
+	var->hsync_len = p->hsend - p->hsstart;
+	var->left_margin = p->hbend - p->hsend;
+	var->lower_margin = p->vsstart;
+	var->vsync_len = p->vsend - p->vsstart;
+	var->upper_margin = p->vbend - p->vsend;
+	var->bits_per_pixel = depth2bpp(p->depth);
+	
+	pm3fb_encode_depth(var, p->depth);
+
+	base = pm3fb_Unshiftbpp(l_fb_info, p->depth, p->base);
+
+	var->xoffset = base % var->xres;
+	var->yoffset = base / var->xres;
+
+	var->height = var->width = -1;
+
+	var->pixclock = KHZ2PICOS(p->pixclock);
+
+	if ((p->video & PM3VideoControl_HSYNC_MASK) ==
+	    PM3VideoControl_HSYNC_ACTIVE_HIGH)
+		var->sync |= FB_SYNC_HOR_HIGH_ACT;
+	if ((p->video & PM3VideoControl_VSYNC_MASK) ==
+	    PM3VideoControl_VSYNC_ACTIVE_HIGH)
+		var->sync |= FB_SYNC_VERT_HIGH_ACT;
+	if (p->video & PM3VideoControl_LINE_DOUBLE_ON)
+		var->vmode = FB_VMODE_DOUBLE;
+
+	return (0);
+}
+
+static void pm3fb_get_par(void *par, struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+
+	DTRACE;
+
+	if (!current_par_valid[l_fb_info->board_num]) {
+		if (l_fb_info->use_current)
+			pm3fb_read_mode(l_fb_info, l_fb_info->current_par);
+		else
+			memcpy(l_fb_info->current_par,
+			       &(mode_base[0].user_mode),
+			       sizeof(struct pm3fb_par));
+		current_par_valid[l_fb_info->board_num] = 1;
+	}
+	*((struct pm3fb_par *) par) = *(l_fb_info->current_par);
+}
+
+static void pm3fb_set_par(const void *par, struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+
+	DTRACE;
+
+	*(l_fb_info->current_par) = *((struct pm3fb_par *) par);
+	current_par_valid[l_fb_info->board_num] = 1;
+
+	pm3fb_write_mode(l_fb_info);
+
+#ifdef PM3FB_USE_ACCEL
+	pm3fb_init_engine(l_fb_info);
+#endif /* PM3FB_USE_ACCEL */
+}
+
+static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
+			    unsigned char regno, unsigned char r,
+			    unsigned char g, unsigned char b)
+{
+	DTRACE;
+
+	PM3_SLOW_WRITE_REG(PM3RD_PaletteWriteAddress, regno);
+	PM3_SLOW_WRITE_REG(PM3RD_PaletteData, r);
+	PM3_SLOW_WRITE_REG(PM3RD_PaletteData, g);
+	PM3_SLOW_WRITE_REG(PM3RD_PaletteData, b);
+}
+
+static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			   unsigned *blue, unsigned *transp,
+			   struct fb_info *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+
+	DTRACE;
+
+	if (regno < 256) {
+		*red =
+		    l_fb_info->palette[regno].red << 8 | l_fb_info->
+		    palette[regno].red;
+		*green =
+		    l_fb_info->palette[regno].green << 8 | l_fb_info->
+		    palette[regno].green;
+		*blue =
+		    l_fb_info->palette[regno].blue << 8 | l_fb_info->
+		    palette[regno].blue;
+		*transp =
+		    l_fb_info->palette[regno].transp << 8 | l_fb_info->
+		    palette[regno].transp;
+	}
+	return (regno > 255);
+}
+
+static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+
+	DTRACE;
+
+	if (regno < 16) {
+		switch (l_fb_info->current_par->depth) {
+#ifdef FBCON_HAS_CFB8
+		case 8:
+			break;
+#endif
+#ifdef FBCON_HAS_CFB16
+		case 12:
+			l_fb_info->cmap.cmap12[regno] =
+				(((u32) red & 0xf000) >> 4) |
+				(((u32) green & 0xf000) >> 8) |
+				(((u32) blue & 0xf000) >> 12);
+			break;
+
+		case 15:
+			l_fb_info->cmap.cmap15[regno] =
+				(((u32) red & 0xf800) >> 1) |
+				(((u32) green & 0xf800) >> 6) |
+				(((u32) blue & 0xf800) >> 11);
+			break;
+
+		case 16:
+			l_fb_info->cmap.cmap16[regno] =
+			    ((u32) red & 0xf800) |
+			    (((u32) green & 0xfc00) >> 5) |
+			    (((u32) blue & 0xf800) >> 11);
+			break;
+#endif
+#ifdef FBCON_HAS_CFB32
+		case 32:
+			l_fb_info->cmap.cmap32[regno] =
+			    (((u32) transp & 0xff00) << 16) |
+			    (((u32) red & 0xff00) << 8) |
+			    (((u32) green & 0xff00)) |
+			    (((u32) blue & 0xff00) >> 8);
+			break;
+#endif
+		default:
+			DPRINTK(1, "bad depth %u\n",
+				l_fb_info->current_par->depth);
+			break;
+		}
+	}
+	if (regno < 256) {
+		l_fb_info->palette[regno].red = red >> 8;
+		l_fb_info->palette[regno].green = green >> 8;
+		l_fb_info->palette[regno].blue = blue >> 8;
+		l_fb_info->palette[regno].transp = transp >> 8;
+		if (l_fb_info->current_par->depth == 8)
+			pm3fb_set_color(l_fb_info, regno, red >> 8,
+					green >> 8, blue >> 8);
+	}
+	return (regno > 255);
+}
+
+static int pm3fb_blank(int blank_mode, struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+	u32 video;
+
+	DTRACE;
+
+	if (!current_par_valid[l_fb_info->board_num])
+		return (1);
+
+	video = l_fb_info->current_par->video;
+
+	/*
+	 * Oxygen VX1 - it appears that setting PM3VideoControl and
+	 * then PM3RD_SyncControl to the same SYNC settings undoes
+	 * any net change - they seem to xor together.  Only set the
+	 * sync options in PM3RD_SyncControl.  --rmk
+	 */
+	video &= ~(PM3VideoControl_HSYNC_MASK |
+		   PM3VideoControl_VSYNC_MASK);
+	video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
+		 PM3VideoControl_VSYNC_ACTIVE_HIGH;
+
+	if (blank_mode > 0) {
+		switch (blank_mode - 1) {
+
+		case VESA_NO_BLANKING:	/* FIXME */
+			video = video & ~(PM3VideoControl_ENABLE);
+			break;
+
+		case VESA_HSYNC_SUSPEND:
+			video = video & ~(PM3VideoControl_HSYNC_MASK |
+					  PM3VideoControl_BLANK_ACTIVE_LOW);
+			break;
+		case VESA_VSYNC_SUSPEND:
+			video = video & ~(PM3VideoControl_VSYNC_MASK |
+					  PM3VideoControl_BLANK_ACTIVE_LOW);
+			break;
+		case VESA_POWERDOWN:
+			video = video & ~(PM3VideoControl_HSYNC_MASK |
+					  PM3VideoControl_VSYNC_MASK |
+					  PM3VideoControl_BLANK_ACTIVE_LOW);
+			break;
+		default:
+			DPRINTK(1, "Unsupported blanking %d\n",
+				blank_mode);
+			return (1);
+			break;
+		}
+	}
+
+	PM3_SLOW_WRITE_REG(PM3VideoControl, video);
+
+	return (0);
+}
+
+static void pm3fb_set_disp(const void *par, struct display *disp,
+			   struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+	struct pm3fb_par *p = (struct pm3fb_par *) par;
+	u32 flags;
+
+	DTRACE;
+
+	save_flags(flags);
+	cli();
+	info->info.screen_base = l_fb_info->v_fb;
+	switch (p->depth) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+#ifdef PM3FB_USE_ACCEL
+		if (!(noaccel[l_fb_info->board_num]))
+			disp->dispsw = &pm3fb_cfb8;
+		else
+#endif /* PM3FB_USE_ACCEL */
+			disp->dispsw = &fbcon_cfb8;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 12:
+#ifdef PM3FB_USE_ACCEL
+		if (!(noaccel[l_fb_info->board_num]))
+			disp->dispsw = &pm3fb_cfb16;
+		else
+#endif /* PM3FB_USE_ACCEL */
+			disp->dispsw = &fbcon_cfb16;
+		disp->dispsw_data = l_fb_info->cmap.cmap12;
+		break;
+	case 15:
+#ifdef PM3FB_USE_ACCEL
+		if (!(noaccel[l_fb_info->board_num]))
+			disp->dispsw = &pm3fb_cfb16;
+		else
+#endif /* PM3FB_USE_ACCEL */
+			disp->dispsw = &fbcon_cfb16;
+		disp->dispsw_data = l_fb_info->cmap.cmap15;
+		break;
+	case 16:
+#ifdef PM3FB_USE_ACCEL
+		if (!(noaccel[l_fb_info->board_num]))
+			disp->dispsw = &pm3fb_cfb16;
+		else
+#endif /* PM3FB_USE_ACCEL */
+			disp->dispsw = &fbcon_cfb16;
+		disp->dispsw_data = l_fb_info->cmap.cmap16;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+#ifdef PM3FB_USE_ACCEL
+		if (!(noaccel[l_fb_info->board_num]))
+			disp->dispsw = &pm3fb_cfb32;
+		else
+#endif /* PM3FB_USE_ACCEL */
+			disp->dispsw = &fbcon_cfb32;
+		disp->dispsw_data = l_fb_info->cmap.cmap32;
+		break;
+#endif /* FBCON_HAS_CFB32 */
+	default:
+		disp->dispsw = &fbcon_dummy;
+		DPRINTK(1, "Invalid depth, using fbcon_dummy\n");
+		break;
+	}
+	restore_flags(flags);
+}
+
+/* */
+static void pm3fb_detect(void)
+{
+	struct pci_dev *dev_array[PM3_MAX_BOARD];
+	struct pci_dev *dev = NULL;
+	struct pm3fb_info *l_fb_info = &(fb_info[0]);
+	unsigned long i, j, done;
+
+	DTRACE;
+
+	for (i = 0; i < PM3_MAX_BOARD; i++) {
+		dev_array[i] = NULL;
+		fb_info[i].dev = NULL;
+	}
+
+	dev =
+	    pci_find_device(PCI_VENDOR_ID_3DLABS,
+			    PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
+
+	for (i = 0; ((i < PM3_MAX_BOARD) && dev); i++) {
+		dev_array[i] = dev;
+		dev =
+		    pci_find_device(PCI_VENDOR_ID_3DLABS,
+				    PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
+	}
+
+	if (dev) {		/* more than PM3_MAX_BOARD */
+		printk(KERN_WARNING "pm3fb: Warning: more than %d boards found\n",
+		       PM3_MAX_BOARD);
+	}
+
+	if (!dev_array[0]) {	/* not a single board, abort */
+		return;
+	}
+
+	/* allocate user-defined boards */
+	for (i = 0; i < PM3_MAX_BOARD; i++) {
+		if ((bus[i] >= 0) && (slot[i] >= 0) && (func[i] >= 0)) {
+			for (j = 0; j < PM3_MAX_BOARD; j++) {
+				if ((dev_array[j] != NULL) &&
+				    (dev_array[j]->bus->number == bus[i])
+				    && (PCI_SLOT(dev_array[j]->devfn) ==
+					slot[i])
+				    && (PCI_FUNC(dev_array[j]->devfn) ==
+					func[i])) {
+					fb_info[i].dev = dev_array[j];
+					dev_array[j] = NULL;
+				}
+			}
+		}
+	}
+	/* allocate remaining boards */
+	for (i = 0; i < PM3_MAX_BOARD; i++) {
+		if (fb_info[i].dev == NULL) {
+			done = 0;
+			for (j = 0; ((j < PM3_MAX_BOARD) && (!done)); j++) {
+				if (dev_array[j] != NULL) {
+					fb_info[i].dev = dev_array[j];
+					dev_array[j] = NULL;
+					done = 1;
+				}
+			}
+		}
+	}
+
+	/* at that point, all PCI Permedia3 are detected and allocated */
+	/* now, initialize... or not */
+	for (i = 0; i < PM3_MAX_BOARD; i++) {
+		l_fb_info = &(fb_info[i]);
+		if ((l_fb_info->dev) && (!disable[i])) {	/* PCI device was found and not disabled by user */
+#ifdef SUPPORT_FB_OF
+			struct device_node *dp =
+			    find_pci_device_OFnode(l_fb_info->dev->bus->
+						   number,
+						   l_fb_info->dev->devfn);
+
+			if ((dp) && (!strncmp(dp->name, "formacGA12", 10))) {
+				/* do nothing, init of board is done in pm3fb_of_init */
+			} else {
+#endif
+				DPRINTK(2,
+					"found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n",
+					(unsigned long) l_fb_info->dev,
+					(unsigned long) l_fb_info->dev->
+					vendor,
+					(unsigned long) l_fb_info->dev->
+					device,
+					(unsigned long)
+					pci_resource_start(l_fb_info->dev,
+							   0),
+					(unsigned long)
+					pci_resource_start(l_fb_info->dev,
+							   1),
+					(unsigned long)
+					pci_resource_start(l_fb_info->dev,
+							   2),
+					(unsigned long)
+					pci_resource_start(l_fb_info->dev,
+							   3),
+					(unsigned long)
+					pci_resource_start(l_fb_info->dev,
+							   4),
+					(unsigned long)
+					pci_resource_start(l_fb_info->dev,
+							   5),
+					(unsigned long) l_fb_info->dev->
+					irq);
+
+				l_fb_info->pIOBase =
+				    (unsigned char *)
+				    pci_resource_start(l_fb_info->dev, 0);
+#ifdef __BIG_ENDIAN
+				l_fb_info->pIOBase += PM3_REGS_SIZE;
+#endif
+				l_fb_info->vIOBase = (unsigned char *) -1;
+				l_fb_info->p_fb =
+				    (unsigned char *)
+				    pci_resource_start(l_fb_info->dev, 1);
+				l_fb_info->v_fb = (unsigned char *) -1;
+
+#if (defined KERNEL_2_4) || (defined KERNEL_2_5) 	/* full resource management, new in linux-2.4.x */
+				if (!request_mem_region
+				    ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */
+				     "pm3fb")) {
+					printk
+					    (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n",
+					     l_fb_info->board_num);
+					continue;
+				}
+				if (!request_mem_region
+				    ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE,
+				     "pm3fb I/O regs")) {
+					printk
+					    (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n",
+					     l_fb_info->board_num);
+					continue;
+				}
+#endif /* KERNEL_2_4 or KERNEL_2_5 */
+				if (forcesize[l_fb_info->board_num])
+					l_fb_info->fb_size = forcesize[l_fb_info->board_num];
+				
+				l_fb_info->fb_size =
+				    pm3fb_size_memory(l_fb_info);
+
+				if (l_fb_info->fb_size) {
+					(void) pci_enable_device(l_fb_info->dev);
+					pm3fb_common_init(l_fb_info);
+				} else
+					printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num);
+				
+#ifdef SUPPORT_FB_OF
+			}
+#endif /* SUPPORT_FB_OF */
+		}
+	}
+}
+
+static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
+			     struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+
+	DTRACE;
+
+	if (!current_par_valid[l_fb_info->board_num])
+		return -EINVAL;
+
+	l_fb_info->current_par->base =	/* in 128 bits chunk - i.e. AFTER Shiftbpp */
+	    pm3fb_Shiftbpp(l_fb_info,
+			   l_fb_info->current_par->depth,
+			   (var->yoffset * l_fb_info->current_par->width) +
+			   var->xoffset);
+	PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
+	return 0;
+}
+
+static int pm3fb_ioctl(struct inode *inode, struct file *file,
+                       u_int cmd, u_long arg, int con,
+		       struct fb_info *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+	u32 cm, i;
+#ifdef PM3FB_MASTER_DEBUG
+	char cc[3];
+#endif /* PM3FB_MASTER_DEBUG */
+
+	switch(cmd)
+	{
+#ifdef PM3FB_MASTER_DEBUG
+	case PM3FBIO_CLEARMEMORY:
+		if (copy_from_user(&cm, (void *)arg, sizeof(u32)))
+			return(-EFAULT);
+		pm3fb_clear_memory(l_fb_info, cm);
+		return(0);
+		break;
+
+	case PM3FBIO_CLEARCMAP:
+		if (copy_from_user(cc, (void*)arg, 3 * sizeof(char)))
+			return(-EFAULT);
+		pm3fb_clear_colormap(l_fb_info, cc[0], cc[1], cc[2]);
+		return(0);
+		break;
+#endif /* PM3FB_MASTER_DEBUG */
+
+	case PM3FBIO_RESETCHIP:
+		cm = 1;
+		PM3_SLOW_WRITE_REG(PM3ResetStatus, 1);
+		for (i = 0 ; (i < 10000) && cm ; i++)
+		{
+			PM3_DELAY(10);
+			cm = PM3_READ_REG(PM3ResetStatus);
+		}
+		if (cm)
+		{
+			printk(KERN_ERR "pm3fb: chip reset failed with status 0x%x\n", cm);
+			return(-EIO);
+		}
+		/* first thing first, reload memory timings */
+		pm3fb_write_memory_timings(l_fb_info);
+#ifdef PM3FB_USE_ACCEL
+		pm3fb_init_engine(l_fb_info);
+#endif /* PM3FB_USE_ACCEL */
+		pm3fb_write_mode(l_fb_info);
+		return(0);
+		break;
+
+	default:
+		DPRINTK(2, "unknown ioctl: %d (%x)\n", cmd, cmd);
+		return(-EINVAL);
+	}
+}
+
+/* ****************************************** */
+/* ***** standard FB API init functions ***** */
+/* ****************************************** */
+
+#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
+int __init pm3fb_setup(char *options)
+#endif
+#ifdef KERNEL_2_2
+__initfunc(void pm3fb_setup(char *options, int *ints))
+#endif
+{
+	long opsi = strlen(options);
+
+	DTRACE;
+
+	memcpy(g_options, options,
+	       ((opsi + 1) >
+		PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1));
+	g_options[PM3_OPTIONS_SIZE - 1] = 0;
+
+#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
+	return (0);
+#endif
+}
+
+#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
+int __init pm3fb_init(void)
+#endif
+#ifdef KERNEL_2_2
+__initfunc(void pm3fb_init(void))
+#endif
+{
+	DTRACE;
+
+	DPRINTK(2, "This is pm3fb.c, CVS version: $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $");
+
+	pm3fb_real_setup(g_options);
+
+	pm3fb_detect();
+
+	if (!fb_info[0].dev) {	/* not even one board ??? */
+		DPRINTK(1, "No PCI Permedia3 board detected\n");
+	}
+#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
+	return (0);
+#endif
+}
+
+#ifdef SUPPORT_FB_OF		/* linux-2.2.x only */
+__initfunc(void pm3fb_of_init(struct device_node *dp))
+{
+	struct pm3fb_info *l_fb_info = NULL;
+	unsigned long i;
+	long bn = -1;
+	struct device_node *dn;
+
+	DTRACE;
+
+	DPRINTK(2, "OpenFirmware board : %s\n", dp->full_name);
+
+	for (i = 0; i < dp->n_addrs; i++) {
+		DPRINTK(2, "MemRange : 0x%08x - 0x%x\n",
+			dp->addrs[i].address, dp->addrs[i].size);
+	}
+
+	for (i = 0; i < PM3_MAX_BOARD; i++) {	/* find which PCI board is the OF device */
+		if (fb_info[i].dev) {
+			dn = find_pci_device_OFnode(fb_info[i].dev->bus->
+						    number,
+						    fb_info[i].dev->devfn);
+			if (dn == dp) {
+				if (bn == -1)
+					bn = i;
+				else {
+					DPRINTK(1,
+						"Error: Multiple PCI device for a single OpenFirmware node\n");
+				}
+			}
+		}
+	}
+
+	if (bn == -1) {
+		DPRINTK(1, "Warning: non-PCI Permedia3 found\n");
+		i = 0;
+		while (fb_info[i].dev && (i < PM3_MAX_BOARD))
+			i++;
+		if (i < PM3_MAX_BOARD)
+			bn = i;
+		else {
+			printk
+			    (KERN_ERR "pm3fb: Error: Couldn't find room for OpenFirmware device");
+			return;
+		}
+	}
+
+	l_fb_info = &(fb_info[bn]);
+
+	l_fb_info->dn = dp;
+
+	l_fb_info->pIOBase = (unsigned char *) dp->addrs[3].address;
+#ifdef __BIG_ENDIAN
+	l_fb_info->pIOBase += PM3_REGS_SIZE;
+#endif
+	l_fb_info->vIOBase = (unsigned char *) -1;
+	l_fb_info->p_fb = (unsigned char *) dp->addrs[1].address;
+	l_fb_info->v_fb = (unsigned char *) -1;
+
+	l_fb_info->fb_size = pm3fb_size_memory(l_fb_info);	/* (unsigned long)dp->addrs[1].size; *//* OF is a liar ! it claims 256 Mb */
+
+	DPRINTK(2,
+		"OpenFirmware board (#%ld) : IOBase 0x%08lx, p_fb 0x%08lx, fb_size %d KB\n",
+		bn, (unsigned long) l_fb_info->pIOBase,
+		(unsigned long) l_fb_info->p_fb, l_fb_info->fb_size >> 10);
+
+	l_fb_info->use_current = 1;	/* will use current mode by default */
+
+	pm3fb_common_init(l_fb_info);
+}
+#endif /* SUPPORT_FB_OF */
+
+/* ************************* */
+/* **** Module support ***** */
+/* ************************* */
+
+#ifdef MODULE
+MODULE_AUTHOR("Romain Dolbeau");
+MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
+static char *mode[PM3_MAX_BOARD];
+MODULE_PARM(mode,PM3_MAX_BOARD_MODULE_ARRAY_STRING);
+MODULE_PARM_DESC(mode,"video mode");
+MODULE_PARM(disable,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+MODULE_PARM_DESC(disable,"disable board");
+static short off[PM3_MAX_BOARD];
+MODULE_PARM(off,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+MODULE_PARM_DESC(off,"disable board");
+static char *pciid[PM3_MAX_BOARD];
+MODULE_PARM(pciid,PM3_MAX_BOARD_MODULE_ARRAY_STRING);
+MODULE_PARM_DESC(pciid,"board PCI Id");
+MODULE_PARM(noaccel,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+MODULE_PARM_DESC(noaccel,"disable accel");
+static char *font[PM3_MAX_BOARD];
+MODULE_PARM(font,PM3_MAX_BOARD_MODULE_ARRAY_STRING);
+MODULE_PARM_DESC(font,"choose font");
+MODULE_PARM(depth,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+MODULE_PARM_DESC(depth,"boot-time depth");
+MODULE_PARM(printtimings, "h");
+MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)");
+MODULE_PARM(forcesize, PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+MODULE_PARM_DESC(forcesize, "force specified memory size");
+/*
+MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards")
+MODULE_GENERIC_TABLE(gtype,name)
+MODULE_DEVICE_TABLE(type,name)
+*/
+
+void pm3fb_build_options(void)
+{
+	int i;
+	char ts[128];
+
+	strcpy(g_options, "pm3fb");
+	for (i = 0; i < PM3_MAX_BOARD ; i++)
+	{
+		if (mode[i])
+		{
+			sprintf(ts, ",mode:%d:%s", i, mode[i]);
+			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
+		}
+		if (disable[i] || off[i])
+		{
+			sprintf(ts, ",disable:%d:", i);
+			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
+		}
+		if (pciid[i])
+		{
+			sprintf(ts, ",pciid:%d:%s", i, pciid[i]);
+			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
+		}
+		if (noaccel[i])
+		{
+			sprintf(ts, ",noaccel:%d:", i);
+			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
+		}
+		if (font[i])
+		{
+			sprintf(ts, ",font:%d:%s", i, font[i]);
+			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
+		}
+		if (depth[i])
+		{
+			sprintf(ts, ",depth:%d:%d", i, depth[i]);
+			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
+		}
+	}
+	g_options[PM3_OPTIONS_SIZE - 1] = '\0';
+	DPRINTK(1, "pm3fb use options: %s\n", g_options);
+}
+
+int init_module(void)
+{
+	DTRACE;
+
+	pm3fb_build_options();
+
+	pm3fb_init();
+
+	return (0);
+}
+
+void cleanup_module(void)
+{
+	DTRACE;
+	{
+		unsigned long i;
+		struct pm3fb_info *l_fb_info;
+		for (i = 0; i < PM3_MAX_BOARD; i++) {
+			l_fb_info = &(fb_info[i]);
+			if ((l_fb_info->dev != NULL)
+			    && (!(disable[l_fb_info->board_num]))) {
+				if (l_fb_info->vIOBase !=
+				    (unsigned char *) -1) {
+					pm3fb_unmapIO(l_fb_info);
+#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
+					release_mem_region(l_fb_info->p_fb,
+							   l_fb_info->
+							   fb_size);
+					release_mem_region(l_fb_info->
+							   pIOBase,
+							   PM3_REGS_SIZE);
+#endif /* KERNEL_2_4 or KERNEL_2_5 */
+				}
+				unregister_framebuffer(&l_fb_info->gen.
+						       info);
+			}
+		}
+	}
+	return;
+}
+#endif /* MODULE */
diff -Nru a/drivers/video/pm3fb.h b/drivers/video/pm3fb.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/video/pm3fb.h	Wed May 29 11:43:03 2002
@@ -0,0 +1,1284 @@
+/*
+ *  linux/drivers/video/pm3fb.h -- 3DLabs Permedia3 frame buffer device
+ *  
+ *  Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr>
+ *  Copyright (C) 2001 Sven Luther, <luther@dpt-info.u-strasbg.fr>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ *  $Header: /cvsroot/linux/drivers/video/pm3fb.h,v 1.1 2002/02/25 19:11:06 marcelo Exp $
+ *
+ */
+
+#ifndef PM3FB_H
+#define PM3FB_H
+
+/**********************************************
+*  GLINT Permedia3 Control Status registers   *
+***********************************************/
+/* Control Status Registers */
+#define PM3ResetStatus						0x0000
+#define PM3IntEnable						0x0008
+#define PM3IntFlags						0x0010
+#define PM3InFIFOSpace						0x0018
+#define PM3OutFIFOWords						0x0020
+#define PM3DMAAddress						0x0028
+#define PM3DMACount						0x0030
+#define PM3ErrorFlags						0x0038
+#define PM3VClkCtl						0x0040
+#define PM3TestRegister						0x0048
+#define PM3Aperture0						0x0050
+#define PM3Aperture1						0x0058
+#define PM3DMAControl						0x0060
+#define PM3FIFODis						0x0068
+#define PM3ChipConfig						0x0070
+#define PM3AGPControl						0x0078
+
+#define PM3GPOutDMAAddress					0x0080
+#define PM3PCIFeedbackCount					0x0088
+#define PM3PCIAbortStatus					0x0090
+#define PM3PCIAbortAddress					0x0098
+
+#define PM3PCIPLLStatus						0x00f0
+
+#define PM3HostTextureAddress					0x0100
+#define PM3TextureDownloadControl				0x0108
+#define PM3TextureOperation					0x0110
+#define PM3LogicalTexturePage					0x0118
+#define PM3TexDMAAddress					0x0120
+#define PM3TexFIFOSpace						0x0128
+
+/**********************************************
+*  GLINT Permedia3 Region 0 Bypass Controls   *
+***********************************************/
+#define PM3ByAperture1Mode					0x0300
+	#define PM3ByApertureMode_BYTESWAP_ABCD			(0<<0)
+	#define PM3ByApertureMode_BYTESWAP_BADC			(1<<0)
+	#define PM3ByApertureMode_BYTESWAP_CDAB			(2<<0)
+	#define PM3ByApertureMode_BYTESWAP_DCBA			(3<<0)
+	#define PM3ByApertureMode_PATCH_DISABLE			(0<<2)
+	#define PM3ByApertureMode_PATCH_ENABLE			(1<<2)
+	#define PM3ByApertureMode_FORMAT_RAW			(0<<3)
+	#define PM3ByApertureMode_FORMAT_YUYV			(1<<3)
+	#define PM3ByApertureMode_FORMAT_UYVY			(2<<3)
+	#define PM3ByApertureMode_PIXELSIZE_8BIT		(0<<5)
+	#define PM3ByApertureMode_PIXELSIZE_16BIT		(1<<5)
+	#define PM3ByApertureMode_PIXELSIZE_32BIT		(2<<5)
+                #define PM3ByApertureMode_PIXELSIZE_MASK        (3<<5)
+	#define PM3ByApertureMode_EFFECTIVE_STRIDE_1024		(0<<7)
+	#define PM3ByApertureMode_EFFECTIVE_STRIDE_2048		(1<<7)
+	#define PM3ByApertureMode_EFFECTIVE_STRIDE_4096		(2<<7)
+	#define PM3ByApertureMode_EFFECTIVE_STRIDE_8192		(3<<7)
+	#define PM3ByApertureMode_PATCH_OFFSET_X(off)	(((off)&7f)<<9)
+	#define PM3ByApertureMode_PATCH_OFFSET_Y(off)	(((off)&7f)<<16)
+	#define PM3ByApertureMode_FRAMEBUFFER			(0<<21)
+	#define PM3ByApertureMode_LOCALBUFFER			(1<<21)
+	#define PM3ByApertureMode_DOUBLE_WRITE_OFF		(0<<22)
+	#define PM3ByApertureMode_DOUBLE_WRITE_1MB		(1<<22)
+	#define PM3ByApertureMode_DOUBLE_WRITE_2MB		(2<<22)
+	#define PM3ByApertureMode_DOUBLE_WRITE_4MB		(3<<22)
+	#define PM3ByApertureMode_DOUBLE_WRITE_8MB		(4<<22)
+	#define PM3ByApertureMode_DOUBLE_WRITE_16MB		(5<<22)
+	#define PM3ByApertureMode_DOUBLE_WRITE_32MB		(6<<22)
+
+#define PM3ByAperture2Mode					0x0328
+	
+/**********************************************
+*  GLINT Permedia3 Memory Control (0x1000)    *
+***********************************************/
+#define PM3MemCounter						0x1000
+#define PM3MemBypassWriteMask					0x1008
+#define PM3MemScratch						0x1010
+#define PM3LocalMemCaps						0x1018
+        #define PM3LocalMemCaps_NoWriteMask                     (1 << 28)
+#define PM3LocalMemTimings					0x1020
+#define PM3LocalMemControl					0x1028
+#define PM3LocalMemRefresh					0x1030
+#define PM3LocalMemPowerDown					0x1038
+#define PM3RemoteMemControl					0x1100
+
+/**********************************************
+*  GLINT Permedia3 Video Control (0x3000)     *
+***********************************************/
+
+#define PM3ScreenBase						0x3000
+#define PM3ScreenStride						0x3008
+#define PM3HTotal						0x3010
+#define PM3HgEnd						0x3018
+#define PM3HbEnd						0x3020
+#define PM3HsStart						0x3028
+#define PM3HsEnd						0x3030
+#define PM3VTotal						0x3038
+#define PM3VbEnd						0x3040
+#define PM3VsStart						0x3048
+#define PM3VsEnd						0x3050
+#define PM3VideoControl						0x3058
+	#define PM3VideoControl_DISABLE				(0<<0)
+	#define PM3VideoControl_ENABLE				(1<<0)
+	#define PM3VideoControl_BLANK_ACTIVE_HIGH		(0<<1)
+	#define PM3VideoControl_BLANK_ACTIVE_LOW		(1<<1)
+	#define PM3VideoControl_LINE_DOUBLE_OFF			(0<<2)
+	#define PM3VideoControl_LINE_DOUBLE_ON			(1<<2)
+	#define PM3VideoControl_HSYNC_FORCE_HIGH		(0<<3)
+	#define PM3VideoControl_HSYNC_ACTIVE_HIGH		(1<<3)
+	#define PM3VideoControl_HSYNC_FORCE_LOW			(2<<3)
+	#define PM3VideoControl_HSYNC_ACTIVE_LOW		(3<<3)
+        #define PM3VideoControl_HSYNC_MASK          (3<<3)
+	#define PM3VideoControl_VSYNC_FORCE_HIGH		(0<<5)
+	#define PM3VideoControl_VSYNC_ACTIVE_HIGH		(1<<5)
+	#define PM3VideoControl_VSYNC_FORCE_LOW			(2<<5)
+	#define PM3VideoControl_VSYNC_ACTIVE_LOW		(3<<5)
+        #define PM3VideoControl_VSYNC_MASK          (3<<5)
+	#define PM3VideoControl_BYTE_DOUBLE_OFF			(0<<7)
+	#define PM3VideoControl_BYTE_DOUBLE_ON			(1<<7)
+	#define PM3VideoControl_BUFFER_SWAP_SYNCON_FRAMEBLANK	(0<<9)
+	#define PM3VideoControl_BUFFER_SWAP_FREE_RUNNING	(1<<9)
+	#define PM3VideoControl_BUFFER_SWAP_LIMITETO_FRAMERATE	(2<<9)
+	#define PM3VideoControl_STEREO_DISABLE			(0<<11)
+	#define PM3VideoControl_STEREO_ENABLE			(1<<11)
+	#define PM3VideoControl_RIGHT_EYE_ACTIVE_HIGH		(0<<12)
+	#define PM3VideoControl_RIGHT_EYE_ACTIVE_LOW		(1<<12)
+	#define PM3VideoControl_VIDEO_EXT_LOW			(0<<14)
+	#define PM3VideoControl_VIDEO_EXT_HIGH			(1<<14)
+	#define PM3VideoControl_SYNC_MODE_INDEPENDENT		(0<<16)
+	#define PM3VideoControl_SYNC_MODE_SYNCTO_VSA		(1<<16)
+	#define PM3VideoControl_SYNC_MODE_SYNCTO_VSB		(2<<16)
+	#define PM3VideoControl_PATCH_DISABLE			(0<<18)
+	#define PM3VideoControl_PATCH_ENABLE			(1<<18)
+	#define PM3VideoControl_PIXELSIZE_8BIT			(0<<19)
+	#define PM3VideoControl_PIXELSIZE_16BIT			(1<<19)
+	#define PM3VideoControl_PIXELSIZE_32BIT			(2<<19)
+	#define PM3VideoControl_DISPLAY_DISABLE			(0<<21)
+	#define PM3VideoControl_DISPLAY_ENABLE			(1<<21)
+	#define PM3VideoControl_PATCH_OFFSET_X(off)	(((off)&0x3f)<<22)
+	#define PM3VideoControl_PATCH_OFFSET_Y(off)	(((off)&0x3f)<<28)
+#define PM3InterruptLine					0x3060
+#define PM3DisplayData						0x3068
+#define PM3VerticalLineCount					0x3070
+#define PM3FifoControl						0x3078
+#define PM3ScreenBaseRight					0x3080
+#define PM3MiscControl						0x3088
+
+#define PM3VideoOverlayUpdate					0x3100
+        #define PM3VideoOverlayUpdate_DISABLE                   (0<<0)
+        #define PM3VideoOverlayUpdate_ENABLE                    (1<<0)
+#define PM3VideoOverlayMode					0x3108
+	#define PM3VideoOverlayMode_DISABLE			(0<<0)
+	#define PM3VideoOverlayMode_ENABLE			(1<<0)
+        #define PM3VideoOverlayMode_BUFFERSYNC_MANUAL           (0<<1)
+        #define PM3VideoOverlayMode_BUFFERSYNC_VIDEOSTREAMA     (1<<1)
+        #define PM3VideoOverlayMode_BUFFERSYNC_VIDEOSTREAMB     (2<<1)
+        #define PM3VideoOverlayMode_FIELDPOLARITY_NORMAL        (0<<4)
+        #define PM3VideoOverlayMode_FIELDPOLARITY_INVERT        (1<<4)
+        #define PM3VideoOverlayMode_PIXELSIZE_8BIT              (0<<5)
+        #define PM3VideoOverlayMode_PIXELSIZE_16BIT             (1<<5)
+        #define PM3VideoOverlayMode_PIXELSIZE_32BIT             (2<<5)
+        #define PM3VideoOverlayMode_COLORFORMAT_RGB8888 ((0<<7)|(1<<12)|(2<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_RGB4444 ((1<<7)|(1<<12)|(1<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_RGB5551 ((2<<7)|(1<<12)|(1<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_RGB565  ((3<<7)|(1<<12)|(1<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_RGB332  ((4<<7)|(1<<12)|(0<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_BGR8888 ((0<<7)|(2<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_BGR4444 ((1<<7)|(1<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_BGR5551 ((2<<7)|(1<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_BGR565  ((3<<7)|(1<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_BGR332  ((4<<7)|(0<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_CI8     ((5<<7)|(1<<12)|(0<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_VUY444  ((2<<10)|(1<<12)|(2<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_YUV444  ((2<<10)|(2<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_VUY422  ((1<<10)|(1<<12)|(1<<5))
+        #define PM3VideoOverlayMode_COLORFORMAT_YUV422  ((1<<10)|(1<<5))
+        #define PM3VideoOverlayMode_COLORORDER_BGR              (0<<12)
+        #define PM3VideoOverlayMode_COLORORDER_RGB              (1<<12)
+        #define PM3VideoOverlayMode_LINEARCOLOREXT_OFF          (0<<13)
+        #define PM3VideoOverlayMode_LINEARCOLOREXT_ON           (1<<13)
+        #define PM3VideoOverlayMode_FILTER_MASK                 (3<<14)
+        #define PM3VideoOverlayMode_FILTER_OFF                  (0<<14)
+        #define PM3VideoOverlayMode_FILTER_FULL                 (1<<14)
+        #define PM3VideoOverlayMode_FILTER_PARTIAL              (2<<14)
+        #define PM3VideoOverlayMode_DEINTERLACE_OFF             (0<<16)
+        #define PM3VideoOverlayMode_DEINTERLACE_BOB             (1<<16)
+        #define PM3VideoOverlayMode_PATCHMODE_OFF               (0<<18)
+        #define PM3VideoOverlayMode_PATCHMODE_ON                (1<<18)
+        #define PM3VideoOverlayMode_FLIP_VIDEO                  (0<<20)
+        #define PM3VideoOverlayMode_FLIP_VIDEOSTREAMA           (1<<20)
+        #define PM3VideoOverlayMode_FLIP_VIDEOSTREAMB           (2<<20)
+        #define PM3VideoOverlayMode_MIRROR_MASK                 (3<<23)
+        #define PM3VideoOverlayMode_MIRRORX_OFF                 (0<<23)
+        #define PM3VideoOverlayMode_MIRRORX_ON                  (1<<23)
+        #define PM3VideoOverlayMode_MIRRORY_OFF                 (0<<24)
+        #define PM3VideoOverlayMode_MIRRORY_ON                  (1<<24)
+#define PM3VideoOverlayFifoControl				0x3110
+#define PM3VideoOverlayIndex					0x3118
+#define PM3VideoOverlayBase0					0x3120
+#define PM3VideoOverlayBase1					0x3128
+#define PM3VideoOverlayBase2					0x3130
+#define PM3VideoOverlayStride					0x3138
+        #define PM3VideoOverlayStride_STRIDE(s)         (((s)&0xfff)<<0)
+#define PM3VideoOverlayWidth                                    0x3140
+        #define PM3VideoOverlayWidth_WIDTH(w)           (((w)&0xfff)<<0)
+#define PM3VideoOverlayHeight                                   0x3148
+        #define PM3VideoOverlayHeight_HEIGHT(h)         (((h)&0xfff)<<0)
+#define PM3VideoOverlayOrigin                                   0x3150
+        #define PM3VideoOverlayOrigin_XORIGIN(x)        (((x)&0xfff)<<0)
+        #define PM3VideoOverlayOrigin_YORIGIN(y)        (((y)&0xfff)<<16)
+#define PM3VideoOverlayShrinkXDelta                             0x3158
+        #define PM3VideoOverlayShrinkXDelta_NONE                (1<<16)
+        #define PM3VideoOverlayShrinkXDelta_DELTA(s,d)          \
+                ((((s)<<16)/(d))&0x0ffffff0)
+#define PM3VideoOverlayZoomXDelta                               0x3160
+        #define PM3VideoOverlayZoomXDelta_NONE                  (1<<16)
+        #define PM3VideoOverlayZoomXDelta_DELTA(s,d)            \
+                ((((s)<<16)/(d))&0x0001fff0)
+#define PM3VideoOverlayYDelta                                   0x3168
+        #define PM3VideoOverlayYDelta_NONE                      (1<<16)
+        #define PM3VideoOverlayYDelta_DELTA(s,d)                        \
+                ((((s)<<16)/(d))&0x0ffffff0)
+#define PM3VideoOverlayFieldOffset				0x3170
+#define PM3VideoOverlayStatus					0x3178
+
+/**********************************************
+*  GLINT Permedia3 RAMDAC Registers (0x4000)  *
+***********************************************/
+/* Direct Registers */
+#define PM3RD_PaletteWriteAddress				0x4000
+#define PM3RD_PaletteData					0x4008
+#define PM3RD_PixelMask						0x4010
+#define PM3RD_PaletteReadAddress				0x4018
+
+#define PM3RD_IndexLow						0x4020
+#define PM3RD_IndexHigh						0x4028
+#define PM3RD_IndexedData					0x4030
+#define PM3RD_IndexControl					0x4038
+	#define PM3RD_IndexControl_AUTOINCREMENT_ENABLE		(1<<0)
+	#define PM3RD_IndexControl_AUTOINCREMENT_DISABLE	(0<<0)
+
+/* Indirect Registers */
+#define PM3RD_MiscControl					0x000
+	#define PM3RD_MiscControl_HIGHCOLOR_RES_DISABLE		(0<<0)
+	#define PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE		(1<<0)
+	#define PM3RD_MiscControl_PIXELDOUBLE_DISABLE		(0<<1)
+	#define PM3RD_MiscControl_PIXELDOUBLE_ENABLE		(1<<1)
+	#define PM3RD_MiscControl_LASTREAD_ADDR_DISABLE		(0<<2)
+	#define PM3RD_MiscControl_LASTREAD_ADDR_ENABLE		(1<<2)
+	#define PM3RD_MiscControl_DIRECTCOLOR_DISABLE		(0<<3)
+	#define PM3RD_MiscControl_DIRECTCOLOR_ENABLE		(1<<3)
+	#define PM3RD_MiscControl_OVERLAY_DISABLE		(0<<4)
+	#define PM3RD_MiscControl_OVERLAY_ENABLE		(1<<4)
+	#define PM3RD_MiscControl_PIXELDOUBLE_BUFFER_DISABLE	(0<<5)
+	#define PM3RD_MiscControl_PIXELDOUBLE_BUFFER_ENABLE	(1<<5)
+	#define PM3RD_MiscControl_VSB_OUTPUT_DISABLE		(0<<6)
+	#define PM3RD_MiscControl_VSB_OUTPUT_ENABLE		(1<<6)
+	#define PM3RD_MiscControl_STEREODOUBLE_BUFFER_DISABLE	(0<<7)
+	#define PM3RD_MiscControl_STEREODOUBLE_BUFFER_ENABLE	(1<<7)
+#define PM3RD_SyncControl					0x001
+	#define PM3RD_SyncControl_HSYNC_ACTIVE_LOW		(0<<0)
+	#define PM3RD_SyncControl_HSYNC_ACTIVE_HIGH		(1<<0)
+	#define PM3RD_SyncControl_HSYNC_FORCE_ACTIVE		(3<<0)
+	#define PM3RD_SyncControl_HSYNC_FORCE_INACTIVE		(4<<0)
+	#define PM3RD_SyncControl_HSYNC_TRI_STATE		(2<<0)
+	#define PM3RD_SyncControl_VSYNC_ACTIVE_LOW		(0<<3)
+	#define PM3RD_SyncControl_VSYNC_ACTIVE_HIGH		(1<<3)
+	#define PM3RD_SyncControl_VSYNC_TRI_STATE		(2<<3)
+	#define PM3RD_SyncControl_VSYNC_FORCE_ACTIVE		(3<<3)
+	#define PM3RD_SyncControl_VSYNC_FORCE_INACTIVE		(4<<3)
+	#define PM3RD_SyncControl_HSYNC_OVERRIDE_SETBY_HSYNC	(0<<6)
+	#define PM3RD_SyncControl_HSYNC_OVERRIDE_FORCE_HIGH	(1<<6)
+	#define PM3RD_SyncControl_VSYNC_OVERRIDE_SETBY_VSYNC	(0<<7)
+	#define PM3RD_SyncControl_VSYNC_OVERRIDE_FORCE_HIGH	(1<<7)
+#define PM3RD_DACControl					0x002
+	#define PM3RD_DACControl_DAC_POWER_ON			(0<<0)
+	#define PM3RD_DACControl_DAC_POWER_OFF			(1<<0)
+	#define PM3RD_DACControl_SYNC_ON_GREEN_DISABLE		(0<<3)
+	#define PM3RD_DACControl_SYNC_ON_GREEN_ENABLE		(1<<3)
+	#define PM3RD_DACControl_BLANK_RED_DAC_DISABLE		(0<<4)
+	#define PM3RD_DACControl_BLANK_RED_DAC_ENABLE		(1<<4)
+	#define PM3RD_DACControl_BLANK_GREEN_DAC_DISABLE	(0<<5)
+	#define PM3RD_DACControl_BLANK_GREEN_DAC_ENABLE		(1<<5)
+	#define PM3RD_DACControl_BLANK_BLUE_DAC_DISABLE		(0<<6)
+	#define PM3RD_DACControl_BLANK_BLUE_DAC_ENABLE		(1<<6)
+	#define PM3RD_DACControl_BLANK_PEDESTAL_DISABLE		(0<<7)
+	#define PM3RD_DACControl_BLANK_PEDESTAL_ENABLE		(1<<7)
+#define PM3RD_PixelSize						0x003
+	#define PM3RD_PixelSize_24_BIT_PIXELS			(4<<0)
+	#define PM3RD_PixelSize_32_BIT_PIXELS			(2<<0)
+	#define PM3RD_PixelSize_16_BIT_PIXELS			(1<<0)
+	#define PM3RD_PixelSize_8_BIT_PIXELS			(0<<0)
+#define PM3RD_ColorFormat					0x004
+	#define PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE	(1<<6)
+	#define PM3RD_ColorFormat_LINEAR_COLOR_EXT_DISABLE	(0<<6)
+	#define PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW		(1<<5)
+	#define PM3RD_ColorFormat_COLOR_ORDER_RED_LOW		(0<<5)
+	#define PM3RD_ColorFormat_COLOR_FORMAT_MASK		(0x1f<<0)
+	#define PM3RD_ColorFormat_8888_COLOR			(0<<0)
+	#define PM3RD_ColorFormat_5551_FRONT_COLOR		(1<<0)
+	#define PM3RD_ColorFormat_4444_COLOR			(2<<0)
+	#define PM3RD_ColorFormat_332_FRONT_COLOR		(5<<0)
+	#define PM3RD_ColorFormat_332_BACK_COLOR		(6<<0)
+	#define PM3RD_ColorFormat_2321_FRONT_COLOR		(9<<0)
+	#define PM3RD_ColorFormat_2321_BACK_COLOR		(10<<0)
+	#define PM3RD_ColorFormat_232_FRONTOFF_COLOR		(11<<0)
+	#define PM3RD_ColorFormat_232_BACKOFF_COLOR		(12<<0)
+	#define PM3RD_ColorFormat_5551_BACK_COLOR		(13<<0)
+	#define PM3RD_ColorFormat_CI8_COLOR			(14<<0)
+	#define PM3RD_ColorFormat_565_FRONT_COLOR		(16<<0)
+	#define PM3RD_ColorFormat_565_BACK_COLOR		(17<<0)
+#define PM3RD_CursorMode					0x005
+	#define PM3RD_CursorMode_CURSOR_DISABLE			(0<<0)
+	#define PM3RD_CursorMode_CURSOR_ENABLE			(1<<0)
+	#define PM3RD_CursorMode_FORMAT_64x64_2BPE_P0123	(0<<2)
+	#define PM3RD_CursorMode_FORMAT_32x32_2BPE_P0		(1<<2)
+	#define PM3RD_CursorMode_FORMAT_32x32_2BPE_P1		(2<<2)
+	#define PM3RD_CursorMode_FORMAT_32x32_2BPE_P2		(3<<2)
+	#define PM3RD_CursorMode_FORMAT_32x32_2BPE_P3		(4<<2)
+	#define PM3RD_CursorMode_FORMAT_32x32_4BPE_P01		(5<<2)
+	#define PM3RD_CursorMode_FORMAT_32x32_4BPE_P23		(6<<2)
+	#define PM3RD_CursorMode_TYPE_MS			(0<<4)
+	#define PM3RD_CursorMode_TYPE_X				(1<<4)
+	#define PM3RD_CursorMode_REVERSE_PIXEL_ORDER_DISABLE	(0<<6)
+	#define PM3RD_CursorMode_REVERSE_PIXEL_ORDER_ENABLE	(1<<6)
+	#define PM3RD_CursorMode_REVERSE_PIXEL_ORDER_3_COLOR	(2<<6)
+	#define PM3RD_CursorMode_REVERSE_PIXEL_ORDER_15_COLOR	(3<<6)
+#define PM3RD_CursorControl					0x006
+	#define PM3RD_CursorControl_DOUBLE_X_DISABLED		(0<<0)
+	#define PM3RD_CursorControl_DOUBLE_X_ENABLED		(1<<0)
+	#define PM3RD_CursorControl_DOUBLE_Y_DISABLED		(0<<1)
+	#define PM3RD_CursorControl_DOUBLE_Y_ENABLED		(1<<1)
+	#define PM3RD_CursorControl_READBACK_POS_DISABLED	(0<<2)
+	#define PM3RD_CursorControl_READBACK_POS_ENABLED	(1<<2)
+
+#define PM3RD_CursorXLow					0x007
+#define PM3RD_CursorXHigh					0x008
+#define PM3RD_CursorYLow					0x009
+#define PM3RD_CursorYHigh					0x00a
+#define PM3RD_CursorHotSpotX					0x00b
+#define PM3RD_CursorHotSpotY					0x00c
+#define PM3RD_OverlayKey					0x00d
+#define PM3RD_Pan						0x00e
+	#define PM3RD_Pan_DISABLE				(0<<0)
+	#define PM3RD_Pan_ENABLE				(1<<0)
+	#define PM3RD_Pan_GATE_DISABLE				(0<<1)
+	#define PM3RD_Pan_GATE_ENABLE				(1<<1)
+#define PM3RD_Sense						0x00f
+
+#define PM3RD_CheckControl					0x018
+	#define PM3RD_CheckControl_PIXEL_DISABLED		(0<<0)
+	#define PM3RD_CheckControl_PIXEL_ENABLED		(1<<0)
+	#define PM3RD_CheckControl_LUT_DISABLED			(0<<1)
+	#define PM3RD_CheckControl_LUT_ENABLED			(1<<1)
+#define PM3RD_CheckPixelRed					0x019
+#define PM3RD_CheckPixelGreen					0x01a
+#define PM3RD_CheckPixelBlue					0x01b
+#define PM3RD_CheckLUTRed					0x01c
+#define PM3RD_CheckLUTGreen					0x01d
+#define PM3RD_CheckLUTBlue					0x01e
+#define PM3RD_Scratch						0x01f
+
+#define PM3RD_VideoOverlayControl				0x020
+        #define PM3RD_VideoOverlayControl_DISABLE               (0<<0)
+        #define PM3RD_VideoOverlayControl_ENABLE                (1<<0)
+        #define PM3RD_VideoOverlayControl_MODE_MASK             (3<<1)
+        #define PM3RD_VideoOverlayControl_MODE_MAINKEY          (0<<1)
+        #define PM3RD_VideoOverlayControl_MODE_OVERLAYKEY       (1<<1)
+        #define PM3RD_VideoOverlayControl_MODE_ALWAYS           (2<<1)
+        #define PM3RD_VideoOverlayControl_MODE_BLEND            (3<<1)
+        #define PM3RD_VideoOverlayControl_DIRECTCOLOR_DISABLED  (0<<3)
+        #define PM3RD_VideoOverlayControl_DIRECTCOLOR_ENABLED   (1<<3)
+        #define PM3RD_VideoOverlayControl_BLENDSRC_MAIN         (0<<4)
+        #define PM3RD_VideoOverlayControl_BLENDSRC_REGISTER     (1<<4)
+        #define PM3RD_VideoOverlayControl_KEY_COLOR             (0<<5)
+        #define PM3RD_VideoOverlayControl_KEY_ALPHA             (1<<5)
+#define PM3RD_VideoOverlayXStartLow				0x021
+#define PM3RD_VideoOverlayXStartHigh				0x022
+#define PM3RD_VideoOverlayYStartLow				0x023
+#define PM3RD_VideoOverlayYStartHigh				0x024
+#define PM3RD_VideoOverlayXEndLow				0x025
+#define PM3RD_VideoOverlayXEndHigh				0x026
+#define PM3RD_VideoOverlayYEndLow				0x027
+#define PM3RD_VideoOverlayYEndHigh				0x028
+#define PM3RD_VideoOverlayKeyR					0x029
+#define PM3RD_VideoOverlayKeyG					0x02a
+#define PM3RD_VideoOverlayKeyB					0x02b
+#define PM3RD_VideoOverlayBlend					0x02c
+        #define PM3RD_VideoOverlayBlend_FACTOR_0_PERCENT        (0<<6)
+        #define PM3RD_VideoOverlayBlend_FACTOR_25_PERCENT       (1<<6)
+        #define PM3RD_VideoOverlayBlend_FACTOR_75_PERCENT       (2<<6)
+        #define PM3RD_VideoOverlayBlend_FACTOR_100_PERCENT      (3<<6)
+
+#define PM3RD_DClkSetup1					0x1f0
+#define PM3RD_DClkSetup2					0x1f1
+#define PM3RD_KClkSetup1					0x1f2
+#define PM3RD_KClkSetup2					0x1f3
+
+#define PM3RD_DClkControl					0x200
+	#define PM3RD_DClkControl_SOURCE_PLL			(0<<4)
+	#define PM3RD_DClkControl_SOURCE_VSA			(1<<4)
+	#define PM3RD_DClkControl_SOURCE_VSB			(2<<4)
+	#define PM3RD_DClkControl_SOURCE_EXT			(3<<4)
+	#define PM3RD_DClkControl_STATE_RUN			(2<<2)
+	#define PM3RD_DClkControl_STATE_HIGH			(1<<2)
+	#define PM3RD_DClkControl_STATE_LOW			(0<<2)
+	#define PM3RD_DClkControl_LOCKED			(1<<1)
+	#define PM3RD_DClkControl_NOT_LOCKED			(0<<1)
+	#define PM3RD_DClkControl_ENABLE			(1<<0)
+	#define PM3RD_DClkControl_DISABLE			(0<<0)
+#define PM3RD_DClk0PreScale					0x201
+#define PM3RD_DClk0FeedbackScale				0x202
+#define PM3RD_DClk0PostScale					0x203
+        #define PM3_REF_CLOCK                                   14318
+#define PM3RD_DClk1PreScale					0x204
+#define PM3RD_DClk1FeedbackScale				0x205
+#define PM3RD_DClk1PostScale					0x206
+#define PM3RD_DClk2PreScale					0x207
+#define PM3RD_DClk2FeedbackScale				0x208
+#define PM3RD_DClk2PostScale					0x209
+#define PM3RD_DClk3PreScale					0x20a
+#define PM3RD_DClk3FeedbackScale				0x20b
+#define PM3RD_DClk3PostScale					0x20c
+#define PM3RD_KClkControl					0x20d
+	#define PM3RD_KClkControl_DISABLE			(0<<0)
+	#define PM3RD_KClkControl_ENABLE			(1<<0)
+	#define PM3RD_KClkControl_NOT_LOCKED			(0<<1)
+	#define PM3RD_KClkControl_LOCKED			(1<<1)
+	#define PM3RD_KClkControl_STATE_LOW			(0<<2)
+	#define PM3RD_KClkControl_STATE_HIGH			(1<<2)
+	#define PM3RD_KClkControl_STATE_RUN			(2<<2)
+	#define PM3RD_KClkControl_STATE_LOW_POWER		(3<<2)
+	#define PM3RD_KClkControl_SOURCE_PCLK			(0<<4)
+	#define PM3RD_KClkControl_SOURCE_HALF_PCLK		(1<<4)
+	#define PM3RD_KClkControl_SOURCE_PLL			(2<<4)
+#define PM3RD_KClkPreScale					0x20e
+#define PM3RD_KClkFeedbackScale					0x20f
+#define PM3RD_KClkPostScale					0x210
+#define PM3RD_MClkControl					0x211
+	#define PM3RD_MClkControl_DISABLE			(0<<0)
+	#define PM3RD_MClkControl_ENABLE			(1<<0)
+	#define PM3RD_MClkControl_NOT_LOCKED			(0<<1)
+	#define PM3RD_MClkControl_LOCKED			(1<<1)
+	#define PM3RD_MClkControl_STATE_LOW			(0<<2)
+	#define PM3RD_MClkControl_STATE_HIGH			(1<<2)
+	#define PM3RD_MClkControl_STATE_RUN			(2<<2)
+	#define PM3RD_MClkControl_STATE_LOW_POWER		(3<<2)
+	#define PM3RD_MClkControl_SOURCE_PCLK			(0<<4)
+	#define PM3RD_MClkControl_SOURCE_HALF_PCLK		(1<<4)
+	#define PM3RD_MClkControl_SOURCE_HALF_EXT		(3<<4)
+	#define PM3RD_MClkControl_SOURCE_EXT			(4<<4)
+	#define PM3RD_MClkControl_SOURCE_HALF_KCLK		(5<<4)
+	#define PM3RD_MClkControl_SOURCE_KCLK			(6<<4)
+#define PM3RD_MClkPreScale					0x212
+#define PM3RD_MClkFeedbackScale					0x213
+#define PM3RD_MClkPostScale					0x214
+#define PM3RD_SClkControl					0x215
+	#define PM3RD_SClkControl_DISABLE			(0<<0)
+	#define PM3RD_SClkControl_ENABLE			(1<<0)
+	#define PM3RD_SClkControl_NOT_LOCKED			(0<<1)
+	#define PM3RD_SClkControl_LOCKED			(1<<1)
+	#define PM3RD_SClkControl_STATE_LOW			(0<<2)
+	#define PM3RD_SClkControl_STATE_HIGH			(1<<2)
+	#define PM3RD_SClkControl_STATE_RUN			(2<<2)
+	#define PM3RD_SClkControl_STATE_LOW_POWER		(3<<2)
+	#define PM3RD_SClkControl_SOURCE_PCLK			(0<<4)
+	#define PM3RD_SClkControl_SOURCE_HALF_PCLK		(1<<4)
+	#define PM3RD_SClkControl_SOURCE_HALF_EXT		(3<<4)
+	#define PM3RD_SClkControl_SOURCE_EXT			(4<<4)
+	#define PM3RD_SClkControl_SOURCE_HALF_KCLK		(5<<4)
+	#define PM3RD_SClkControl_SOURCE_KCLK			(6<<4)
+#define PM3RD_SClkPreScale					0x216
+#define PM3RD_SClkFeedbackScale					0x217
+#define PM3RD_SClkPostScale					0x218
+
+#define PM3RD_CursorPalette(p)					(0x303+(p))
+#define PM3RD_CursorPattern(p)					(0x400+(p))
+/******************************************************
+*  GLINT Permedia3 Video Streaming Registers (0x5000) *
+*******************************************************/
+
+#define PM3VSConfiguration					0x5800
+
+/**********************************************
+*  GLINT Permedia3 Core Registers (0x8000+)   *
+***********************************************/
+#define PM3AALineWidth						0x94c0
+#define PM3AAPointsize						0x94a0
+#define PM3AlphaBlendAlphaMode					0xafa8
+#define PM3AlphaBlendAlphaModeAnd				0xad30
+#define PM3AlphaBlendAlphaModeOr				0xad38
+#define PM3AlphaBlendColorMode					0xafa0
+#define PM3AlphaBlendColorModeAnd				0xacb0
+#define PM3AlphaBlendColorModeOr				0xacb8
+#define PM3AlphaDestColor					0xaf88
+#define PM3AlphaSourceColor					0xaf80
+#define PM3AlphaTestMode					0x8800
+#define PM3AlphaTestModeAnd					0xabf0
+#define PM3AlphaTestModeOr					0xabf8
+#define PM3AntialiasMode					0x8808
+#define PM3AntialiasModeAnd					0xac00
+#define PM3AntialiasModeOr					0xac08
+/* ... */
+#define PM3BackgroundColor					0xb0c8
+/* ... */
+#define PM3ColorDDAMode						0x87e0
+#define PM3ColorDDAModeAnd					0xabe0
+#define PM3ColorDDAModeOr					0xabe8
+#define PM3CommandInterrupt					0xa990
+#define PM3ConstantColorDDA					0xafb0
+	#define PM3ConstantColorDDA_R(r)		((r)&0xff)
+	#define PM3ConstantColorDDA_G(g)		(((g)&0xff)<<8)
+	#define PM3ConstantColorDDA_B(b)		(((b)&0xff)<<16)
+	#define PM3ConstantColorDDA_A(a)		(((a)&0xff)<<24)
+#define PM3ContextData						0x8dd0
+#define PM3ContextDump						0x8dc0
+#define PM3ContextRestore					0x8dc8
+#define PM3Continue						0x8058
+#define PM3ContinueNewDom					0x8048
+#define PM3ContinueNewLine					0x8040
+#define PM3ContinueNewSub					0x8050
+#define PM3Count						0x8030
+/* ... */
+#define PM3DeltaControl						0x9350
+#define PM3DeltaControlAnd					0xab20
+#define PM3DeltaControlOr					0xab28
+#define PM3DeltaMode						0x9300
+#define PM3DeltaModeAnd						0xaad0
+#define PM3DeltaModeOr						0xaad8
+/* ... */
+#define PM3DitherMode						0x8818
+#define PM3DitherModeAnd					0xacd0
+#define PM3DitherModeOr						0xacd8
+/* ... */
+#define PM3dXDom						0x8008
+#define PM3dXSub						0x8018
+#define PM3dY							0x8028
+/* ... */
+#define PM3FBBlockColor						0x8ac8
+#define PM3FBBlockColor0					0xb060
+#define PM3FBBlockColor1					0xb068
+#define PM3FBBlockColor2					0xb070
+#define PM3FBBlockColor3					0xb078
+#define PM3FBBlockColorBack					0xb0a0
+#define PM3FBBlockColorBack0					0xb080
+#define PM3FBBlockColorBack1					0xb088
+#define PM3FBBlockColorBack2					0xb090
+#define PM3FBBlockColorBack3					0xb098
+#define PM3FBColor						0x8a98
+#define PM3FBDestReadBufferAddr0				0xae80
+#define PM3FBDestReadBufferAddr1				0xae88
+#define PM3FBDestReadBufferAddr2				0xae90
+#define PM3FBDestReadBufferAddr3				0xae98
+#define PM3FBDestReadBufferOffset0				0xaea0
+#define PM3FBDestReadBufferOffset1				0xaea8
+#define PM3FBDestReadBufferOffset2				0xaeb0
+#define PM3FBDestReadBufferOffset3				0xaeb8
+	#define PM3FBDestReadBufferOffset_XOffset(x)	((x)&0xffff)
+	#define PM3FBDestReadBufferOffset_YOffset(y)	(((y)&0xffff)<<16)
+#define PM3FBDestReadBufferWidth0				0xaec0
+#define PM3FBDestReadBufferWidth1				0xaec8
+#define PM3FBDestReadBufferWidth2				0xaed0
+#define PM3FBDestReadBufferWidth3				0xaed8
+	#define PM3FBDestReadBufferWidth_Width(w)	((w)&0x0fff)
+
+#define PM3FBDestReadEnables					0xaee8
+#define PM3FBDestReadEnablesAnd					0xad20
+#define PM3FBDestReadEnablesOr					0xad28
+	#define PM3FBDestReadEnables_E(e)		((e)&0xff)
+	#define PM3FBDestReadEnables_E0				1<<0
+	#define PM3FBDestReadEnables_E1				1<<1
+	#define PM3FBDestReadEnables_E2				1<<2
+	#define PM3FBDestReadEnables_E3				1<<3
+	#define PM3FBDestReadEnables_E4				1<<4
+	#define PM3FBDestReadEnables_E5				1<<5
+	#define PM3FBDestReadEnables_E6				1<<6
+	#define PM3FBDestReadEnables_E7				1<<7
+	#define PM3FBDestReadEnables_R(r)		(((r)&0xff)<<8)
+	#define PM3FBDestReadEnables_R0				1<<8
+	#define PM3FBDestReadEnables_R1				1<<9
+	#define PM3FBDestReadEnables_R2				1<<10
+	#define PM3FBDestReadEnables_R3				1<<11
+	#define PM3FBDestReadEnables_R4				1<<12
+	#define PM3FBDestReadEnables_R5				1<<13
+	#define PM3FBDestReadEnables_R6				1<<14
+	#define PM3FBDestReadEnables_R7				1<<15
+	#define PM3FBDestReadEnables_ReferenceAlpha(a)	(((a)&0xff)<<24)
+
+#define PM3FBDestReadMode					0xaee0
+#define PM3FBDestReadModeAnd					0xac90
+#define PM3FBDestReadModeOr					0xac98
+	#define PM3FBDestReadMode_ReadDisable			0<<0
+	#define PM3FBDestReadMode_ReadEnable			1<<0
+	#define PM3FBDestReadMode_StripePitch(sp)	(((sp)&0x7)<<2
+	#define PM3FBDestReadMode_StripeHeight(sh)	(((sh)&0x7)<<7
+	#define PM3FBDestReadMode_Enable0			1<<8
+	#define PM3FBDestReadMode_Enable1			1<<9
+	#define PM3FBDestReadMode_Enable2			1<<10
+	#define PM3FBDestReadMode_Enable3			1<<11
+	#define PM3FBDestReadMode_Layout0(l)		(((l)&0x3)<<12
+	#define PM3FBDestReadMode_Layout1(l)		(((l)&0x3)<<14
+	#define PM3FBDestReadMode_Layout2(l)		(((l)&0x3)<<16
+	#define PM3FBDestReadMode_Layout3(l)		(((l)&0x3)<<18
+	#define PM3FBDestReadMode_Origin0			1<<20
+	#define PM3FBDestReadMode_Origin1			1<<21
+	#define PM3FBDestReadMode_Origin2			1<<22
+	#define PM3FBDestReadMode_Origin3			1<<23
+	#define PM3FBDestReadMode_Blocking			1<<24
+	#define PM3FBDestReadMode_UseReadEnabled		1<<26
+	#define PM3FBDestReadMode_AlphaFiltering		1<<27
+
+#define PM3FBHardwareWriteMask					0x8ac0
+#define PM3FBSoftwareWriteMask					0x8820
+#define PM3FBData						0x8aa0
+#define PM3FBSourceData						0x8aa8
+#define PM3FBSourceReadBufferAddr				0xaf08
+#define PM3FBSourceReadBufferOffset				0xaf10
+	#define PM3FBSourceReadBufferOffset_XOffset(x)	((x)&0xffff)
+	#define PM3FBSourceReadBufferOffset_YOffset(y)	(((y)&0xffff)<<16)
+#define PM3FBSourceReadBufferWidth				0xaf18
+	#define PM3FBSourceReadBufferWidth_Width(w)	((w)&0x0fff)
+#define PM3FBSourceReadMode					0xaf00
+#define PM3FBSourceReadModeAnd					0xaca0
+#define PM3FBSourceReadModeOr					0xaca8
+	#define PM3FBSourceReadMode_ReadDisable			(0<<0)
+	#define PM3FBSourceReadMode_ReadEnable			(1<<0)
+	#define PM3FBSourceReadMode_StripePitch(sp)	(((sp)&0x7)<<2
+	#define PM3FBSourceReadMode_StripeHeight(sh)	(((sh)&0x7)<<7
+	#define PM3FBSourceReadMode_Layout(l)		(((l)&0x3)<<8
+	#define PM3FBSourceReadMode_Origin			1<<10
+	#define PM3FBSourceReadMode_Blocking			1<<11
+	#define PM3FBSourceReadMode_UserTexelCoord		1<<13
+	#define PM3FBSourceReadMode_WrapXEnable			1<<14
+	#define PM3FBSourceReadMode_WrapYEnable			1<<15
+	#define PM3FBSourceReadMode_WrapX(w)		(((w)&0xf)<<16
+	#define PM3FBSourceReadMode_WrapY(w)		(((w)&0xf)<<20
+	#define PM3FBSourceReadMode_ExternalSourceData		1<<24
+#define PM3FBWriteBufferAddr0                                   0xb000
+#define PM3FBWriteBufferAddr1                                   0xb008
+#define PM3FBWriteBufferAddr2                                   0xb010
+#define PM3FBWriteBufferAddr3                                   0xb018
+
+#define PM3FBWriteBufferOffset0                                 0xb020
+#define PM3FBWriteBufferOffset1                                 0xb028
+#define PM3FBWriteBufferOffset2                                 0xb030
+#define PM3FBWriteBufferOffset3                                 0xb038
+	#define PM3FBWriteBufferOffset_XOffset(x)		((x)&0xffff)
+	#define PM3FBWriteBufferOffset_YOffset(y)		(((y)&0xffff)<<16)
+
+#define PM3FBWriteBufferWidth0                                  0xb040
+#define PM3FBWriteBufferWidth1                                  0xb048
+#define PM3FBWriteBufferWidth2                                  0xb050
+#define PM3FBWriteBufferWidth3                                  0xb058
+	#define PM3FBWriteBufferWidth_Width(w)			((w)&0x0fff)
+
+#define PM3FBWriteMode                                          0x8ab8
+#define PM3FBWriteModeAnd                                       0xacf0
+#define PM3FBWriteModeOr                                        0xacf8
+	#define PM3FBWriteMode_WriteDisable                     0<<0
+	#define PM3FBWriteMode_WriteEnable                      1<<0
+	#define PM3FBWriteMode_Replicate                        1<<4
+	#define PM3FBWriteMode_OpaqueSpan                       1<<5
+	#define PM3FBWriteMode_StripePitch(p)            (((p)&0x7)<<6)
+	#define PM3FBWriteMode_StripeHeight(h)           (((h)&0x7)<<9)
+	#define PM3FBWriteMode_Enable0                          1<<12
+	#define PM3FBWriteMode_Enable1                          1<<13
+	#define PM3FBWriteMode_Enable2                          1<<14
+	#define PM3FBWriteMode_Enable3                          1<<15
+	#define PM3FBWriteMode_Layout0(l)               (((l)&0x3)<<16)
+	#define PM3FBWriteMode_Layout1(l)               (((l)&0x3)<<18)
+	#define PM3FBWriteMode_Layout2(l)               (((l)&0x3)<<20)
+	#define PM3FBWriteMode_Layout3(l)               (((l)&0x3)<<22)
+	#define PM3FBWriteMode_Origin0                          1<<24
+	#define PM3FBWriteMode_Origin1                          1<<25
+	#define PM3FBWriteMode_Origin2                          1<<26
+	#define PM3FBWriteMode_Origin3                          1<<27
+#define PM3ForegroundColor					0xb0c0
+/* ... */
+#define PM3GIDMode						0xb538
+#define PM3GIDModeAnd						0xb5b0
+#define PM3GIDModeOr						0xb5b8
+/* ... */
+#define PM3LBDestReadBufferAddr					0xb510
+#define PM3LBDestReadBufferOffset				0xb518
+#define PM3LBDestReadEnables					0xb508
+#define PM3LBDestReadEnablesAnd					0xb590
+#define PM3LBDestReadEnablesOr					0xb598
+#define PM3LBDestReadMode					0xb500
+#define PM3LBDestReadModeAnd					0xb580
+#define PM3LBDestReadModeOr					0xb588
+	#define PM3LBDestReadMode_Disable			0<<0
+	#define PM3LBDestReadMode_Enable			1<<0
+	#define PM3LBDestReadMode_StripePitch(p)		(((p)&0x7)<<2)
+	#define PM3LBDestReadMode_StripeHeight(h)		(((h)&0x7)<<5)
+	#define PM3LBDestReadMode_Layout			1<<8
+	#define PM3LBDestReadMode_Origin			1<<9
+	#define PM3LBDestReadMode_UserReadEnables		1<<10
+	#define PM3LBDestReadMode_Packed16			1<<11
+	#define PM3LBDestReadMode_Width(w)			(((w)&0xfff)<<12)
+#define PM3LBReadFormat						0x8888
+	#define PM3LBReadFormat_DepthWidth(w)			(((w)&0x3)<<0)
+	#define PM3LBReadFormat_StencilWidth(w)			(((w)&0xf)<<2)
+	#define PM3LBReadFormat_StencilPosition(p)		(((p)&0x1f)<<6)
+	#define PM3LBReadFormat_FCPWidth(w)			(((w)&0xf)<<11)
+	#define PM3LBReadFormat_FCPPosition(p)			(((p)&0x1f)<<15)
+	#define PM3LBReadFormat_GIDWidth(w)			(((w)&0x7)<<20)
+	#define PM3LBReadFormat_GIDPosition(p)			(((p)&0x1f)<<23)
+#define PM3LBSourceReadBufferAddr				0xb528
+#define PM3LBSourceReadBufferOffset				0xb530
+#define PM3LBSourceReadMode					0xb520
+#define PM3LBSourceReadModeAnd					0xb5a0
+#define PM3LBSourceReadModeOr					0xb5a8
+	#define PM3LBSourceReadMode_Enable			1<<0
+	#define PM3LBSourceReadMode_StripePitch(p)		(((p)&0x7)<<2)
+	#define PM3LBSourceReadMode_StripeHeight(h)		(((h)&0x7)<<5)
+	#define PM3LBSourceReadMode_Layout			1<<8
+	#define PM3LBSourceReadMode_Origin			1<<9
+	#define PM3LBSourceReadMode_Packed16			1<<10
+	#define PM3LBSourceReadMode_Width(w)			(((w)&0xfff)<<11)
+#define PM3LBStencil						0x88a8
+#define PM3LBWriteBufferAddr					0xb540
+#define PM3LBWriteBufferOffset					0xb548
+#define PM3LBWriteFormat					0x88c8
+	#define PM3LBWriteFormat_DepthWidth(w)			(((w)&0x3)<<0)
+	#define PM3LBWriteFormat_StencilWidth(w)		(((w)&0xf)<<2)
+	#define PM3LBWriteFormat_StencilPosition(p)		(((p)&0x1f)<<6)
+	#define PM3LBWriteFormat_GIDWidth(w)			(((w)&0x7)<<20)
+	#define PM3LBWriteFormat_GIDPosition(p)			(((p)&0x1f)<<23)
+#define PM3LBWriteMode						0x88c0
+#define PM3LBWriteModeAnd					0xac80
+#define PM3LBWriteModeOr					0xac88
+	#define PM3LBWriteMode_WriteDisable			0<<0
+	#define PM3LBWriteMode_WriteEnable			1<<0
+	#define PM3LBWriteMode_StripePitch(p)			(((p)&0x7)<<3)
+	#define PM3LBWriteMode_StripeHeight(h)			(((h)&0x7)<<6)
+	#define PM3LBWriteMode_Layout				1<<9
+	#define PM3LBWriteMode_Origin				1<<10
+	#define PM3LBWriteMode_Packed16				1<<11
+	#define PM3LBWriteMode_Width(w)				(((w)&0xfff)<<12)
+/* ... */
+#define PM3LineStippleMode					0x81a8
+#define PM3LineStippleModeAnd					0xabc0
+#define PM3LineStippleModeOr					0xabc8
+#define PM3LoadLineStippleCounters				0x81b0
+/* ... */
+#define PM3LogicalOpMode					0x8828
+#define PM3LogicalOpModeAnd					0xace0
+#define PM3LogicalOpModeOr					0xace8
+	#define PM3LogicalOpMode_Disable			(0<<0)
+	#define PM3LogicalOpMode_Enable				(1<<0)
+	#define PM3LogicalOpMode_LogicOp(op)			(((op)&0xf)<<1)
+	#define PM3LogicalOpMode_UseConstantWriteData_Disable	(0<<5)
+	#define PM3LogicalOpMode_UseConstantWriteData_Enable	(1<<5)
+	#define PM3LogicalOpMode_Background_Disable		(0<<6)
+	#define PM3LogicalOpMode_Background_Enable		(1<<6)
+	#define PM3LogicalOpMode_Background_LogicOp(op)		(((op)&0xf)<<7)
+	#define PM3LogicalOpMode_UseConstantSource_Disable	(0<<11)
+	#define PM3LogicalOpMode_UseConstantSource_Enable	(1<<11)
+
+/* ... */
+#define PM3LUT							0x8e80
+/* ... */
+#define PM3LUT							0x8e80
+#define PM3LUTAddress						0x84d0
+#define PM3LUTData						0x84c8
+#define PM3LUTIndex						0x84c0
+#define PM3LUTMode						0xb378
+#define PM3LUTModeAnd						0xad70
+#define PM3LUTModeOr						0xad78
+#define PM3LUTTransfer						0x84d8
+/* ... */
+#define PM3PixelSize						0x80c0
+	#define PM3PixelSize_GLOBAL_32BIT			(0<<0)
+	#define PM3PixelSize_GLOBAL_16BIT			(1<<0)
+	#define PM3PixelSize_GLOBAL_8BIT			(2<<0)
+	#define PM3PixelSize_RASTERIZER_32BIT			(0<<2)
+	#define PM3PixelSize_RASTERIZER_16BIT			(1<<2)
+	#define PM3PixelSize_RASTERIZER_8BIT			(2<<2)
+	#define PM3PixelSize_SCISSOR_AND_STIPPLE_32BIT		(0<<4)
+	#define PM3PixelSize_SCISSOR_AND_STIPPLE_16BIT		(1<<4)
+	#define PM3PixelSize_SCISSOR_AND_STIPPLE_8BIT		(2<<4)
+	#define PM3PixelSize_TEXTURE_32BIT			(0<<6)
+	#define PM3PixelSize_TEXTURE_16BIT			(1<<6)
+	#define PM3PixelSize_TEXTURE_8BIT			(2<<6)
+	#define PM3PixelSize_LUT_32BIT				(0<<8)
+	#define PM3PixelSize_LUT_16BIT				(1<<8)
+	#define PM3PixelSize_LUT_8BIT				(2<<8)
+	#define PM3PixelSize_FRAMEBUFFER_32BIT			(0<<10)
+	#define PM3PixelSize_FRAMEBUFFER_16BIT			(1<<10)
+	#define PM3PixelSize_FRAMEBUFFER_8BIT			(2<<10)
+	#define PM3PixelSize_LOGICAL_OP_32BIT			(0<<12)
+	#define PM3PixelSize_LOGICAL_OP_16BIT			(1<<12)
+	#define PM3PixelSize_LOGICAL_OP_8BIT			(2<<12)
+	#define PM3PixelSize_LOCALBUFFER_32BIT			(0<<14)
+	#define PM3PixelSize_LOCALBUFFER_16BIT			(1<<14)
+	#define PM3PixelSize_LOCALBUFFER_8BIT			(2<<14)
+	#define PM3PixelSize_SETUP_32BIT			(0<<16)
+	#define PM3PixelSize_SETUP_16BIT			(1<<16)
+	#define PM3PixelSize_SETUP_8BIT				(2<<16)
+	#define PM3PixelSize_GLOBAL				(0<<31)
+	#define PM3PixelSize_INDIVIDUAL				(1<<31)
+/* ... */
+#define PM3Render						0x8038
+	#define PM3Render_AreaStipple_Disable			(0<<0)
+	#define PM3Render_AreaStipple_Enable			(1<<0)
+	#define PM3Render_LineStipple_Disable			(0<<1)
+	#define PM3Render_LineStipple_Enable			(1<<1)
+	#define PM3Render_ResetLine_Disable			(0<<2)
+	#define PM3Render_ResetLine_Enable			(1<<2)
+	#define PM3Render_FastFill_Disable			(0<<3)
+	#define PM3Render_FastFill_Enable			(1<<3)
+	#define PM3Render_Primitive_Line			(0<<6)
+	#define PM3Render_Primitive_Trapezoid			(1<<6)
+	#define PM3Render_Primitive_Point			(2<<6)
+	#define PM3Render_Antialias_Disable			(0<<8)
+	#define PM3Render_Antialias_Enable			(1<<8)
+	#define PM3Render_Antialias_SubPixelRes_4x4		(0<<9)
+	#define PM3Render_Antialias_SubPixelRes_8x8		(1<<9)
+	#define PM3Render_UsePointTable_Disable			(0<<10)
+	#define PM3Render_UsePointTable_Enable			(1<<10)
+	#define PM3Render_SyncOnbitMask_Disable			(0<<11)
+	#define PM3Render_SyncOnBitMask_Enable			(1<<11)
+	#define PM3Render_SyncOnHostData_Disable		(0<<12)
+	#define PM3Render_SyncOnHostData_Enable			(1<<12)
+	#define PM3Render_Texture_Disable			(0<<13)
+	#define PM3Render_Texture_Enable			(1<<13)
+	#define PM3Render_Fog_Disable				(0<<14)
+	#define PM3Render_Fog_Enable				(1<<14)
+	#define PM3Render_Coverage_Disable			(0<<15)
+	#define PM3Render_Coverage_Enable			(1<<15)
+	#define PM3Render_SubPixelCorrection_Disable		(0<<16)
+	#define PM3Render_SubPixelCorrection_Enable		(1<<16)
+	#define PM3Render_SpanOperation_Disable			(0<<18)
+	#define PM3Render_SpanOperation_Enable			(1<<18)
+	#define PM3Render_FBSourceRead_Disable			(0<<27)
+	#define PM3Render_FBSourceRead_Enable			(1<<27)
+#define PM3RasterizerMode					0x80a0
+#define PM3RasterizerModeAnd					0xaba0
+#define PM3RasterizerModeOr					0xabb8
+#define PM3RectangleHeight					0x94e0
+#define PM3Render						0x8038
+#define PM3RepeatLine						0x9328
+#define PM3ResetPickResult					0x8c20
+#define PM3RLEMask						0x8c48
+#define PM3RouterMode						0x8840
+#define PM3RStart						0x8780
+#define PM3S1Start						0x8400
+#define PM3aveLineStippleCounters				0x81c0
+#define PM3ScissorMaxXY						0x8190
+#define PM3ScissorMinXY						0x8188
+#define PM3ScissorMode						0x8180
+#define PM3ScissorModeAnd					0xabb0
+#define PM3ScissorModeOr					0xabb8
+#define PM3ScreenSize						0x8198
+#define PM3Security						0x8908
+#define PM3SetLogicalTexturePage				0xb360
+#define PM3SizeOfFramebuffer					0xb0a8
+#define PM3SStart						0x8388
+#define PM3StartXDom						0x8000
+#define PM3StartXSub						0x8010
+#define PM3StartY						0x8020
+/* ... */
+#define PM3SpanColorMask					0x8168
+/* ... */
+#define PM3TextureApplicationMode				0x8680
+#define PM3TextureApplicationModeAnd				0xac50
+#define PM3TextureApplicationModeOr				0xac58
+#define PM3TextureBaseAddr					0x8500
+#define PM3TextureCacheControl					0x8490
+#define PM3TextureChromaLower0					0x84f0
+#define PM3TextureChromaLower1					0x8608
+#define PM3TextureChromaUpper0					0x84e8
+#define PM3TextureChromaUpper1					0x8600
+#define PM3TextureCompositeAlphaMode0				0xb310
+#define PM3TextureCompositeAlphaMode0And			0xb390
+#define PM3TextureCompositeAlphaMode0Or				0xb398
+#define PM3TextureCompositeAlphaMode1				0xb320
+#define PM3TextureCompositeAlphaMode1And			0xb3b0
+#define PM3TextureCompositeAlphaMode1Or				0xb3b8
+#define PM3TextureCompositeColorMode0				0xb308
+#define PM3TextureCompositeColorMode0And			0xb380
+#define PM3TextureCompositeColorMode0Or				0xb388
+#define PM3TextureCompositeColorMode1				0xb318
+#define PM3TextureCompositeColorMode1And			0xb3a0
+#define PM3TextureCompositeColorMode1Or				0xb3a8
+#define PM3TextureCompositeFactor0				0xb328
+#define PM3TextureCompositeFactor1				0xb330
+#define PM3TextureCompositeMode					0xb300
+#define PM3TextureCoordMode					0x8380
+#define PM3TextureCoordModeAnd					0xac20
+#define PM3TextureCoordModeOr					0xac28
+#define PM3TextureData						0x88e8
+/*
+#define PM3TextureDownloadControl				0x0108
+*/
+#define PM3TextureDownloadOffset				0x88f0
+#define PM3TextureEnvColor					0x8688
+#define PM3TextureFilterMode					0x84e0
+#define PM3TextureFilterModeAnd					0xad50
+#define PM3TextureFilterModeOr					0xad58
+#define PM3TextureIndexMode0					0xb338
+#define PM3TextureIndexMode0And					0xb3c0
+#define PM3TextureIndexMode0Or					0xb3c8
+#define PM3TextureIndexMode1					0xb340
+#define PM3TextureIndexMode1And					0xb3d0
+#define PM3TextureIndexMode1Or					0xb3d8
+/* ... */
+#define PM3TextureMapSize                                       0xb428
+#define PM3TextureMapWidth0                                     0x8580
+#define PM3TextureMapWidth1                                     0x8588
+        #define PM3TextureMapWidth_Width(w)             ((w&0xfff)<<0)
+        #define PM3TextureMapWidth_BorderLayout                 (1<<12)
+        #define PM3TextureMapWidth_Layout_Linear                (0<<13)
+        #define PM3TextureMapWidth_Layout_Patch64               (1<<13)
+        #define PM3TextureMapWidth_Layout_Patch32_2             (2<<13)
+        #define PM3TextureMapWidth_Layout_Patch2                (3<<13)
+        #define PM3TextureMapWidth_HostTexture                  (1<<15)
+#define PM3TextureReadMode0                                     0xb400
+#define PM3TextureReadMode0And                                  0xac30
+#define PM3TextureReadMode0Or                                   0xac38
+#define PM3TextureReadMode1                                     0xb408
+#define PM3TextureReadMode1And                                  0xad40
+#define PM3TextureReadMode1Or                                   0xad48
+/* ... */
+#define PM3WaitForCompletion					0x80b8
+#define PM3Window						0x8980
+	#define PM3Window_ForceLBUpdate				1<<3
+	#define PM3Window_LBUpdateSource			1<<4
+	#define PM3Window_FrameCount(c)				(((c)&0xff)<<9
+	#define PM3Window_StencilFCP				1<<17
+	#define PM3Window_DepthFCP				1<<18
+	#define PM3Window_OverrideWriteFiltering		1<<19
+#define PM3WindowAnd						0xab80
+#define PM3WindowOr						0xab88
+#define PM3WindowOrigin						0x81c8
+#define PM3XBias						0x9480
+#define PM3YBias						0x9488
+#define PM3YLimits						0x80a8
+#define PM3UVMode						0x8f00
+#define PM3ZFogBias						0x86b8
+#define PM3ZStart						0xadd8
+#define PM3ZStartL						0x89b8
+#define PM3ZStartU						0x89b0
+
+
+/**********************************************
+*  GLINT Permedia3 2D setup Unit              *
+***********************************************/
+#define PM3Config2D						0xb618
+	#define PM3Config2D_OpaqueSpan				1<<0
+	#define PM3Config2D_MultiRXBlit				1<<1
+	#define PM3Config2D_UserScissorEnable			1<<2
+	#define PM3Config2D_FBDestReadEnable			1<<3
+	#define PM3Config2D_AlphaBlendEnable			1<<4
+	#define PM3Config2D_DitherEnable			1<<5
+	#define PM3Config2D_ForegroundROPEnable			1<<6
+	#define PM3Config2D_ForegroundROP(rop)		(((rop)&0xf)<<7)
+	#define PM3Config2D_BackgroundROPEnable			1<<11
+	#define PM3Config2D_BackgroundROP(rop)		(((rop)&0xf)<<12)
+	#define PM3Config2D_UseConstantSource			1<<16
+	#define PM3Config2D_FBWriteEnable			1<<17
+	#define PM3Config2D_Blocking				1<<18
+	#define PM3Config2D_ExternalSourceData			1<<19
+	#define PM3Config2D_LUTModeEnable			1<<20
+#define PM3DownloadGlyphwidth					0xb658
+	#define PM3DownloadGlyphwidth_GlyphWidth(gw)	((gw)&0xffff)
+#define PM3DownloadTarget					0xb650
+	#define PM3DownloadTarget_TagName(tag)		((tag)&0x1fff)
+#define PM3GlyphData						0xb660
+#define PM3GlyphPosition					0xb608
+	#define PM3GlyphPosition_XOffset(x)		((x)&0xffff)
+	#define PM3GlyphPosition_YOffset(y)		(((y)&0xffff)<<16)
+#define PM3Packed4Pixels					0xb668
+#define PM3Packed8Pixels					0xb630
+#define PM3Packed16Pixels					0xb638
+#define PM3RectanglePosition					0xb600
+	#define PM3RectanglePosition_XOffset(x)		((x)&0xffff)
+	#define PM3RectanglePosition_YOffset(y)		(((y)&0xffff)<<16)
+#define PM3Render2D						0xb640
+	#define PM3Render2D_Width(w)			((w)&0x0fff)
+	#define PM3Render2D_Operation_Normal			0<<12
+	#define PM3Render2D_Operation_SyncOnHostData		1<<12
+	#define PM3Render2D_Operation_SyncOnBitMask		2<<12
+	#define PM3Render2D_Operation_PatchOrderRendering	3<<12
+	#define PM3Render2D_FBSourceReadEnable			1<<14
+	#define PM3Render2D_SpanOperation			1<<15
+	#define PM3Render2D_Height(h)			(((h)&0x0fff)<<16)
+	#define PM3Render2D_XPositive				1<<28
+	#define PM3Render2D_YPositive				1<<29
+	#define PM3Render2D_AreaStippleEnable			1<<30
+	#define PM3Render2D_TextureEnable			1<<31
+#define PM3Render2DGlyph					0xb648
+	#define PM3Render2DGlyph_Width(w)		((w)&0x7f)
+	#define PM3Render2DGlyph_Height(h)		(((h)&0x7f)<<7)
+	#define PM3Render2DGlyph_XOffset(x)		(((x)&0x1ff)<<14)
+	#define PM3Render2DGlyph_YOffset(y)		(((y)&0x1ff)<<23)
+#define PM3RenderPatchOffset					0xb610
+	#define PM3RenderPatchOffset_XOffset(x)		((x)&0xffff)
+	#define PM3RenderPatchOffset_YOffset(y)		(((y)&0xffff)<<16)
+#define PM3RLCount						0xb678
+	#define PM3RLCount_Count(c)			((c)&0x0fff)
+#define PM3RLData						0xb670
+
+/**********************************************
+*  GLINT Permedia3 Alias Register             *
+***********************************************/
+#define PM3FillBackgroundColor                                  0x8330
+#define PM3FillConfig2D0                                        0x8338
+#define PM3FillConfig2D1                                        0x8360
+	#define PM3FillConfig2D_OpaqueSpan                      1<<0
+	#define PM3FillConfig2D_MultiRXBlit                     1<<1
+	#define PM3FillConfig2D_UserScissorEnable               1<<2
+	#define PM3FillConfig2D_FBDestReadEnable                1<<3
+	#define PM3FillConfig2D_AlphaBlendEnable                1<<4
+	#define PM3FillConfig2D_DitherEnable                    1<<5
+	#define PM3FillConfig2D_ForegroundROPEnable             1<<6
+	#define PM3FillConfig2D_ForegroundROP(rop)              (((rop)&0xf)<<7)
+	#define PM3FillConfig2D_BackgroundROPEnable             1<<11
+	#define PM3FillConfig2D_BackgroundROP(rop)              (((rop)&0xf)<<12)
+	#define PM3FillConfig2D_UseConstantSource               1<<16
+	#define PM3FillConfig2D_FBWriteEnable                   1<<17
+	#define PM3FillConfig2D_Blocking                        1<<18
+	#define PM3FillConfig2D_ExternalSourceData              1<<19
+	#define PM3FillConfig2D_LUTModeEnable                   1<<20
+#define PM3FillFBDestReadBufferAddr                             0x8310
+#define PM3FillFBSourceReadBufferAddr                           0x8308
+#define PM3FillFBSourceReadBufferOffset                         0x8340
+	#define PM3FillFBSourceReadBufferOffset_XOffset(x)     ((x)&0xffff)
+	#define PM3FillFBSourceReadBufferOffset_YOffset(y)      (((y)&0xffff)<<16)
+#define PM3FillFBWriteBufferAddr                                0x8300
+#define PM3FillForegroundColor0                                 0x8328
+#define PM3FillForegroundColor1                                 0x8358
+#define PM3FillGlyphPosition                                    0x8368
+        #define PM3FillGlyphPosition_XOffset(x)                        ((x)&0xffff)
+	#define PM3FillGlyphPosition_YOffset(y)                        (((y)&0xffff)<<16)
+#define PM3FillRectanglePosition                                0x8348
+	#define PM3FillRectanglePosition_XOffset(x)            ((x)&0xffff)
+	#define PM3FillRectanglePosition_YOffset(y)            (((y)&0xffff)<<16)
+
+#define PM3_REGS_SIZE           0x10000
+#define PM3_MAX_PIXCLOCK        300000
+/* a few more useful registers & regs value... */
+#define PM3Sync 0x8c40
+        #define PM3Sync_Tag 0x188
+#define PM3FilterMode 0x8c00
+        #define PM3FilterModeSync 0x400
+#define PM3OutputFifo 0x2000
+#define PM3StatisticMode 0x8c08
+#define PM3AreaStippleMode 0x81a0
+        #define AreaStipplePattern0					(0x8200)
+        #define AreaStipplePattern1					(0x8208)
+        #define AreaStipplePattern2					(0x8210)
+        #define AreaStipplePattern3					(0x8218)
+        #define AreaStipplePattern4					(0x8220)
+        #define AreaStipplePattern5					(0x8228)
+        #define AreaStipplePattern6					(0x8230)
+        #define AreaStipplePattern7					(0x8238)
+        #define AreaStipplePattern8					(0x8240)
+        #define AreaStipplePattern9					(0x8248)
+        #define AreaStipplePattern10					(0x8250)
+        #define AreaStipplePattern11					(0x8258)
+        #define AreaStipplePattern12					(0x8260)
+        #define AreaStipplePattern13					(0x8268)
+        #define AreaStipplePattern14					(0x8270)
+        #define AreaStipplePattern15					(0x8278)
+        #define AreaStipplePattern16					(0x8280)
+        #define AreaStipplePattern17					(0x8288)
+        #define AreaStipplePattern18					(0x8290)
+        #define AreaStipplePattern19					(0x8298)
+        #define AreaStipplePattern20					(0x82a0)
+        #define AreaStipplePattern21					(0x82a8)
+        #define AreaStipplePattern22					(0x82b0)
+        #define AreaStipplePattern23					(0x82b8)
+        #define AreaStipplePattern24					(0x82c0)
+        #define AreaStipplePattern25					(0x82c8)
+        #define AreaStipplePattern26					(0x82d0)
+        #define AreaStipplePattern27					(0x82d8)
+        #define AreaStipplePattern28					(0x82eo)
+        #define AreaStipplePattern29					(0x82e8)
+        #define AreaStipplePattern30					(0x82f0)
+        #define AreaStipplePattern31					(0x82f8)
+        #define AreaStipplePattern_indexed(i)             (0x8200 + ((i) * 0x8))
+
+#define PM3DepthMode 0x89a0
+#define PM3StencilMode 0x8988
+#define PM3StencilData 0x8990
+#define PM3TextureReadMode 0x8670
+#define PM3FogMode 0x8690
+#define PM3ChromaTestMode 0x8f18
+#define PM3YUVMode 0x8f00
+#define PM3BitMaskPattern 0x8068
+
+/* ***************************** */
+/* ***** pm3fb IOCTL const ***** */
+/* ***************************** */
+/* debug-only IOCTL */
+#define PM3FBIO_CLEARMEMORY 0x504D3300 /* 'PM3\000' */
+#define PM3FBIO_CLEARCMAP   0x504D3301 /* 'PM3\001' */
+/* common use IOCTL */
+#define PM3FBIO_RESETCHIP   0x504D33FF /* 'PM3\377' */
+
+/* ***************************************** */
+/* ***** pm3fb useful define and macro ***** */
+/* ***************************************** */
+
+/* kernel -specific definitions */
+/* what kernel is this ? */
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)))
+#define KERNEL_2_5
+#endif
+
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)))
+#define KERNEL_2_4
+#endif
+
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))) 
+#define KERNEL_2_2
+/* pci_resource_start, available in 2.2.18 */
+#include <linux/kcomp.h>
+#ifdef CONFIG_FB_OF
+#define SUPPORT_FB_OF
+#endif
+#endif
+
+#if (!defined(KERNEL_2_2)) && (!defined(KERNEL_2_4)) && (!defined(KERNEL_2_5))
+#error "Only kernel 2.2.x, kernel 2.4.y and kernel 2.5.z might work"
+#endif
+
+/* not sure if/why it's needed. doesn't work without on my PowerMac... */
+#ifdef __BIG_ENDIAN
+#define MUST_BYTESWAP
+#endif
+
+/* for compatibility between 2.5, 2.4 and 2.2 */
+#ifndef B_FREE
+#define B_FREE   -1
+#endif
+
+/* permedia3 -specific definitions */
+#define PM3_SCALE_TO_CLOCK(pr, fe, po) ((2 * PM3_REF_CLOCK * fe) / (pr * (1 << (po))))
+
+/* in case it's not in linux/pci.h */
+#ifndef PCI_DEVICE_ID_3DLABS_PERMEDIA3
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA3 0x000a
+#endif
+
+/* max number of simultaneous board */
+/* warning : make sure module array def's are coherent with PM3_MAX_BOARD */
+#define PM3_MAX_BOARD 4
+#define PM3_MAX_BOARD_MODULE_ARRAY_SHORT "1-4h"
+#define PM3_MAX_BOARD_MODULE_ARRAY_STRING "1-4s"
+
+/* max size of options */
+#define PM3_OPTIONS_SIZE 256
+
+/* max size of font name */
+#define PM3_FONTNAME_SIZE 40
+
+/* do we want accelerated console  */
+#define PM3FB_USE_ACCEL 1
+
+/* useful ? */
+#define CHAR_IS_NUM(a)  ((((a) >= '0') && ((a) <= '9')) ? 1 : 0)
+
+/* for driver debugging ONLY */
+/* 0 = assert only, 1 = error, 2 = info, 3+ = verbose */
+/* define PM3FB_MASTER_DEBUG 1 */
+#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 3)
+#define PM3FB_TRACE
+#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 3) */
+
+#ifdef PM3FB_MASTER_DEBUG
+#define DPRINTK(l,a,b...) do { if ((l) <= PM3FB_MASTER_DEBUG) printk("pm3fb: %s: " a, __FUNCTION__ , ## b); } while (0)
+#define DASSERT(t,a,b...) do { if (!(t)) printk("pm3fb: _assert failed: %s: " a, __FUNCTION__ , ## b); } while (0)
+#ifdef PM3FB_TRACE
+#define DTRACE printk("pm3fb: _enter %s\n", __FUNCTION__)
+#else /* PM3FB_TRACE */
+#define DTRACE
+#endif /* PM3FB_TRACE */
+#else /* PM3FB_MASTER_DEBUG */
+#define DPRINTK(l,a,b...)
+#define DASSERT(t,a,b...)
+#define DTRACE
+#endif /* PM3FB_MASTER_DEBUG */
+
+#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
+#define PM3_SHOW_CUR_MODE pm3fb_show_cur_mode(l_fb_info)
+#else
+#define PM3_SHOW_CUR_MODE /* pm3fb_show_cur_mode() */
+#endif
+
+/* ******************************************** */
+/* ***** A bunch of register-access macro ***** */
+/* ******************************************** */
+#ifdef KERNEL_2_2
+#ifdef MUST_BYTESWAP /* we are writing big_endian to big_endian through a little_endian macro */
+#define PM3_READ_REG(r) __swab32(readl((l_fb_info->vIOBase + r)))
+#define PM3_WRITE_REG(r, v) writel(__swab32(v), (l_fb_info->vIOBase + r))
+#else /* MUST_BYTESWAP */
+#define PM3_WRITE_REG(r, v) writel(v, (l_fb_info->vIOBase + r))
+#define PM3_READ_REG(r) readl((l_fb_info->vIOBase + r))
+#endif /* MUST_BYTESWAP */
+#endif /* KERNEL_2_2 */
+#if (defined KERNEL_2_4) || (defined KERNEL_2_5) /* native-endian access */
+#define PM3_WRITE_REG(r, v) fb_writel(v, (l_fb_info->vIOBase + r))
+#define PM3_READ_REG(r) fb_readl((l_fb_info->vIOBase + r))
+#endif /* KERNEL_2_4 or KERNEL_2_5 */
+
+
+#define depth2bpp(d) ((d + 7L) & ~7L)
+#define depth2ByPP(d) (depth2bpp(d) / 8)
+
+#define depth_supported(d) ((d == 8) || (d == 12) || (d == 15) || (d == 16) || (d==32))
+
+
+#define PM3_WAIT(n) \
+do{ \
+	while(PM3_READ_REG(PM3InFIFOSpace)<(n)); \
+} while(0)
+
+#define PM3_DELAY(x) do { \
+        int delay = x; \
+        unsigned char tmp; \
+        while(delay--){tmp = PM3_READ_REG(PM3InFIFOSpace);}; \
+} while(0)
+
+#define PM3_SLOW_WRITE_REG(r,v)	\
+do{                             \
+    DASSERT((l_fb_info->vIOBase != (unsigned char*)(-1)), "l_fb_info->vIOBase mapped in slow write\n"); \
+	mb();                   \
+	PM3_WAIT(1);            \
+	mb();                   \
+    PM3_WRITE_REG(r,v);     \
+} while(0)
+
+#define PM3_SET_INDEX(index) \
+do{ \
+	PM3_SLOW_WRITE_REG(PM3RD_IndexHigh,(((index)>>8)&0xff)); \
+	PM3_SLOW_WRITE_REG(PM3RD_IndexLow,((index)&0xff)); \
+} while(0)
+
+#define PM3_WRITE_DAC_REG(r, v) \
+do { \
+     DASSERT((l_fb_info->vIOBase != (unsigned char*)(-1)), "l_fb_info->vIOBase mapped in write dac reg\n"); \
+     PM3_SET_INDEX(r); \
+     mb(); \
+     PM3_WRITE_REG(PM3RD_IndexedData, v); \
+} while (0)
+
+/* next one is really a function, added as a macro to be consistent */
+#define PM3_READ_DAC_REG(r) pm3fb_read_dac_reg(l_fb_info, r)
+
+
+#define PM3_COLOR(c) \
+do { \
+  if (l_fb_info->current_par->depth == 8) \
+    { \
+      c = (c & 0xFF); \
+      c = c | (c << 8); \
+    } \
+  if ((l_fb_info->current_par->depth == 8) || (depth2bpp(l_fb_info->current_par->depth) == 16)) \
+    { \
+      c = (c & 0xFFFF); \
+      c = c | (c << 16); \
+    } \
+} while (0)
+
+#endif PM3FB_H
diff -Nru a/drivers/video/q40fb.c b/drivers/video/q40fb.c
--- a/drivers/video/q40fb.c	Wed May 29 11:43:02 2002
+++ b/drivers/video/q40fb.c	Wed May 29 11:43:02 2002
@@ -1,3 +1,15 @@
+/* 
+ * linux/drivers/video/q40fb.c -- Q40 frame buffer device
+ *
+ * Copyright (C) 2001 
+ *
+ *      Richard Zidlicky <Richard.Zidlicky@stud.informatik.uni-erlangen.de>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -9,181 +21,68 @@
 
 #include <asm/uaccess.h>
 #include <asm/setup.h>
+#include <asm/segment.h>
 #include <asm/system.h>
-/*#include <asm/irq.h>*/
 #include <asm/q40_master.h>
 #include <linux/fb.h>
 #include <linux/module.h>
 #include <asm/pgtable.h>
 
 #include <video/fbcon.h>
-#include <video/fbcon-cfb16.h>
-
-#define FBIOSETSCROLLMODE   0x4611
 
 #define Q40_PHYS_SCREEN_ADDR 0xFE800000
 
-static u16 fbcon_cmap_cfb16[16];
+static u32 pseudo_palette[17];
+static struct fb_info fb_info;
+static struct display display;
 
-/* frame buffer operations */
+static struct fb_fix_screeninfo q40fb_fix __initdata = {
+	id:		"Q40",
+	smem_len:	1024*1024,
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_TRUECOLOR,
+	line_length:	1024*2,
+	accel_flags:	FB_ACCEL_NONE,
+};
 
-static int q40fb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			struct fb_info *info);
-static int q40fb_get_var(struct fb_var_screeninfo *var, int con,
-			struct fb_info *info);
-static int q40fb_set_var(struct fb_var_screeninfo *var, int con,
-			struct fb_info *info);
-static int q40fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
-			 struct fb_info *info);
-static int q40fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
-			 struct fb_info *info);
-static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green,
-			   unsigned blue, unsigned transp,
-			   const struct fb_info *info);
+static struct fb_var_screeninfo q40fb_var __initdata = {
+	xres:		1024,
+	yres:		512,
+	xres_virtual:	1024,
+	yres_virtual:	512,
+	bits_per_pixel:	16,
+    	red:		{6, 5, 0}, 
+	green:		{11, 5, 0},
+	blue:		{0, 6, 0},
+	activate:	FB_ACTIVATE_NOW,
+	height:		230,
+	width:		300,
+	vmode:		FB_VMODE_NONINTERLACED,
+};
 
-static int q40con_switch(int con, struct fb_info *info);
-static int q40con_updatevar(int con, struct fb_info *info);
+/* frame buffer operations */
+int q40fb_init(void);
 
-static void q40fb_set_disp(int con, struct fb_info *info);
+static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                           unsigned blue, unsigned transp,
+                           struct fb_info *info);
 
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
 static struct fb_ops q40fb_ops = {
 	owner:		THIS_MODULE,
-	fb_get_fix:	q40fb_get_fix,
-	fb_get_var:	q40fb_get_var,
-	fb_set_var:	q40fb_set_var,
-	fb_get_cmap:	q40fb_get_cmap,
-	fb_set_cmap:	q40fb_set_cmap,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
+	fb_set_cmap:	gen_set_cmap,
 	fb_setcolreg:	q40fb_setcolreg,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
 };
 
-static char q40fb_name[]="Q40";
-
-static int q40fb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			struct fb_info *info)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-
-	strcpy(fix->id,"Q40");
-	fix->smem_start = info->screen_base;
-	fix->smem_len=1024*1024;
-	fix->type=FB_TYPE_PACKED_PIXELS;
-	fix->type_aux=0;
-	fix->visual=FB_VISUAL_TRUECOLOR;  /* good approximation so far ..*/;
-	fix->xpanstep=0;
-	fix->ypanstep=0;
-	fix->ywrapstep=0;
-        fix->line_length=1024*2;
-
-	/* no mmio,accel ...*/
-
-	return 0;
-
-}
-        
-static int q40fb_get_var(struct fb_var_screeninfo *var, int con,
-			struct fb_info *info)
-{
-	memset(var, 0, sizeof(struct fb_var_screeninfo));
-
-	var->xres=1024;
-	var->yres=512;
-	var->xres_virtual=1024;
-	var->yres_virtual=512;
-	var->xoffset=0;
-	var->yoffset=0;
-	var->bits_per_pixel=16;
-	var->grayscale=0;
-	var->nonstd=0;
-	var->activate=FB_ACTIVATE_NOW;
-	var->height=230;     /* approx for my 17" monitor, more important */
-	var->width=300;      /* than the absolute values is the unusual aspect ratio*/
-
-	var->red.offset=6; /*6*/
-	var->red.length=5;
-	var->green.offset=11; /*11*/
-	var->green.length=5;
-	var->blue.offset=0;
-	var->blue.length=6;
-	var->transp.length=0;
-
-	var->pixclock=0;
-	var->left_margin=0;
-	var->right_margin=0;
-	var->hsync_len=0;
-	var->vsync_len=0;
-	var->sync=0;
-	var->vmode=FB_VMODE_NONINTERLACED;
-
-	return 0;
-
-}
-
-static int q40fb_set_var(struct fb_var_screeninfo *var, int con,
-			struct fb_info *info)
-{
-	if(var->xres!=1024) 
-		return -EINVAL;
-	if(var->yres!=512)
-		return -EINVAL;
-	if(var->xres_virtual!=1024)
-		return -EINVAL;
-	if(var->yres_virtual!=512)
-		return -EINVAL;
-	if(var->xoffset!=0)
-		return -EINVAL;
-	if(var->yoffset!=0)
-		return -EINVAL;
-	if(var->bits_per_pixel!=16)
-		return -EINVAL;
-	if(var->grayscale!=0)
-		return -EINVAL;
-	if(var->nonstd!=0)
-		return -EINVAL;
-	if(var->activate!=FB_ACTIVATE_NOW)
-		return -EINVAL;
-	if(var->pixclock!=0)
-		return -EINVAL;
-	if(var->left_margin!=0)
-		return -EINVAL;
-	if(var->right_margin!=0)
-		return -EINVAL;
-	if(var->hsync_len!=0)
-		return -EINVAL;
-	if(var->vsync_len!=0)
-		return -EINVAL;
-	if(var->sync!=0)
-		return -EINVAL;
-	if(var->vmode!=FB_VMODE_NONINTERLACED)
-		return -EINVAL;
-
-	return 0;
-
-}
-
-static int q40_getcolreg(unsigned regno, unsigned *red, unsigned *green,
-			 unsigned *blue, unsigned *transp,
-			 struct fb_info *info)
-{
-    /*
-     *  Read a single color register and split it into colors/transparent.
-     *  The return values must have a 16 bit magnitude.
-     *  Return != 0 for invalid regno.
-     */
-    if (regno>=16) return 1;
-
-    *transp=0;
-    *green = ((fbcon_cmap_cfb16[regno]>>11) & 31)<<11;
-    *red   = ((fbcon_cmap_cfb16[regno]>>6) & 31)<<11;
-    *blue  = ((fbcon_cmap_cfb16[regno]) & 63)<<10;
-
-    return 0;
-}
-
 static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green,
-			   unsigned blue, unsigned transp,
-			   const struct fb_info *info)
+		  	   unsigned blue, unsigned transp,
+			   struct fb_info *info)
 {
     /*
      *  Set a single color register. The values supplied have a 16 bit
@@ -191,142 +90,54 @@
      *  Return != 0 for invalid regno.
      */
   
-  red>>=11;
-  green>>=11;
-  blue>>=10;
+    red>>=11;
+    green>>=11;
+    blue>>=10;
 
     if (regno < 16) {
-      fbcon_cmap_cfb16[regno] = ((red & 31) <<6) |
-	                         ((green & 31) << 11) |
-	                         (blue & 63);
+	info->pseudo_palette[regno] = ((red & 31) <<6) |
+	                              ((green & 31) << 11) |
+	                         	(blue & 63);
     }
     return 0;
 }
 
-static int q40fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			 struct fb_info *info)
+int q40fb_init(void)
 {
-#if 1
-	if (con == info->currcon) /* current console? */
-		return fb_get_cmap(cmap, kspc, q40_getcolreg, info);
-	else if (fb_display[con].cmap.len) /* non default colormap? */
-		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-			     cmap, kspc ? 0 : 2);
-	return 0;
-#else
-	printk(KERN_ERR "get cmap not supported\n");
-
-	return -EINVAL;
-#endif
-}
-
-static int q40fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			 struct fb_info *info)
-{
-#if 1
-	int err;
-
-	if (!fb_display[con].cmap.len) {	/* no colormap allocated? */
-		if ((err = fb_alloc_cmap(&fb_display[con].cmap,
-					 1<<fb_display[con].var.bits_per_pixel,
-					 0)))
-			return err;
-	}
-	if (con == info->currcon)			/* current console? */
-		return fb_set_cmap(cmap, kspc, info);
-	else
-		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
-	return 0;
-#else
-	printk(KERN_ERR "set cmap not supported\n");
-
-	return -EINVAL;
-#endif
-}
-
-static void q40fb_set_disp(int con, struct fb_info *info)
-{
-  struct fb_fix_screeninfo fix;
-  struct display *display;
-
-  q40fb_get_fix(&fix, con, info);
-
-  if (con>=0)
-    display = &fb_display[con];
-  else 	
-    display = &disp[0];
-
-  if (con<0) con=0;
-
-   display->visual = fix.visual;
-   display->type = fix.type;
-   display->type_aux = fix.type_aux;
-   display->ypanstep = fix.ypanstep;
-   display->ywrapstep = fix.ywrapstep;
-   display->can_soft_blank = 0;
-   display->inverse = 0;
-   display->line_length = fix.line_length;
-
-   display->scrollmode = SCROLL_YREDRAW;
-
-#ifdef FBCON_HAS_CFB16
-   display->dispsw = &fbcon_cfb16;
-   disp->dispsw_data = fbcon_cmap_cfb16;
-#else
-   display->dispsw = &fbcon_dummy;
-#endif
-}
-  
-int __init q40fb_init(void)
-{
-
         if ( !MACH_IS_Q40)
 	  return -ENXIO;
-#if 0
-        fb_info.screen_base = kernel_map(Q40_PHYS_SCREEN_ADDR, 1024*1024,
-					   KERNELMAP_NO_COPYBACK, NULL);
-#else
-	fb_info.screen_base = Q40_PHYS_SCREEN_ADDR; /* mapped in q40/config.c */
-#endif
-
-	fb_info.changevar=NULL;
-	strcpy(&fb_info.modename[0],q40fb_name);
-	fb_info.fontname[0]=0;
-	fb_info.disp=disp;
-	fb_info.currcon = -1;
-	fb_info.switch_con=&q40con_switch;
-	fb_info.updatevar=&q40con_updatevar;
+
+	/* mapped in q40/config.c */
+	q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR;
+	
+	fb_info.var = q40fb_var;
+	fb_info.fix = q40fb_fix;
 	fb_info.node = NODEV;
 	fb_info.fbops = &q40fb_ops;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;  /* not as module for now */
-	
-	master_outb(3,DISPLAY_CONTROL_REG);
+	fb_info.pseudo_palette = pseudo_palette;	
+   	fb_info.screen_base = (char *) q40fb_fix.smem_start;
+
+	/* The below feilds will go away !!!! */
+	fb_info.currcon		= -1;
+	strcpy(fb_info.modename, fb_info.fix.id);
+	fb_info.disp		= &display;
+	fb_info.switch_con	= gen_switch;
+	fb_info.updatevar	= gen_update_var;
+	fb_alloc_cmap(&fb_info.cmap, 16, 0);
 
-        q40fb_get_var(&disp[0].var, 0, &fb_info);
-	q40fb_set_disp(-1, &fb_info);
+        gen_set_disp(-1, &fb_info);
+	
+	master_outb(3, DISPLAY_CONTROL_REG);
 
 	if (register_framebuffer(&fb_info) < 0) {
-		printk(KERN_ERR "unable to register Q40 frame buffer\n");
+		printk(KERN_ERR "Unable to register Q40 frame buffer\n");
 		return -EINVAL;
 	}
 
         printk(KERN_INFO "fb%d: Q40 frame buffer alive and kicking !\n",
 	       GET_FB_IDX(fb_info.node));
 	return 0;
-}	
-
-	
-static int q40con_switch(int con, struct fb_info *info)
-{ 
-	info->currcon=con;
-	return 0;
-}
-
-static int q40con_updatevar(int con, struct fb_info *info)
-{
-	return 0;
 }
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL");	
diff -Nru a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
--- a/drivers/video/skeletonfb.c	Wed May 29 11:43:02 2002
+++ b/drivers/video/skeletonfb.c	Wed May 29 11:43:02 2002
@@ -1,11 +1,45 @@
 /*
  * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
  *
+ *  Modified to new api Jan 2001 by James Simmons (jsimmons@transvirtual.com)
+ *
  *  Created 28 Dec 1997 by Geert Uytterhoeven
  *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
+ *
+ *  I have started rewriting this driver as a example of the upcoming new API
+ *  The primary goal is to remove the console code from fbdev and place it
+ *  into fbcon.c. This reduces the code and makes writing a new fbdev driver
+ *  easy since the author doesn't need to worry about console internals. It
+ *  also allows the ability to run fbdev without a console/tty system on top 
+ *  of it. 
+ *
+ *  First the roles of struct fb_info and struct display have changed. Struct
+ *  display will go away. The way the the new framebuffer console code will
+ *  work is that it will act to translate data about the tty/console in 
+ *  struct vc_data to data in a device independent way in struct fb_info. Then
+ *  various functions in struct fb_ops will be called to store the device 
+ *  dependent state in the par field in struct fb_info and to change the 
+ *  hardware to that state. This allows a very clean seperation of the fbdev
+ *  layer from the console layer. It also allows one to use fbdev on its own
+ *  which is a bounus for embedded devices. The reason this approach works is  
+ *  for each framebuffer device when used as a tty/console device is allocated
+ *  a set of virtual terminals to it. Only one virtual terminal can be active 
+ *  per framebuffer device. We already have all the data we need in struct 
+ *  vc_data so why store a bunch of colormaps and other fbdev specific data
+ *  per virtual terminal. 
+ *
+ *  As you can see doing this makes the con parameter pretty much useless
+ *  for struct fb_ops functions, as it should be. Also having struct  
+ *  fb_var_screeninfo and other data in fb_info pretty much eliminates the 
+ *  need for get_fix and get_var. Once all drivers use the fix, var, and cmap
+ *  fbcon can be written around these fields. This will also eliminate the
+ *  need to regenerate struct fb_var_screeninfo, struct fb_fix_screeninfo
+ *  struct fb_cmap every time get_var, get_fix, get_cmap functions are called
+ *  as many drivers do now. 
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
  */
 
 #include <linux/module.h>
@@ -19,9 +53,6 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 
-#include <video/fbcon.h>
-
-
     /*
      *  This is just simple sample code.
      *
@@ -29,310 +60,410 @@
      *  Even less warranty that it actually works :-)
      */
 
+/*
+ *  If your driver supports multiple boards, you should make the  
+ *  below data types arrays, or allocate them dynamically (using kmalloc()). 
+ */ 
+
+/* 
+ * This structure defines the hardware state of the graphics card. Normally
+ * you place this in a header file in linux/include/video. This file usually
+ * also includes register information. That allows other driver subsystems
+ * and userland applications the ability to use the same header file to 
+ * avoid duplicate work and easy porting of software. 
+ */
+struct xxx_par;
 
-struct xxxfb_info {
-    /*
-     *  Choose _one_ of the two alternatives:
-     *
-     *    1. Use the generic frame buffer operations (fbgen_*).
-     */
-    struct fb_info_gen gen;
-    /*
-     *    2. Provide your own frame buffer operations.
-     */
-    struct fb_info info;
-
-    /* Here starts the frame buffer device dependent part */
-    /* You can use this to store e.g. the board number if you support */
-    /* multiple boards */
+/*
+ * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
+ * if we don't use modedb. If we do use modedb see xxxfb_init how to use it
+ * to get a fb_var_screeninfo. Otherwise define a default var as well. 
+ */
+static struct fb_fix_screeninfo xxxfb_fix __initdata = {
+	id:		"FB's name", 
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_PSEUDOCOLOR,
+	xpanstep:	1,
+	ypanstep:	1,
+	ywrapstep:	1, 
+	accel:		FB_ACCEL_NONE,
 };
 
-
-struct xxxfb_par {
     /*
-     *  The hardware specific data in this structure uniquely defines a video
-     *  mode.
-     *
-     *  If your hardware supports only one video mode, you can leave it empty.
+     * 	Modern graphical hardware not only supports pipelines but some 
+     *  also support multiple monitors where each display can have its  
+     *  its own unique data. In this case each display could be  
+     *  represented by a seperate framebuffer device thus a seperate 
+     *  struct fb_info. Now the struct xxx_par represents the graphics
+     *  hardware state thus only one exist per card. In this case the 
+     *  struct xxx_par for each graphics card would be shared between 
+     *  every struct fb_info that represents a framebuffer on that card. 
+     *  This allows when one display changes it video resolution (info->var) 
+     *  the other displays know instantly. Each display can always be
+     *  aware of the entire hardware state that affects it because they share
+     *  the same xxx_par struct. The other side of the coin is multiple
+     *  graphics cards that pass data around until it is finally displayed
+     *  on one monitor. Such examples are the voodoo 1 cards and high end
+     *  NUMA graphics servers. For this case we have a bunch of pars, each
+     *  one that represents a graphics state, that belong to one struct 
+     *  fb_info. Their you would want to have *par point to a array of device
+     *  states and have each struct fb_ops function deal with all those 
+     *  states. I hope this covers every possible hardware design. If not
+     *  feel free to send your ideas at jsimmons@users.sf.net 
      */
-};
-
 
     /*
-     *  If your driver supports multiple boards, you should make these arrays,
-     *  or allocate them dynamically (using kmalloc()).
+     *  If your driver supports multiple boards or it supports multiple 
+     *  framebuffers, you should make these arrays, or allocate them 
+     *  dynamically (using kmalloc()). 
+     */ 
+static struct fb_info info;
+
+    /* 
+     * Each one represents the a state of the hardware. Most hardware have 
+     * just one hardware state. These here represent the default state(s). 
      */
+static struct xxx_par __initdata current_par;
 
-static struct xxxfb_info fb_info;
-static struct xxxfb_par current_par;
-static int current_par_valid = 0;
+    /* To go away in the near future */ 
 static struct display disp;
 
-static struct fb_var_screeninfo default_var;
-
-static int inverse = 0;
-
 int xxxfb_init(void);
 int xxxfb_setup(char*);
 
-/* ------------------- chipset specific functions -------------------------- */
-
-
-static void xxx_detect(void)
-{
-    /*
-     *  This function should detect the current video mode settings and store
-     *  it as the default video mode
-     */
-
-    struct xxxfb_par par;
-
-    /* ... */
-    xxx_get_par(&par);
-    xxx_encode_var(&default_var, &par);
-}
-
-static int xxx_encode_fix(struct fb_fix_screeninfo *fix, struct xxxfb_par *par,
-			  const struct fb_info *info)
-{
-    /*
-     *  This function should fill in the 'fix' structure based on the values
-     *  in the `par' structure.
-     */
-
-    /* ... */
-    return 0;
-}
-
-static int xxx_decode_var(struct fb_var_screeninfo *var, struct xxxfb_par *par,
-			  const struct fb_info *info)
+/**
+ *      xxxfb_check_var - Optional function. Validates a var passed in. 
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer 
+ *
+ *	Checks to see if the hardware supports the state requested by
+ *	var passed in. This function does not alter the hardware state!!! 
+ *	This means the data stored in struct fb_info and struct xxx_par do 
+ *      not change. This includes the var inside of struct fb_info. 
+ *	Do NOT change these. This function can be called on its own if we
+ *	intent to only test a mode and not actually set it. The stuff in 
+ *	modedb.c is a example of this. If the var passed in is slightly 
+ *	off by what the hardware can support then we alter the var PASSED in
+ *	to what we can do. If the hardware doesn't support mode change 
+ * 	a -EINVAL will be returned by the upper layers. You don't need to 
+ *	implement this function then.
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int xxxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
-    /*
-     *  Get the video params out of 'var'. If a value doesn't fit, round it up,
-     *  if it's too big, return -EINVAL.
-     *
-     *  Suggestion: Round up in the following order: bits_per_pixel, xres,
-     *  yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
-     *  bitfields, horizontal timing, vertical timing.
-     */
-
+    const struct xxx_par *par = (const struct xxx_par *) info->par;
     /* ... */
-
-    /* pixclock in picos, htotal in pixels, vtotal in scanlines */
-    if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
-	    return -EINVAL;
-
-    return 0;
+    return 0;	   	
 }
 
-static int xxx_encode_var(struct fb_var_screeninfo *var, struct xxxfb_par *par,
-			  const struct fb_info *info)
+/**
+ *      xxxfb_set_par - Optional function. Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Using the fb_var_screeninfo in fb_info we set the resolution of the
+ *	this particular framebuffer. This function alters the par AND the
+ *	fb_fix_screeninfo stored in fb_info. It doesn't not alter var in 
+ *	fb_info since we are using that data. This means we depend on the
+ *	data in var inside fb_info to be supported by the hardware. 
+ *	xxxfb_check_var is always called before xxxfb_set_par to ensure this.
+ *
+ */
+static int xxxfb_set_par(struct fb_info *info)
 {
-    /*
-     *  Fill the 'var' structure based on the values in 'par' and maybe other
-     *  values read out of the hardware.
-     */
-
+    struct xxx_par *par = (struct xxx_par *) info->par;
     /* ... */
-    return 0;
+    return 0;	
 }
 
-static void xxx_get_par(struct xxxfb_par *par, const struct fb_info *info)
+/**
+ *  	xxxfb_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *	@green: The green value which can be up to 16 bits wide 
+ *	@blue:  The blue value which can be up to 16 bits wide.
+ *	@transp: If supported the alpha value which can be up to 16 bits wide.	
+ *      @info: frame buffer info structure
+ * 
+ *  	Set a single color register. The values supplied have a 16 bit
+ *  	magnitude which needs to be scaled in this function for the hardware. 
+ *	Things to take into consideration are how many color registers, if
+ *	any, are supported with the current color visual. With truecolor mode
+ *	no color palettes are supported. Here a psuedo palette is created 
+ *	which we store the value in pseudo_palette in struct fb_info. For
+ *	pseudocolor mode we have a limited color palette. To deal with this
+ *	we can program what color is displayed for a particular pixel value.
+ *	DirectColor is similar in that we can program each color field. If
+ *	we have a static colormap we don't need to implement this function. 
+ * 
+ *	Returns negative errno on error, or zero on success.
+ */
+static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   const struct fb_info *info)
 {
+    if (regno >= 256)  /* no. of hw registers */
+       return 1;
     /*
-     *  Fill the hardware's 'par' structure.
+     * Program hardware... do anything you want with transp
      */
 
-    if (current_par_valid)
-	*par = current_par;
-    else {
-	/* ... */
+    /* grayscale works only partially under directcolor */
+    if (info->var.grayscale) {
+       /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+       red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
     }
-}
-
-static void xxx_set_par(struct xxxfb_par *par, const struct fb_info *info)
-{
-    /*
-     *  Set the hardware according to 'par'.
-     */
 
-    current_par = *par;
-    current_par_valid = 1;
+    /* Directcolor:
+     *   var->{color}.offset contains start of bitfield
+     *   var->{color}.length contains length of bitfield
+     *   {hardwarespecific} contains width of DAC
+     *   cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset)
+     *   RAMDAC[X] is programmed to (red, green, blue)
+     *
+     * Pseudocolor:
+     *    uses offset = 0 && length = DAC register width.
+     *    var->{color}.offset is 0
+     *    var->{color}.length contains widht of DAC
+     *    cmap is not used
+     *    DAC[X] is programmed to (red, green, blue)
+     * Truecolor:
+     *    does not use RAMDAC (usually has 3 of them).
+     *    var->{color}.offset contains start of bitfield
+     *    var->{color}.length contains length of bitfield
+     *    cmap is programmed to (red << red.offset) | (green << green.offset) |
+     *                      (blue << blue.offset) | (transp << transp.offset)
+     *    RAMDAC does not exist
+     */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+    switch (info->fix.visual) {
+       case FB_VISUAL_TRUECOLOR:
+       case FB_VISUAL_PSEUDOCOLOR:
+               red = CNVT_TOHW(red, info->var.red.length);
+               green = CNVT_TOHW(green, info->var.green.length);
+               blue = CNVT_TOHW(blue, info->var.blue.length);
+               transp = CNVT_TOHW(transp, info->var.transp.length);
+               break;
+       case FB_VISUAL_DIRECTCOLOR:
+	       /* example here assumes 8 bit DAC. Might be different 
+		* for your hardware */	
+               red = CNVT_TOHW(red, 8);       
+               green = CNVT_TOHW(green, 8);
+               blue = CNVT_TOHW(blue, 8);
+               /* hey, there is bug in transp handling... */
+               transp = CNVT_TOHW(transp, 8);
+               break;
+    }
+#undef CNVT_TOHW
+    /* Truecolor has hardware independent palette */
+    if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+       u32 v;
+
+       if (regno >= 16)
+           return 1;
+
+       v = (red << info->var.red.offset) |
+           (green << info->var.green.offset) |
+           (blue << info->var.blue.offset) |
+           (transp << info->var.transp.offset);
+
+       switch (info->var.bits_per_pixel) {
+		case 8:
+			/* Yes some hand held devices have this. */ 
+           		((u8*)(info->pseudo_palette))[regno] = v;
+			break;	
+   		case 16:
+           		((u16*)(info->pseudo_palette))[regno] = v;
+			break;
+		case 24:
+		case 32:	
+           		((u32*)(info->pseudo_palette))[regno] = v;
+			break;
+       }
+       return 0;
+    }
     /* ... */
+    return 0;
 }
 
-static int xxx_getcolreg(unsigned regno, unsigned *red, unsigned *green,
-			 unsigned *blue, unsigned *transp,
-			 const struct fb_info *info)
+/**
+ *      xxxfb_pan_display - NOT a required function. Pans the display.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Pan (or wrap, depending on the `vmode' field) the display using the
+ *  	`xoffset' and `yoffset' fields of the `var' structure.
+ *  	If the values don't fit, return -EINVAL.
+ *
+ *      Returns negative errno on error, or zero on success.
+ *
+ */
+static int xxxfb_pan_display(struct fb_var_screeninfo *var,
+			     const struct fb_info *info)
 {
-    /*
-     *  Read a single color register and split it into colors/transparent.
-     *  The return values must have a 16 bit magnitude.
-     *  Return != 0 for invalid regno.
-     */
-
     /* ... */
     return 0;
 }
 
-static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
-			   unsigned blue, unsigned transp,
-			   const struct fb_info *info)
+/**
+ *      xxxfb_blank - NOT a required function. Blanks the display.
+ *      @blank_mode: the blank mode we want. 
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *      Blank the screen if blank_mode != 0, else unblank. Return 0 if
+ *      blanking succeeded, != 0 if un-/blanking failed due to e.g. a 
+ *      video mode which doesn't support it. Implements VESA suspend
+ *      and powerdown modes on hardware that supports disabling hsync/vsync:
+ *      blank_mode == 2: suspend vsync
+ *      blank_mode == 3: suspend hsync
+ *      blank_mode == 4: powerdown
+ *
+ *      Returns negative errno on error, or zero on success.
+ *
+ */
+static int xxxfb_blank(int blank_mode, const struct fb_info *info)
 {
-    /*
-     *  Set a single color register. The values supplied have a 16 bit
-     *  magnitude.
-     *  Return != 0 for invalid regno.
-     */
-
-    if (regno < 16) {
-	/*
-	 *  Make the first 16 colors of the palette available to fbcon
-	 */
-	if (is_cfb15)		/* RGB 555 */
-	    ...fbcon_cmap.cfb16[regno] = ((red & 0xf800) >> 1) |
-					 ((green & 0xf800) >> 6) |
-					 ((blue & 0xf800) >> 11);
-	if (is_cfb16)		/* RGB 565 */
-	    ...fbcon_cmap.cfb16[regno] = (red & 0xf800) |
-					 ((green & 0xfc00) >> 5) |
-					 ((blue & 0xf800) >> 11);
-	if (is_cfb24)		/* RGB 888 */
-	    ...fbcon_cmap.cfb24[regno] = ((red & 0xff00) << 8) |
-					 (green & 0xff00) |
-					 ((blue & 0xff00) >> 8);
-	if (is_cfb32)		/* RGBA 8888 */
-	    ...fbcon_cmap.cfb32[regno] = ((red & 0xff00) << 16) |
-					 ((green & 0xff00) << 8) |
-					 (blue & 0xff00) |
-					 ((transp & 0xff00) >> 8);
-    }
     /* ... */
     return 0;
 }
 
-static int xxx_pan_display(struct fb_var_screeninfo *var,
-			   struct xxxfb_par *par, const struct fb_info *info)
-{
-    /*
-     *  Pan (or wrap, depending on the `vmode' field) the display using the
-     *  `xoffset' and `yoffset' fields of the `var' structure.
-     *  If the values don't fit, return -EINVAL.
-     */
+/* ------------ Accelerated Functions --------------------- */
 
-    /* ... */
-    return 0;
-}
+/*
+ * We provide our own functions if we have hardware acceleration
+ * or non packed pixel format layouts. If we have no hardware 
+ * acceleration, we use a generic unaccelerated function. If using
+ * a pack pixel format just use the functions in cfb*.c. Each file 
+ * has one of the three different accel functions we support. You   
+ * can use these functions as fallbacks if hardware unsupported
+ * action is requested. Also if you have non pack pixel modes and
+ * non accelerated cards you have to provide your own functions.
+ */
 
-static int xxx_blank(int blank_mode, const struct fb_info *info)
+/**
+ *      xxxfb_fillrect - REQUIRED function. Can use generic routines if 
+ *		 	 non acclerated hardware and packed pixel based.
+ *			 Draws a rectangle on the screen.		
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *	@x1: The x and y corrdinates of the upper left hand corner of the 
+ *	@y1: area we want to draw to. 
+ *	@width: How wide the rectangle is we want to draw.
+ *	@height: How tall the rectangle is we want to draw.
+ *	@color:	The color to fill in the rectangle with. 
+ *	@rop: The rater operation. We can draw the rectangle with a COPY
+ *	      of XOR which provides erasing effect. 
+ *
+ *	This drawing operation places/removes a retangle on the screen 
+ *	depending on the rastering operation with the value of color which
+ *	is in the current color depth format.
+ */
+void xxxfb_fillrect(struct fb_info *p, struct fb_fillrect *region)
 {
-    /*
-     *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
-     *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
-     *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
-     *  to e.g. a video mode which doesn't support it. Implements VESA suspend
-     *  and powerdown modes on hardware that supports disabling hsync/vsync:
-     *    blank_mode == 2: suspend vsync
-     *    blank_mode == 3: suspend hsync
-     *    blank_mode == 4: powerdown
-     */
-
-    /* ... */
-    return 0;
 }
 
-static void xxx_set_disp(const void *par, struct display *disp,
-			 struct fb_info_gen *info)
+/**
+ *      xxxfb_copyarea - REQUIRED function. Can use generic routines if
+ *                       non acclerated hardware and packed pixel based.
+ *                       Copies on area of the screen to another area.
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @sx: The x and y corrdinates of the upper left hand corner of the
+ *      @sy: source area on the screen.
+ *      @width: How wide the rectangle is we want to copy.
+ *      @height: How tall the rectangle is we want to copy.
+ *      @dx: The x and y coordinates of the destination area on the screen.
+ *
+ *      This drawing operation copies a rectangular area from one area of the
+ *	screen to another area.
+ */
+void xxxfb_copyarea(struct fb_info *p, struct fb_copyarea *area) 
 {
-    /*
-     *  Fill in a pointer with the virtual address of the mapped frame buffer.
-     *  Fill in a pointer to appropriate low level text console operations (and
-     *  optionally a pointer to help data) for the video mode `par' of your
-     *  video hardware. These can be generic software routines, or hardware
-     *  accelerated routines specifically tailored for your hardware.
-     *  If you don't have any appropriate operations, you must fill in a
-     *  pointer to dummy operations, and there will be no text output.
-     */
-#ifdef FBCON_HAS_CFB8
-    if (is_cfb8) {
-	disp->dispsw = fbcon_cfb8;
-    } else
-#endif
-#ifdef FBCON_HAS_CFB16
-    if (is_cfb16) {
-	disp->dispsw = fbcon_cfb16;
-	disp->dispsw_data = ...fbcon_cmap.cfb16;	/* console palette */
-    } else
-#endif
-#ifdef FBCON_HAS_CFB24
-    if (is_cfb24) {
-	disp->dispsw = fbcon_cfb24;
-	disp->dispsw_data = ...fbcon_cmap.cfb24;	/* console palette */
-    } else
-#endif
-#ifdef FBCON_HAS_CFB32
-    if (is_cfb32) {
-	disp->dispsw = fbcon_cfb32;
-	disp->dispsw_data = ...fbcon_cmap.cfb32;	/* console palette */
-    } else
-#endif
-	disp->dispsw = &fbcon_dummy;
 }
 
-
-/* ------------ Interfaces to hardware functions ------------ */
-
-
-struct fbgen_hwswitch xxx_switch = {
-    xxx_detect, xxx_encode_fix, xxx_decode_var, xxx_encode_var, xxx_get_par,
-    xxx_set_par, xxx_getcolreg, xxx_pan_display, xxx_blank,
-    xxx_set_disp
-};
-
-
+/**
+ *      xxxfb_imageblit - REQUIRED function. Can use generic routines if
+ *                        non acclerated hardware and packed pixel based.
+ *                        Copies a image from system memory to the screen. 
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *	@image:	structure defining the image.
+ *
+ *      This drawing operation draws a image on the screen. It can be a 
+ *	mono image (needed for font handling) or a color image (needed for
+ *	tux). 
+ */
+void xxxfb_imageblit(struct fb_info *p, struct fb_image *image) 
+{
+}
 
 /* ------------ Hardware Independent Functions ------------ */
 
-
     /*
      *  Initialization
      */
 
 int __init xxxfb_init(void)
 {
-    fb_info.gen.fbhw = &xxx_switch;
-    fb_info.gen.fbhw->detect();
-    strcpy(fb_info.gen.info.modename, "XXX");
-    fb_info.gen.info.changevar = NULL;
-    fb_info.gen.info.node = NODEV;
-    fb_info.gen.info.fbops = &xxxfb_ops;
-    fb_info.gen.info.screen_base = virtual_frame_buffer_address;
-    fb_info.gen.info.disp = &disp;
-    fb_info.gen.info.currcon = -1;
-    fb_info.gen.info.switch_con = &xxxfb_switch;
-    fb_info.gen.info.updatevar = &xxxfb_update_var;
-    fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
-    /* This should give a reasonable default video mode */
-    fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
-    fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
-    fbgen_set_disp(-1, &fb_info.gen);
-    do_install_cmap(0, &fb_info.gen);
-    if (register_framebuffer(&fb_info.gen.info) < 0)
+    int cmap_len, retval;	
+   
+    /* 
+     * Here we set the screen_base to the vitrual memory address
+     * for the framebuffer. Usually we obtain the resource address
+     * from the bus layer and then translate it to virtual memory
+     * space via ioremap. Consult ioport.h. 
+     */
+    info.screen_base = framebuffer_virtual_memory;	
+    info.node = NODEV;
+    info.fbops = &xxxfb_ops;
+    info.fix = xxxfb_fix;
+    info.pseudo_palette = pseudo_palette;
+    info.flags = FBINFO_FLAG_DEFAULT;
+    info.par = current_par;
+
+    /* The following has to be set but in th efuture will go away */
+    strcpy(info.modename, xxxfb_fix.id);
+    info.changevar = NULL;
+    info.currcon = -1;
+    info.disp = &disp; 			
+    info.switch_con = gen_switch;
+    info.updatevar = gen_update_var;
+    
+
+    /*
+     * This should give a reasonable default video mode. The following is
+     * done when we can set a video mode. 
+     */
+    if (!mode_option)
+	mode_option = "640x480@60";	 	
+
+    retval = fb_find_mode(&info.var, &info, mode_option, NULL, 0, NULL, 8);
+  
+    if (!retval || retval == 4)
+	return -EINVAL;			
+
+    /* This has to been done !!! */	
+    fb_alloc_cmap(&info.cmap, cmap_len, 0);
+	
+    /* 
+     * The following is done in the case of having hardware with a static 
+     * mode. If we are setting the mode ourselves we don't call this. 
+     */	
+    info.var = xxxfb_var;
+    gen_set_disp(-1, &fb_info);
+	
+    if (register_framebuffer(&info) < 0)
 	return -EINVAL;
-    printk(KERN_INFO "fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.gen.info.node),
-	   fb_info.gen.info.modename);
-
-    /* uncomment this if your driver cannot be unloaded */
-    /* MOD_INC_USE_COUNT; */
+    printk(KERN_INFO "fb%d: %s frame buffer device\n", GET_FB_IDX(info.node),
+	   info.fix.id);
     return 0;
 }
 
-
     /*
      *  Cleanup
      */
 
-void xxxfb_cleanup(struct fb_info *info)
+static void __exit xxxfb_cleanup(void)
 {
     /*
      *  If your driver supports multiple boards, you should unregister and
@@ -343,11 +474,14 @@
     /* ... */
 }
 
-
     /*
      *  Setup
      */
 
+/* 
+ * Only necessary if your driver takes special options,
+ * otherwise we fall back on the generic fb_setup().
+ */
 int __init xxxfb_setup(char *options)
 {
     /* Parse user speficied options (`video=xxxfb:') */
@@ -356,7 +490,6 @@
 
 /* ------------------------------------------------------------------------- */
 
-
     /*
      *  Frame buffer operations
      */
@@ -373,28 +506,29 @@
     return 0;
 }
 
-
-    /*
-     *  In most cases the `generic' routines (fbgen_*) should be satisfactory.
-     *  However, you're free to fill in your own replacements.
-     */
-
 static struct fb_ops xxxfb_ops = {
 	owner:		THIS_MODULE,
 	fb_open:	xxxfb_open,    /* only if you need it to do something */
 	fb_release:	xxxfb_release, /* only if you need it to do something */
-	fb_get_fix:	fbgen_get_fix,
-	fb_get_var:	fbgen_get_var,
-	fb_set_var:	fbgen_set_var,
-	fb_get_cmap:	fbgen_get_cmap,
+	/* Stuff to go away. Use generic functions for now */
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,	
+	fb_get_cmap:	gen_get_cmap,
 	fb_set_cmap:	gen_set_cmap,
+
+	fb_check_var:	xxxfb_check_var,
+	fb_set_par:	xxxfb_set_par,	   /* optional */	
 	fb_setcolreg:	xxxfb_setcolreg,
-	fb_pan_display:	fbgen_pan_display,
-	fb_blank:	fbgen_blank,
-	fb_ioctl:	xxxfb_ioctl,   /* optional */
+	fb_blank:	xxxfb_blank,	   /* optional */
+	fb_pan_display:	xxxfb_pan_display, /* optional */	
+	fb_fillrect:	xxxfb_fillrect,  
+	fb_copyarea:	xxxfb_copyarea,  
+	fb_imageblit:	xxxfb_imageblit, 
+	fb_ioctl:       xxxfb_ioctl,     /* optional */
+	fb_mmap:	xxxfb_mmap,      /* optional */	
 };
 
-
 /* ------------------------------------------------------------------------- */
 
 
@@ -403,14 +537,8 @@
      */
 
 #ifdef MODULE
-MODULE_LICENSE("GPL");
-int init_module(void)
-{
-    return xxxfb_init();
-}
+module_init(xxxfb_init);
+#endif 
+module_exit(xxxfb_cleanup);
 
-void cleanup_module(void)
-{
-    xxxfb_cleanup(void);
-}
-#endif /* MODULE */
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
--- a/drivers/video/tdfxfb.c	Wed May 29 11:43:02 2002
+++ b/drivers/video/tdfxfb.c	Wed May 29 11:43:02 2002
@@ -43,6 +43,8 @@
  *
  * Version history:
  *
+ * 0.1.4 (released 2002-05-28) ported over to new fbdev api by James Simmons
+ *
  * 0.1.3 (released 1999-11-02) added Attila's panning support, code
  *			       reorg, hwcursor address page size alignment
  *                             (for mmaping both frame buffer and regs),
@@ -64,174 +66,32 @@
 #include <linux/mm.h>
 #include <linux/tty.h>
 #include <linux/slab.h>
-#include <linux/vmalloc.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/fb.h>
-#include <linux/selection.h>
-#include <linux/console.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/nvram.h>
-#include <linux/kd.h>
-#include <linux/vt_kern.h>
 #include <asm/io.h>
 #include <linux/timer.h>
+#include <linux/spinlock.h>
+
+#include <linux/kd.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
 
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
 
+#include <video/tdfx.h>
 #include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-
-#include <linux/spinlock.h>
 
 #ifndef PCI_DEVICE_ID_3DFX_VOODOO5
 #define PCI_DEVICE_ID_3DFX_VOODOO5	0x0009
 #endif
 
-/* membase0 register offsets */
-#define STATUS		0x00
-#define PCIINIT0	0x04
-#define SIPMONITOR	0x08
-#define LFBMEMORYCONFIG	0x0c
-#define MISCINIT0	0x10
-#define MISCINIT1	0x14
-#define DRAMINIT0	0x18
-#define DRAMINIT1	0x1c
-#define AGPINIT		0x20
-#define TMUGBEINIT	0x24
-#define VGAINIT0	0x28
-#define VGAINIT1	0x2c
-#define DRAMCOMMAND	0x30
-#define DRAMDATA	0x34
-/* reserved             0x38 */
-/* reserved             0x3c */
-#define PLLCTRL0	0x40
-#define PLLCTRL1	0x44
-#define PLLCTRL2	0x48
-#define DACMODE		0x4c
-#define DACADDR		0x50
-#define DACDATA		0x54
-#define RGBMAXDELTA	0x58
-#define VIDPROCCFG	0x5c
-#define HWCURPATADDR	0x60
-#define HWCURLOC	0x64
-#define HWCURC0		0x68
-#define HWCURC1		0x6c
-#define VIDINFORMAT	0x70
-#define VIDINSTATUS	0x74
-#define VIDSERPARPORT	0x78
-#define VIDINXDELTA	0x7c
-#define VIDININITERR	0x80
-#define VIDINYDELTA	0x84
-#define VIDPIXBUFTHOLD	0x88
-#define VIDCHRMIN	0x8c
-#define VIDCHRMAX	0x90
-#define VIDCURLIN	0x94
-#define VIDSCREENSIZE	0x98
-#define VIDOVRSTARTCRD	0x9c
-#define VIDOVRENDCRD	0xa0
-#define VIDOVRDUDX	0xa4
-#define VIDOVRDUDXOFF	0xa8
-#define VIDOVRDVDY	0xac
-/*  ... */
-#define VIDOVRDVDYOFF	0xe0
-#define VIDDESKSTART	0xe4
-#define VIDDESKSTRIDE	0xe8
-#define VIDINADDR0	0xec
-#define VIDINADDR1	0xf0
-#define VIDINADDR2	0xf4
-#define VIDINSTRIDE	0xf8
-#define VIDCUROVRSTART	0xfc
-
-#define INTCTRL		(0x00100000 + 0x04)
-#define CLIP0MIN	(0x00100000 + 0x08)
-#define CLIP0MAX	(0x00100000 + 0x0c)
-#define DSTBASE		(0x00100000 + 0x10)
-#define DSTFORMAT	(0x00100000 + 0x14)
-#define SRCBASE		(0x00100000 + 0x34)
-#define COMMANDEXTRA_2D	(0x00100000 + 0x38)
-#define CLIP1MIN	(0x00100000 + 0x4c)
-#define CLIP1MAX	(0x00100000 + 0x50)
-#define SRCFORMAT	(0x00100000 + 0x54)
-#define SRCSIZE		(0x00100000 + 0x58)
-#define SRCXY		(0x00100000 + 0x5c)
-#define COLORBACK	(0x00100000 + 0x60)
-#define COLORFORE	(0x00100000 + 0x64)
-#define DSTSIZE		(0x00100000 + 0x68)
-#define DSTXY		(0x00100000 + 0x6c)
-#define COMMAND_2D	(0x00100000 + 0x70)
-#define LAUNCH_2D	(0x00100000 + 0x80)
-
-#define COMMAND_3D	(0x00200000 + 0x120)
-
-/* register bitfields (not all, only as needed) */
-
-#define BIT(x) (1UL << (x))
-
-/* COMMAND_2D reg. values */
-#define TDFX_ROP_COPY	     0xcc     // src
-#define TDFX_ROP_INVERT      0x55     // NOT dst
-#define TDFX_ROP_XOR         0x66     // src XOR dst
-
-#define AUTOINC_DSTX                    BIT(10)
-#define AUTOINC_DSTY                    BIT(11)
-#define COMMAND_2D_FILLRECT		0x05
-#define COMMAND_2D_S2S_BITBLT		0x01      // screen to screen
-#define COMMAND_2D_H2S_BITBLT           0x03       // host to screen
-
-
-#define COMMAND_3D_NOP			0x00
-#define STATUS_RETRACE			BIT(6)
-#define STATUS_BUSY			BIT(9)
-#define MISCINIT1_CLUT_INV		BIT(0)
-#define MISCINIT1_2DBLOCK_DIS		BIT(15)
-#define DRAMINIT0_SGRAM_NUM		BIT(26)
-#define DRAMINIT0_SGRAM_TYPE		BIT(27)
-#define DRAMINIT1_MEM_SDRAM		BIT(30)
-#define VGAINIT0_VGA_DISABLE		BIT(0)
-#define VGAINIT0_EXT_TIMING		BIT(1)
-#define VGAINIT0_8BIT_DAC		BIT(2)
-#define VGAINIT0_EXT_ENABLE		BIT(6)
-#define VGAINIT0_WAKEUP_3C3		BIT(8)
-#define VGAINIT0_LEGACY_DISABLE		BIT(9)
-#define VGAINIT0_ALT_READBACK		BIT(10)
-#define VGAINIT0_FAST_BLINK		BIT(11)
-#define VGAINIT0_EXTSHIFTOUT		BIT(12)
-#define VGAINIT0_DECODE_3C6		BIT(13)
-#define VGAINIT0_SGRAM_HBLANK_DISABLE	BIT(22)
-#define VGAINIT1_MASK			0x1fffff
-#define VIDCFG_VIDPROC_ENABLE		BIT(0)
-#define VIDCFG_CURS_X11			BIT(1)
-#define VIDCFG_HALF_MODE		BIT(4)
-#define VIDCFG_DESK_ENABLE		BIT(7)
-#define VIDCFG_CLUT_BYPASS		BIT(10)
-#define VIDCFG_2X			BIT(26)
-#define VIDCFG_HWCURSOR_ENABLE          BIT(27)
-#define VIDCFG_PIXFMT_SHIFT		18
-#define DACMODE_2X			BIT(0)
-
-/* VGA rubbish, need to change this for multihead support */
-#define MISC_W 	0x3c2
-#define MISC_R 	0x3cc
-#define SEQ_I 	0x3c4
-#define SEQ_D	0x3c5
-#define CRT_I	0x3d4
-#define CRT_D	0x3d5
-#define ATT_IW	0x3c0
-#define IS1_R	0x3da
-#define GRA_I	0x3ce
-#define GRA_D	0x3cf
-
-#ifndef FB_ACCEL_3DFX_BANSHEE 
-#define FB_ACCEL_3DFX_BANSHEE 31
-#endif
-
 #define TDFXF_HSYNC_ACT_HIGH	0x01
 #define TDFXF_HSYNC_ACT_LOW	0x02
 #define TDFXF_VSYNC_ACT_HIGH	0x04
@@ -247,285 +107,235 @@
 #define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b)
 #else
 #define DPRINTK(a,b...)
-#endif 
-
-#define PICOS2KHZ(a) (1000000000UL/(a))
-#define KHZ2PICOS(a) (1000000000UL/(a))
+#endif
 
 #define BANSHEE_MAX_PIXCLOCK 270000.0
 #define VOODOO3_MAX_PIXCLOCK 300000.0
 #define VOODOO5_MAX_PIXCLOCK 350000.0
 
-struct banshee_reg {
-  /* VGA rubbish */
-  unsigned char att[21];
-  unsigned char crt[25];
-  unsigned char gra[ 9];
-  unsigned char misc[1];
-  unsigned char seq[ 5];
-
-  /* Banshee extensions */
-  unsigned char ext[2];
-  unsigned long vidcfg;
-  unsigned long vidpll;
-  unsigned long mempll;
-  unsigned long gfxpll;
-  unsigned long dacmode;
-  unsigned long vgainit0;
-  unsigned long vgainit1;
-  unsigned long screensize;
-  unsigned long stride;
-  unsigned long cursloc;
-  unsigned long curspataddr;
-  unsigned long cursc0;
-  unsigned long cursc1;
-  unsigned long startaddr;
-  unsigned long clip0min;
-  unsigned long clip0max;
-  unsigned long clip1min;
-  unsigned long clip1max;
-  unsigned long srcbase;
-  unsigned long dstbase;
-  unsigned long miscinit0;
-};
-
 struct tdfxfb_par {
-  u32 pixclock;
+	u32 pixclock;
 
-  u32 baseline;
+	u32 baseline;
 
-  u32 width;
-  u32 height;
-  u32 width_virt;
-  u32 height_virt;
-  u32 lpitch; /* line pitch, in bytes */
-  u32 ppitch; /* pixel pitch, in bits */
-  u32 bpp;    
-
-  u32 hdispend;
-  u32 hsyncsta;
-  u32 hsyncend;
-  u32 htotal;
-
-  u32 vdispend;
-  u32 vsyncsta;
-  u32 vsyncend;
-  u32 vtotal;
-
-  u32 video;
-  u32 accel_flags;
-  u32 cmap_len;
+	u32 width;
+	u32 height;
+	u32 width_virt;
+	u32 height_virt;
+	u32 lpitch;		/* line pitch, in bytes */
+	u32 ppitch;		/* pixel pitch, in bits */
+	u32 bpp;
+
+	u32 hdispend;
+	u32 hsyncsta;
+	u32 hsyncend;
+	u32 htotal;
+
+	u32 vdispend;
+	u32 vsyncsta;
+	u32 vsyncend;
+	u32 vtotal;
+
+	u32 video;
+	u32 accel_flags;
+	u32 cmap_len;
 };
 
 struct fb_info_tdfx {
-  struct fb_info fb_info;
+	struct fb_info fb_info;
 
-  u16 dev;
-  u32 max_pixclock;
+	u16 dev;
+	u32 max_pixclock;
 
-  unsigned long regbase_phys;
-  void *regbase_virt;
-  unsigned long regbase_size;
-  unsigned long bufbase_phys;
-  void *bufbase_virt;
-  unsigned long bufbase_size;
-  unsigned long iobase;
-
-  struct { unsigned red, green, blue, pad; } palette[256];
-  struct tdfxfb_par default_par;
-  struct tdfxfb_par current_par;
-  struct display disp;
-#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)  
-  union {
+	unsigned long regbase_phys;
+	void *regbase_virt;
+	unsigned long regbase_size;
+	unsigned long bufbase_phys;
+	void *bufbase_virt;
+	unsigned long bufbase_size;
+	unsigned long iobase;
+
+	struct {
+		unsigned red, green, blue, pad;
+	} palette[256];
+	struct tdfxfb_par default_par;
+	struct tdfxfb_par current_par;
+	struct display disp;
+#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)
+	union {
 #ifdef FBCON_HAS_CFB16
-    u16 cfb16[16];
+		u16 cfb16[16];
 #endif
 #ifdef FBCON_HAS_CFB24
-    u32 cfb24[16];
+		u32 cfb24[16];
 #endif
 #ifdef FBCON_HAS_CFB32
-    u32 cfb32[16];
+		u32 cfb32[16];
 #endif
-  } fbcon_cmap;
+	} fbcon_cmap;
 #endif
-  struct { 
-     int type;             
-     int state;             
-     int w,u,d;             
-     int x,y,redraw;
-     unsigned long enable,disable;    
-     unsigned long cursorimage;       
-     struct timer_list timer;
-  } cursor;
- 
-  spinlock_t DAClock; 
+	struct {
+		int type;
+		int state;
+		int w, u, d;
+		int x, y, redraw;
+		unsigned long enable, disable;
+		unsigned long cursorimage;
+		struct timer_list timer;
+	} cursor;
+
+	spinlock_t DAClock;
 #ifdef CONFIG_MTRR
-  int mtrr_idx;
+	int mtrr_idx;
 #endif
 };
 
 /*
  *  Frame buffer device API
  */
-static int tdfxfb_get_fix(struct fb_fix_screeninfo* fix, 
-			  int con,
-			  struct fb_info* fb);
-static int tdfxfb_get_var(struct fb_var_screeninfo* var, 
-			  int con,
-			  struct fb_info* fb);
-static int tdfxfb_set_var(struct fb_var_screeninfo* var,
-			  int con,
-			  struct fb_info* fb);
-static int  tdfxfb_setcolreg(u_int regno, 
-			     u_int red, 
-			     u_int green, 
-			     u_int blue,
-			     u_int transp, 
-			     struct fb_info* fb);
-static int tdfxfb_pan_display(struct fb_var_screeninfo* var, 
-			      int con,
-			      struct fb_info* fb);
-static int tdfxfb_get_cmap(struct fb_cmap *cmap, 
-			   int kspc, 
-			   int con,
-			   struct fb_info* info);
-static int tdfxfb_set_cmap(struct fb_cmap* cmap, 
-			   int kspc, 
-			   int con,
-			   struct fb_info* info);
+static int tdfxfb_get_fix(struct fb_fix_screeninfo *fix,
+			  int con, struct fb_info *fb);
+static int tdfxfb_get_var(struct fb_var_screeninfo *var,
+			  int con, struct fb_info *fb);
+static int tdfxfb_set_var(struct fb_var_screeninfo *var,
+			  int con, struct fb_info *fb);
+static int tdfxfb_setcolreg(u_int regno,
+			    u_int red,
+			    u_int green,
+			    u_int blue, u_int transp, struct fb_info *fb);
+static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
+			      int con, struct fb_info *fb);
+static int tdfxfb_get_cmap(struct fb_cmap *cmap,
+			   int kspc, int con, struct fb_info *info);
+static int tdfxfb_set_cmap(struct fb_cmap *cmap,
+			   int kspc, int con, struct fb_info *info);
 
 /*
  *  Interface to the low level console driver
  */
-static int  tdfxfb_switch_con(int con, 
-			      struct fb_info* fb);
-static int  tdfxfb_updatevar(int con, 
-			     struct fb_info* fb);
-static int tdfxfb_blank(int blank, 
-			 struct fb_info* fb);
+static int tdfxfb_switch_con(int con, struct fb_info *fb);
+static int tdfxfb_updatevar(int con, struct fb_info *fb);
+static int tdfxfb_blank(int blank, struct fb_info *fb);
 
 /*
  *  Internal routines
  */
-static void tdfxfb_set_par(const struct tdfxfb_par* par,
-			   struct fb_info_tdfx* 
-			   info);
-static int  tdfxfb_decode_var(const struct fb_var_screeninfo *var,
-			      struct tdfxfb_par *par,
-			      const struct fb_info_tdfx *info);
-static int  tdfxfb_encode_var(struct fb_var_screeninfo* var,
-			      const struct tdfxfb_par* par,
-			      const struct fb_info_tdfx* info);
-static int  tdfxfb_encode_fix(struct fb_fix_screeninfo* fix,
-			      const struct tdfxfb_par* par,
-			      const struct fb_info_tdfx* info);
-static void tdfxfb_set_dispsw(struct display* disp, 
-			      struct fb_info_tdfx* info,
-			      int bpp, 
-			      int accel);
-static int  tdfxfb_getcolreg(u_int regno,
-			     u_int* red, 
-			     u_int* green, 
-			     u_int* blue,
-			     u_int* transp, 
-			     struct fb_info* fb);
+static void tdfxfb_set_par(const struct tdfxfb_par *par,
+			   struct fb_info_tdfx *info);
+static int tdfxfb_decode_var(const struct fb_var_screeninfo *var,
+			     struct tdfxfb_par *par,
+			     const struct fb_info_tdfx *info);
+static int tdfxfb_encode_var(struct fb_var_screeninfo *var,
+			     const struct tdfxfb_par *par,
+			     const struct fb_info_tdfx *info);
+static int tdfxfb_encode_fix(struct fb_fix_screeninfo *fix,
+			     const struct tdfxfb_par *par,
+			     const struct fb_info_tdfx *info);
+static void tdfxfb_set_dispsw(struct display *disp,
+			      struct fb_info_tdfx *info,
+			      int bpp, int accel);
+static int tdfxfb_getcolreg(u_int regno,
+			    u_int * red,
+			    u_int * green,
+			    u_int * blue,
+			    u_int * transp, struct fb_info *fb);
 
 static void tdfxfb_hwcursor_init(void);
-static void tdfxfb_createcursorshape(struct display* p);
-static void tdfxfb_createcursor(struct display * p);  
+static void tdfxfb_createcursorshape(struct display *p);
+static void tdfxfb_createcursor(struct display *p);
 
 /*
  * do_xxx: Hardware-specific functions
  */
-static void  do_pan_var(struct fb_var_screeninfo* var, struct fb_info_tdfx *i);
-static void  do_flashcursor(unsigned long ptr);
-static void  do_bitblt(u32 curx, u32 cury, u32 dstx,u32 dsty, 
-		      u32 width, u32 height,u32 stride,u32 bpp);
-static void  do_fillrect(u32 x, u32 y, u32 w,u32 h, 
-			u32 color,u32 stride,u32 bpp,u32 rop);
-static void  do_putc(u32 fgx, u32 bgx,struct display *p,
-			int c, int yy,int xx);
-static void  do_putcs(u32 fgx, u32 bgx,struct display *p,
-		     const unsigned short *s,int count, int yy,int xx);
-static u32 do_calc_pll(int freq, int* freq_out);
-static void  do_write_regs(struct banshee_reg* reg);
+static void do_pan_var(struct fb_var_screeninfo *var,
+		       struct fb_info_tdfx *i);
+static void do_flashcursor(unsigned long ptr);
+static void do_bitblt(u32 curx, u32 cury, u32 dstx, u32 dsty,
+		      u32 width, u32 height, u32 stride, u32 bpp);
+static void do_fillrect(u32 x, u32 y, u32 w, u32 h,
+			u32 color, u32 stride, u32 bpp, u32 rop);
+static void do_putc(u32 fgx, u32 bgx, struct display *p,
+		    int c, int yy, int xx);
+static void do_putcs(u32 fgx, u32 bgx, struct display *p,
+		     const unsigned short *s, int count, int yy, int xx);
+static u32 do_calc_pll(int freq, int *freq_out);
+static void do_write_regs(struct banshee_reg *reg);
 static unsigned long do_lfb_size(void);
 
 /*
  *  Interface used by the world
  */
 int tdfxfb_init(void);
-void tdfxfb_setup(char *options, 
-		  int *ints);
+void tdfxfb_setup(char *options, int *ints);
 
 /*
  * PCI driver prototypes
  */
-static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static int tdfxfb_probe(struct pci_dev *pdev,
+			const struct pci_device_id *id);
 static void tdfxfb_remove(struct pci_dev *pdev);
 
 static struct fb_ops tdfxfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	tdfxfb_get_fix,
-	fb_get_var:	tdfxfb_get_var,
-	fb_set_var:	tdfxfb_set_var,
-	fb_get_cmap:	tdfxfb_get_cmap,
-	fb_set_cmap:	tdfxfb_set_cmap,
-	fb_setcolreg:	tdfxfb_setcolreg,
-	fb_pan_display:	tdfxfb_pan_display,
-	fb_blank:	tdfxfb_blank,
+	owner:THIS_MODULE,
+	fb_get_fix:tdfxfb_get_fix,
+	fb_get_var:tdfxfb_get_var,
+	fb_set_var:tdfxfb_set_var,
+	fb_get_cmap:tdfxfb_get_cmap,
+	fb_set_cmap:tdfxfb_set_cmap,
+	fb_setcolreg:tdfxfb_setcolreg,
+	fb_pan_display:tdfxfb_pan_display,
+	fb_blank:tdfxfb_blank,
 };
 
 static struct pci_device_id tdfxfb_id_table[] __devinitdata = {
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE,
-	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
-	  0xff0000, 0 },
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3,
-	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
-	  0xff0000, 0 },
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5,
-	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
-	  0xff0000, 0 },
-	{ 0, }
+	{PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE,
+	 PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	 0xff0000, 0},
+	{PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3,
+	 PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	 0xff0000, 0},
+	{PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5,
+	 PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	 0xff0000, 0},
+	{0,}
 };
 
 static struct pci_driver tdfxfb_driver = {
-	name:		"tdfxfb",
-	id_table:	tdfxfb_id_table,
-	probe:		tdfxfb_probe,
-	remove:		__devexit_p(tdfxfb_remove),
+	name:"tdfxfb",
+	id_table:tdfxfb_id_table,
+	probe:tdfxfb_probe,
+	remove:__devexit_p(tdfxfb_remove),
 };
 
 MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
 
 struct mode {
-  char* name;
-  struct fb_var_screeninfo var;
+	char *name;
+	struct fb_var_screeninfo var;
 } mode;
 
 /* 2.3.x kernels have a fb mode database, so supply only one backup default */
 struct mode default_mode[] = {
-  { "640x480-8@60", /* @ 60 Hz */
-    {
-      640, 480, 640, 1024, 0, 0, 8, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT, 
-      39722, 40, 24, 32, 11, 96, 2,
-      0, FB_VMODE_NONINTERLACED
-    }
-  }
+	{"640x480-8@60",	/* @ 60 Hz */
+	 {
+	  640, 480, 640, 1024, 0, 0, 8, 0,
+	  {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	  0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
+	  39722, 40, 24, 32, 11, 96, 2,
+	  0, FB_VMODE_NONINTERLACED}
+	 }
 };
 
 static struct fb_info_tdfx fb_info;
 
-static int  noaccel = 0;
-static int  nopan   = 0;
-static int  nowrap  = 1;      // not implemented (yet)
-static int  inverse = 0;
+static int noaccel = 0;
+static int nopan = 0;
+static int nowrap = 1;		// not implemented (yet)
+static int inverse = 0;
 #ifdef CONFIG_MTRR
-static int  nomtrr = 0;
+static int nomtrr = 0;
 #endif
-static int  nohwcursor = 0;
+static int nohwcursor = 0;
 static char __initdata fontname[40] = { 0 };
 static char *mode_option __initdata = NULL;
 
@@ -533,476 +343,554 @@
  *                      Hardware-specific funcions
  * ------------------------------------------------------------------------- */
 
-#ifdef VGA_REG_IO 
-static inline  u8 vga_inb(u32 reg) { return inb(reg); }
-static inline u16 vga_inw(u32 reg) { return inw(reg); }
-static inline u16 vga_inl(u32 reg) { return inl(reg); }
-
-static inline void vga_outb(u32 reg,  u8 val) { outb(val, reg); }
-static inline void vga_outw(u32 reg, u16 val) { outw(val, reg); }
-static inline void vga_outl(u32 reg, u32 val) { outl(val, reg); }
+#ifdef VGA_REG_IO
+static inline u8 vga_inb(u32 reg)
+{
+	return inb(reg);
+}
+static inline u16 vga_inw(u32 reg)
+{
+	return inw(reg);
+}
+static inline u16 vga_inl(u32 reg)
+{
+	return inl(reg);
+}
+
+static inline void vga_outb(u32 reg, u8 val)
+{
+	outb(val, reg);
+}
+static inline void vga_outw(u32 reg, u16 val)
+{
+	outw(val, reg);
+}
+static inline void vga_outl(u32 reg, u32 val)
+{
+	outl(val, reg);
+}
 #else
-static inline  u8 vga_inb(u32 reg) { 
-  return inb(fb_info.iobase + reg - 0x300); 
+static inline u8 vga_inb(u32 reg)
+{
+	return inb(fb_info.iobase + reg - 0x300);
 }
-static inline u16 vga_inw(u32 reg) { 
-  return inw(fb_info.iobase + reg - 0x300); 
+static inline u16 vga_inw(u32 reg)
+{
+	return inw(fb_info.iobase + reg - 0x300);
 }
-static inline u16 vga_inl(u32 reg) { 
-  return inl(fb_info.iobase + reg - 0x300); 
+static inline u16 vga_inl(u32 reg)
+{
+	return inl(fb_info.iobase + reg - 0x300);
 }
 
-static inline void vga_outb(u32 reg,  u8 val) { 
-  outb(val, fb_info.iobase + reg - 0x300); 
+static inline void vga_outb(u32 reg, u8 val)
+{
+	outb(val, fb_info.iobase + reg - 0x300);
 }
-static inline void vga_outw(u32 reg, u16 val) { 
-  outw(val, fb_info.iobase + reg - 0x300); 
+static inline void vga_outw(u32 reg, u16 val)
+{
+	outw(val, fb_info.iobase + reg - 0x300);
 }
-static inline void vga_outl(u32 reg, u32 val) { 
-  outl(val, fb_info.iobase + reg - 0x300); 
+static inline void vga_outl(u32 reg, u32 val)
+{
+	outl(val, fb_info.iobase + reg - 0x300);
 }
 #endif
 
-static inline void gra_outb(u32 idx, u8 val) {
-  vga_outb(GRA_I, idx); vga_outb(GRA_D, val);
+static inline void gra_outb(u32 idx, u8 val)
+{
+	vga_outb(GRA_I, idx);
+	vga_outb(GRA_D, val);
 }
 
-static inline u8 gra_inb(u32 idx) {
-  vga_outb(GRA_I, idx); return vga_inb(GRA_D);
+static inline u8 gra_inb(u32 idx)
+{
+	vga_outb(GRA_I, idx);
+	return vga_inb(GRA_D);
 }
 
-static inline void seq_outb(u32 idx, u8 val) {
-  vga_outb(SEQ_I, idx); vga_outb(SEQ_D, val);
+static inline void seq_outb(u32 idx, u8 val)
+{
+	vga_outb(SEQ_I, idx);
+	vga_outb(SEQ_D, val);
 }
 
-static inline u8 seq_inb(u32 idx) {
-  vga_outb(SEQ_I, idx); return vga_inb(SEQ_D);
+static inline u8 seq_inb(u32 idx)
+{
+	vga_outb(SEQ_I, idx);
+	return vga_inb(SEQ_D);
 }
 
-static inline void crt_outb(u32 idx, u8 val) {
-  vga_outb(CRT_I, idx); vga_outb(CRT_D, val);
+static inline void crt_outb(u32 idx, u8 val)
+{
+	vga_outb(CRT_I, idx);
+	vga_outb(CRT_D, val);
 }
 
-static inline u8 crt_inb(u32 idx) {
-  vga_outb(CRT_I, idx); return vga_inb(CRT_D);
+static inline u8 crt_inb(u32 idx)
+{
+	vga_outb(CRT_I, idx);
+	return vga_inb(CRT_D);
 }
 
-static inline void att_outb(u32 idx, u8 val) {
-  unsigned char tmp;
-  tmp = vga_inb(IS1_R);
-  vga_outb(ATT_IW, idx);
-  vga_outb(ATT_IW, val);
+static inline void att_outb(u32 idx, u8 val)
+{
+	unsigned char tmp;
+	tmp = vga_inb(IS1_R);
+	vga_outb(ATT_IW, idx);
+	vga_outb(ATT_IW, val);
 }
 
-static inline u8 att_inb(u32 idx) {
-  unsigned char tmp;
-  tmp = vga_inb(IS1_R);
-  vga_outb(ATT_IW, idx);
-  return vga_inb(ATT_IW);
+static inline u8 att_inb(u32 idx)
+{
+	unsigned char tmp;
+	tmp = vga_inb(IS1_R);
+	vga_outb(ATT_IW, idx);
+	return vga_inb(ATT_IW);
 }
 
-static inline void vga_disable_video(void) {
-  unsigned char s;
-  s = seq_inb(0x01) | 0x20;
-  seq_outb(0x00, 0x01);
-  seq_outb(0x01, s);
-  seq_outb(0x00, 0x03);
+static inline void vga_disable_video(void)
+{
+	unsigned char s;
+	s = seq_inb(0x01) | 0x20;
+	seq_outb(0x00, 0x01);
+	seq_outb(0x01, s);
+	seq_outb(0x00, 0x03);
 }
 
-static inline void vga_enable_video(void) {
-  unsigned char s;
-  s = seq_inb(0x01) & 0xdf;
-  seq_outb(0x00, 0x01);
-  seq_outb(0x01, s);
-  seq_outb(0x00, 0x03);
+static inline void vga_enable_video(void)
+{
+	unsigned char s;
+	s = seq_inb(0x01) & 0xdf;
+	seq_outb(0x00, 0x01);
+	seq_outb(0x01, s);
+	seq_outb(0x00, 0x03);
 }
 
-static inline void vga_disable_palette(void) {
-  vga_inb(IS1_R);
-  vga_outb(ATT_IW, 0x00);
+static inline void vga_disable_palette(void)
+{
+	vga_inb(IS1_R);
+	vga_outb(ATT_IW, 0x00);
 }
 
-static inline void vga_enable_palette(void) {
-  vga_inb(IS1_R);
-  vga_outb(ATT_IW, 0x20);
+static inline void vga_enable_palette(void)
+{
+	vga_inb(IS1_R);
+	vga_outb(ATT_IW, 0x20);
 }
 
-static inline u32 tdfx_inl(unsigned int reg) {
-  return readl(fb_info.regbase_virt + reg);
+static inline u32 tdfx_inl(unsigned int reg)
+{
+	return readl(fb_info.regbase_virt + reg);
 }
 
-static inline void tdfx_outl(unsigned int reg, u32 val) {
-  writel(val, fb_info.regbase_virt + reg);
+static inline void tdfx_outl(unsigned int reg, u32 val)
+{
+	writel(val, fb_info.regbase_virt + reg);
 }
 
-static inline void banshee_make_room(int size) {
-  while((tdfx_inl(STATUS) & 0x1f) < size);
+static inline void banshee_make_room(int size)
+{
+	while ((tdfx_inl(STATUS) & 0x1f) < size);
 }
- 
-static inline void banshee_wait_idle(void) {
-  int i = 0;
 
-  banshee_make_room(1);
-  tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
+static inline void banshee_wait_idle(void)
+{
+	int i = 0;
+
+	banshee_make_room(1);
+	tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
 
-  while(1) {
-    i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1;
-    if(i == 3) break;
-  }
+	while (1) {
+		i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1;
+		if (i == 3)
+			break;
+	}
 }
+
 /*
  * Set the color of a palette entry in 8bpp mode 
  */
-static inline void do_setpalentry(unsigned regno, u32 c) {  
-   banshee_make_room(2); tdfx_outl(DACADDR,  regno); tdfx_outl(DACDATA,  c); }
+static inline void do_setpalentry(unsigned regno, u32 c)
+{
+	banshee_make_room(2);
+	tdfx_outl(DACADDR, regno);
+	tdfx_outl(DACDATA, c);
+}
 
 /* 
  * Set the starting position of the visible screen to var->yoffset 
  */
-static void do_pan_var(struct fb_var_screeninfo* var, struct fb_info_tdfx *i)
+static void do_pan_var(struct fb_var_screeninfo *var,
+		       struct fb_info_tdfx *i)
 {
-    u32 addr;
-    addr = var->yoffset*i->current_par.lpitch;
-    banshee_make_room(1);
-    tdfx_outl(VIDDESKSTART, addr);
+	u32 addr;
+	addr = var->yoffset * i->current_par.lpitch;
+	banshee_make_room(1);
+	tdfx_outl(VIDDESKSTART, addr);
 }
-   
+
 /*
  * Invert the hardware cursor image (timerfunc)  
  */
 static void do_flashcursor(unsigned long ptr)
 {
-   struct fb_info_tdfx* i=(struct fb_info_tdfx *)ptr;
-   unsigned long flags;
+	struct fb_info_tdfx *i = (struct fb_info_tdfx *) ptr;
+	unsigned long flags;
 
-   spin_lock_irqsave(&i->DAClock, flags);
-   banshee_make_room(1);
-   tdfx_outl( VIDPROCCFG, tdfx_inl(VIDPROCCFG) ^ VIDCFG_HWCURSOR_ENABLE );
-   i->cursor.timer.expires=jiffies+HZ/2;
-   add_timer(&i->cursor.timer);
-   spin_unlock_irqrestore(&i->DAClock, flags);
+	spin_lock_irqsave(&i->DAClock, flags);
+	banshee_make_room(1);
+	tdfx_outl(VIDPROCCFG,
+		  tdfx_inl(VIDPROCCFG) ^ VIDCFG_HWCURSOR_ENABLE);
+	i->cursor.timer.expires = jiffies + HZ / 2;
+	add_timer(&i->cursor.timer);
+	spin_unlock_irqrestore(&i->DAClock, flags);
 }
 
 /*
  * FillRect 2D command (solidfill or invert (via ROP_XOR))   
  */
-static void do_fillrect(u32 x, u32 y, u32 w, u32 h, 
-			u32 color, u32 stride, u32 bpp, u32 rop) {
+static void do_fillrect(u32 x, u32 y, u32 w, u32 h,
+			u32 color, u32 stride, u32 bpp, u32 rop)
+{
 
-   u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); 
+	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
 
-   banshee_make_room(5);
-   tdfx_outl(DSTFORMAT, fmt);
-   tdfx_outl(COLORFORE, color);
-   tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (rop << 24));
-   tdfx_outl(DSTSIZE,    w | (h << 16));
-   tdfx_outl(LAUNCH_2D,  x | (y << 16));
-   banshee_wait_idle();
+	banshee_make_room(5);
+	tdfx_outl(DSTFORMAT, fmt);
+	tdfx_outl(COLORFORE, color);
+	tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (rop << 24));
+	tdfx_outl(DSTSIZE, w | (h << 16));
+	tdfx_outl(LAUNCH_2D, x | (y << 16));
+	banshee_wait_idle();
 }
 
 /*
  * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) 
  */
 
-static void do_bitblt(u32 curx, 
-			   u32 cury, 
-			   u32 dstx,
-			   u32 dsty, 
-			   u32 width, 
-			   u32 height,
-			   u32 stride,
-			   u32 bpp) {
-
-   u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);
-   u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); 
-   
-   if (curx <= dstx) {
-     //-X 
-     blitcmd |= BIT(14);
-     curx += width-1;
-     dstx += width-1;
-   }
-   if (cury <= dsty) {
-     //-Y  
-     blitcmd |= BIT(15);
-     cury += height-1;
-     dsty += height-1;
-   }
-   
-   banshee_make_room(6);
-
-   tdfx_outl(SRCFORMAT, fmt);
-   tdfx_outl(DSTFORMAT, fmt);
-   tdfx_outl(COMMAND_2D, blitcmd); 
-   tdfx_outl(DSTSIZE,   width | (height << 16));
-   tdfx_outl(DSTXY,     dstx | (dsty << 16));
-   tdfx_outl(LAUNCH_2D, curx | (cury << 16)); 
-   banshee_wait_idle();
+static void do_bitblt(u32 curx,
+		      u32 cury,
+		      u32 dstx,
+		      u32 dsty, u32 width, u32 height, u32 stride, u32 bpp)
+{
+
+	u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);
+	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
+
+	if (curx <= dstx) {
+		//-X 
+		blitcmd |= BIT(14);
+		curx += width - 1;
+		dstx += width - 1;
+	}
+	if (cury <= dsty) {
+		//-Y  
+		blitcmd |= BIT(15);
+		cury += height - 1;
+		dsty += height - 1;
+	}
+
+	banshee_make_room(6);
+
+	tdfx_outl(SRCFORMAT, fmt);
+	tdfx_outl(DSTFORMAT, fmt);
+	tdfx_outl(COMMAND_2D, blitcmd);
+	tdfx_outl(DSTSIZE, width | (height << 16));
+	tdfx_outl(DSTXY, dstx | (dsty << 16));
+	tdfx_outl(LAUNCH_2D, curx | (cury << 16));
+	banshee_wait_idle();
 }
 
 static void do_putc(u32 fgx, u32 bgx,
-			 struct display *p,
-			 int c, int yy,int xx)
-{   
-   int i;
-   int stride=fb_info.current_par.lpitch;
-   u32 bpp=fb_info.current_par.bpp;
-   int fw=(fontwidth(p)+7)>>3;
-   u8 *chardata=p->fontdata+(c&p->charmask)*fontheight(p)*fw;
-   u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); 
-   
-   xx *= fontwidth(p);
-   yy *= fontheight(p);
-
-   banshee_make_room(8+((fontheight(p)*fw+3)>>2) );
-   tdfx_outl(COLORFORE, fgx);
-   tdfx_outl(COLORBACK, bgx);
-   tdfx_outl(SRCXY,     0);
-   tdfx_outl(DSTXY,     xx | (yy << 16));
-   tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
-   tdfx_outl(SRCFORMAT, 0x400000);
-   tdfx_outl(DSTFORMAT, fmt);
-   tdfx_outl(DSTSIZE,   fontwidth(p) | (fontheight(p) << 16));
-   i=fontheight(p);
-   switch (fw) {
-    case 1:
-     while (i>=4) {
-         tdfx_outl(LAUNCH_2D,*(u32*)chardata);
-	 chardata+=4;
-	 i-=4;
-     }
-     switch (i) {
-      case 0: break;
-      case 1:  tdfx_outl(LAUNCH_2D,*chardata); break;
-      case 2:  tdfx_outl(LAUNCH_2D,*(u16*)chardata); break;
-      case 3:  tdfx_outl(LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
-     }
-     break;
-   case 2:
-     while (i>=2) {
-         tdfx_outl(LAUNCH_2D,*(u32*)chardata);
-	 chardata+=4;
-	 i-=2;
-     }
-     if (i) tdfx_outl(LAUNCH_2D,*(u16*)chardata); 
-     break;
-   default:
-     // Is there a font with width more that 16 pixels ?
-     for (i=fontheight(p);i>0;i--) {
-	 tdfx_outl(LAUNCH_2D,*(u32*)chardata);
-	 chardata+=4;
-     }
-     break;
-   }
-   banshee_wait_idle();
+		    struct display *p, int c, int yy, int xx)
+{
+	int i;
+	int stride = fb_info.current_par.lpitch;
+	u32 bpp = fb_info.current_par.bpp;
+	int fw = (fontwidth(p) + 7) >> 3;
+	u8 *chardata =
+	    p->fontdata + (c & p->charmask) * fontheight(p) * fw;
+	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
+
+	xx *= fontwidth(p);
+	yy *= fontheight(p);
+
+	banshee_make_room(8 + ((fontheight(p) * fw + 3) >> 2));
+	tdfx_outl(COLORFORE, fgx);
+	tdfx_outl(COLORBACK, bgx);
+	tdfx_outl(SRCXY, 0);
+	tdfx_outl(DSTXY, xx | (yy << 16));
+	tdfx_outl(COMMAND_2D,
+		  COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
+	tdfx_outl(SRCFORMAT, 0x400000);
+	tdfx_outl(DSTFORMAT, fmt);
+	tdfx_outl(DSTSIZE, fontwidth(p) | (fontheight(p) << 16));
+	i = fontheight(p);
+	switch (fw) {
+	case 1:
+		while (i >= 4) {
+			tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
+			chardata += 4;
+			i -= 4;
+		}
+		switch (i) {
+		case 0:
+			break;
+		case 1:
+			tdfx_outl(LAUNCH_2D, *chardata);
+			break;
+		case 2:
+			tdfx_outl(LAUNCH_2D, *(u16 *) chardata);
+			break;
+		case 3:
+			tdfx_outl(LAUNCH_2D,
+				  *(u16 *) chardata | ((chardata[3]) <<
+						       24));
+			break;
+		}
+		break;
+	case 2:
+		while (i >= 2) {
+			tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
+			chardata += 4;
+			i -= 2;
+		}
+		if (i)
+			tdfx_outl(LAUNCH_2D, *(u16 *) chardata);
+		break;
+	default:
+		// Is there a font with width more that 16 pixels ?
+		for (i = fontheight(p); i > 0; i--) {
+			tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
+			chardata += 4;
+		}
+		break;
+	}
+	banshee_wait_idle();
 }
 
 static void do_putcs(u32 fgx, u32 bgx,
-			  struct display *p,
-			  const unsigned short *s,
-			  int count, int yy,int xx)
-{   
-   int i;
-   int stride=fb_info.current_par.lpitch;
-   u32 bpp=fb_info.current_par.bpp;
-   int fw=(fontwidth(p)+7)>>3;
-   int w=fontwidth(p);
-   int h=fontheight(p);
-   int regsneed=1+((h*fw+3)>>2);
-   u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); 
-
-   xx *= w;
-   yy = (yy*h) << 16;
-   banshee_make_room(8);
-
-   tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
-   tdfx_outl(COLORFORE, fgx);
-   tdfx_outl(COLORBACK, bgx);
-   tdfx_outl(SRCFORMAT, 0x400000);
-   tdfx_outl(DSTFORMAT, fmt);
-   tdfx_outl(DSTSIZE, w | (h << 16));
-   tdfx_outl(SRCXY,     0);
-   tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
-   
-   while (count--) {
-      u8 *chardata=p->fontdata+(scr_readw(s++) & p->charmask)*h*fw;
-   
-      banshee_make_room(regsneed);
-      tdfx_outl(DSTXY, xx | yy);
-      xx+=w;
-      
-      i=h;
-      switch (fw) {
-       case 1:
-        while (i>=4) {
-           tdfx_outl(LAUNCH_2D,*(u32*)chardata);
-	   chardata+=4;
-	   i-=4;
-        }
-        switch (i) {
-          case 0: break;
-          case 1:  tdfx_outl(LAUNCH_2D,*chardata); break;
-          case 2:  tdfx_outl(LAUNCH_2D,*(u16*)chardata); break;
-          case 3:  tdfx_outl(LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
-        }
-        break;
-       case 2:
-        while (i>=2) {
-         tdfx_outl(LAUNCH_2D,*(u32*)chardata);
-	 chardata+=4;
-	 i-=2;
-        }
-        if (i) tdfx_outl(LAUNCH_2D,*(u16*)chardata); 
-        break;
-       default:
-       // Is there a font with width more that 16 pixels ?
-        for (;i>0;i--) {
-	  tdfx_outl(LAUNCH_2D,*(u32*)chardata);
-	  chardata+=4;
-        }
-        break;
-     }
-   }
-   banshee_wait_idle();
-}
-
-static u32 do_calc_pll(int freq, int* freq_out) {
-  int m, n, k, best_m, best_n, best_k, f_cur, best_error;
-  int fref = 14318;
-  
-  /* this really could be done with more intelligence --
-     255*63*4 = 64260 iterations is silly */
-  best_error = freq;
-  best_n = best_m = best_k = 0;
-  for(n = 1; n < 256; n++) {
-    for(m = 1; m < 64; m++) {
-      for(k = 0; k < 4; k++) {
-	f_cur = fref*(n + 2)/(m + 2)/(1 << k);
-	if(abs(f_cur - freq) < best_error) {
-	  best_error = abs(f_cur-freq);
-	  best_n = n;
-	  best_m = m;
-	  best_k = k;
-	}
-      }
-    }
-  }
-  n = best_n;
-  m = best_m;
-  k = best_k;
-  *freq_out = fref*(n + 2)/(m + 2)/(1 << k);
-
-  return (n << 8) | (m << 2) | k;
-}
-
-static void do_write_regs(struct banshee_reg* reg) {
-  int i;
-
-  banshee_wait_idle();
-
-  tdfx_outl(MISCINIT1, tdfx_inl(MISCINIT1) | 0x01);
-
-  crt_outb(0x11, crt_inb(0x11) & 0x7f); /* CRT unprotect */
-
-  banshee_make_room(3);
-  tdfx_outl(VGAINIT1,      reg->vgainit1 &  0x001FFFFF);
-  tdfx_outl(VIDPROCCFG,    reg->vidcfg   & ~0x00000001);
+		     struct display *p,
+		     const unsigned short *s, int count, int yy, int xx)
+{
+	int i;
+	int stride = fb_info.current_par.lpitch;
+	u32 bpp = fb_info.current_par.bpp;
+	int fw = (fontwidth(p) + 7) >> 3;
+	int w = fontwidth(p);
+	int h = fontheight(p);
+	int regsneed = 1 + ((h * fw + 3) >> 2);
+	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
+
+	xx *= w;
+	yy = (yy * h) << 16;
+	banshee_make_room(8);
+
+	tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
+	tdfx_outl(COLORFORE, fgx);
+	tdfx_outl(COLORBACK, bgx);
+	tdfx_outl(SRCFORMAT, 0x400000);
+	tdfx_outl(DSTFORMAT, fmt);
+	tdfx_outl(DSTSIZE, w | (h << 16));
+	tdfx_outl(SRCXY, 0);
+	tdfx_outl(COMMAND_2D,
+		  COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
+
+	while (count--) {
+		u8 *chardata =
+		    p->fontdata + (scr_readw(s++) & p->charmask) * h * fw;
+
+		banshee_make_room(regsneed);
+		tdfx_outl(DSTXY, xx | yy);
+		xx += w;
+
+		i = h;
+		switch (fw) {
+		case 1:
+			while (i >= 4) {
+				tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
+				chardata += 4;
+				i -= 4;
+			}
+			switch (i) {
+			case 0:
+				break;
+			case 1:
+				tdfx_outl(LAUNCH_2D, *chardata);
+				break;
+			case 2:
+				tdfx_outl(LAUNCH_2D, *(u16 *) chardata);
+				break;
+			case 3:
+				tdfx_outl(LAUNCH_2D,
+					  *(u16 *) chardata |
+					  ((chardata[3]) << 24));
+				break;
+			}
+			break;
+		case 2:
+			while (i >= 2) {
+				tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
+				chardata += 4;
+				i -= 2;
+			}
+			if (i)
+				tdfx_outl(LAUNCH_2D, *(u16 *) chardata);
+			break;
+		default:
+			// Is there a font with width more that 16 pixels ?
+			for (; i > 0; i--) {
+				tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
+				chardata += 4;
+			}
+			break;
+		}
+	}
+	banshee_wait_idle();
+}
+
+static u32 do_calc_pll(int freq, int *freq_out)
+{
+	int m, n, k, best_m, best_n, best_k, f_cur, best_error;
+	int fref = 14318;
+
+	/* this really could be done with more intelligence --
+	   255*63*4 = 64260 iterations is silly */
+	best_error = freq;
+	best_n = best_m = best_k = 0;
+	for (n = 1; n < 256; n++) {
+		for (m = 1; m < 64; m++) {
+			for (k = 0; k < 4; k++) {
+				f_cur =
+				    fref * (n + 2) / (m + 2) / (1 << k);
+				if (abs(f_cur - freq) < best_error) {
+					best_error = abs(f_cur - freq);
+					best_n = n;
+					best_m = m;
+					best_k = k;
+				}
+			}
+		}
+	}
+	n = best_n;
+	m = best_m;
+	k = best_k;
+	*freq_out = fref * (n + 2) / (m + 2) / (1 << k);
+
+	return (n << 8) | (m << 2) | k;
+}
+
+static void do_write_regs(struct banshee_reg *reg)
+{
+	int i;
+
+	banshee_wait_idle();
+
+	tdfx_outl(MISCINIT1, tdfx_inl(MISCINIT1) | 0x01);
+
+	crt_outb(0x11, crt_inb(0x11) & 0x7f);	/* CRT unprotect */
+
+	banshee_make_room(3);
+	tdfx_outl(VGAINIT1, reg->vgainit1 & 0x001FFFFF);
+	tdfx_outl(VIDPROCCFG, reg->vidcfg & ~0x00000001);
 #if 0
-  tdfx_outl(PLLCTRL1,      reg->mempll);
-  tdfx_outl(PLLCTRL2,      reg->gfxpll);
+	tdfx_outl(PLLCTRL1, reg->mempll);
+	tdfx_outl(PLLCTRL2, reg->gfxpll);
 #endif
-  tdfx_outl(PLLCTRL0,      reg->vidpll);
+	tdfx_outl(PLLCTRL0, reg->vidpll);
 
-  vga_outb(MISC_W, reg->misc[0x00] | 0x01);
+	vga_outb(MISC_W, reg->misc[0x00] | 0x01);
 
-  for(i = 0; i < 5; i++)
-    seq_outb(i, reg->seq[i]);
-
-  for(i = 0; i < 25; i++)
-    crt_outb(i, reg->crt[i]);
-
-  for(i = 0; i < 9; i++)
-    gra_outb(i, reg->gra[i]);
-
-  for(i = 0; i < 21; i++)
-    att_outb(i, reg->att[i]);
-
-  crt_outb(0x1a, reg->ext[0]);
-  crt_outb(0x1b, reg->ext[1]);
-
-  vga_enable_palette();
-  vga_enable_video();
-
-  banshee_make_room(11);
-  tdfx_outl(VGAINIT0,      reg->vgainit0);
-  tdfx_outl(DACMODE,       reg->dacmode);
-  tdfx_outl(VIDDESKSTRIDE, reg->stride);
-  if (nohwcursor) {
-     tdfx_outl(HWCURPATADDR,  0);
-  } else {
-     tdfx_outl(HWCURPATADDR,  reg->curspataddr);
-     tdfx_outl(HWCURC0,       reg->cursc0);
-     tdfx_outl(HWCURC1,       reg->cursc1);
-     tdfx_outl(HWCURLOC,      reg->cursloc);
-  }
-   
-  tdfx_outl(VIDSCREENSIZE, reg->screensize);
-  tdfx_outl(VIDDESKSTART,  reg->startaddr);
-  tdfx_outl(VIDPROCCFG,    reg->vidcfg);
-  tdfx_outl(VGAINIT1,      reg->vgainit1);  
-  tdfx_outl(MISCINIT0,	   reg->miscinit0);
-
-  banshee_make_room(8);
-  tdfx_outl(SRCBASE,         reg->srcbase);
-  tdfx_outl(DSTBASE,         reg->dstbase);
-  tdfx_outl(COMMANDEXTRA_2D, 0);
-  tdfx_outl(CLIP0MIN,        0);
-  tdfx_outl(CLIP0MAX,        0x0fff0fff);
-  tdfx_outl(CLIP1MIN,        0);
-  tdfx_outl(CLIP1MAX,        0x0fff0fff);
-  tdfx_outl(SRCXY, 0);
-
-  banshee_wait_idle();
-}
-
-static unsigned long do_lfb_size(void) {
-  u32 draminit0 = 0;
-  u32 draminit1 = 0;
-  u32 miscinit1 = 0;
-  u32 lfbsize   = 0;
-  int sgram_p     = 0;
-
-  draminit0 = tdfx_inl(DRAMINIT0);  
-  draminit1 = tdfx_inl(DRAMINIT1);
-
-  if ((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) ||
-      (fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3)) {
-    sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
-  
-    lfbsize = sgram_p ?
-      (((draminit0 & DRAMINIT0_SGRAM_NUM)  ? 2 : 1) * 
-       ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
-      16 * 1024 * 1024;
-  } else {
-    /* Voodoo4/5 */
-    u32 chips, psize, banks;
-
-    chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8;
-    psize = 1 << ((draminit0 & 0x38000000) >> 28);
-    banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4;
-    lfbsize = chips * psize * banks;
-    lfbsize <<= 20;
-  }
-
-  /* disable block writes for SDRAM (why?) */
-  miscinit1 = tdfx_inl(MISCINIT1);
-  miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
-  miscinit1 |= MISCINIT1_CLUT_INV;
+	for (i = 0; i < 5; i++)
+		seq_outb(i, reg->seq[i]);
+
+	for (i = 0; i < 25; i++)
+		crt_outb(i, reg->crt[i]);
+
+	for (i = 0; i < 9; i++)
+		gra_outb(i, reg->gra[i]);
+
+	for (i = 0; i < 21; i++)
+		att_outb(i, reg->att[i]);
+
+	crt_outb(0x1a, reg->ext[0]);
+	crt_outb(0x1b, reg->ext[1]);
+
+	vga_enable_palette();
+	vga_enable_video();
+
+	banshee_make_room(11);
+	tdfx_outl(VGAINIT0, reg->vgainit0);
+	tdfx_outl(DACMODE, reg->dacmode);
+	tdfx_outl(VIDDESKSTRIDE, reg->stride);
+	if (nohwcursor) {
+		tdfx_outl(HWCURPATADDR, 0);
+	} else {
+		tdfx_outl(HWCURPATADDR, reg->curspataddr);
+		tdfx_outl(HWCURC0, reg->cursc0);
+		tdfx_outl(HWCURC1, reg->cursc1);
+		tdfx_outl(HWCURLOC, reg->cursloc);
+	}
 
-  banshee_make_room(1); 
-  tdfx_outl(MISCINIT1, miscinit1);
+	tdfx_outl(VIDSCREENSIZE, reg->screensize);
+	tdfx_outl(VIDDESKSTART, reg->startaddr);
+	tdfx_outl(VIDPROCCFG, reg->vidcfg);
+	tdfx_outl(VGAINIT1, reg->vgainit1);
+	tdfx_outl(MISCINIT0, reg->miscinit0);
+
+	banshee_make_room(8);
+	tdfx_outl(SRCBASE, reg->srcbase);
+	tdfx_outl(DSTBASE, reg->dstbase);
+	tdfx_outl(COMMANDEXTRA_2D, 0);
+	tdfx_outl(CLIP0MIN, 0);
+	tdfx_outl(CLIP0MAX, 0x0fff0fff);
+	tdfx_outl(CLIP1MIN, 0);
+	tdfx_outl(CLIP1MAX, 0x0fff0fff);
+	tdfx_outl(SRCXY, 0);
 
-  return lfbsize;
+	banshee_wait_idle();
+}
+
+static unsigned long do_lfb_size(void)
+{
+	u32 draminit0 = 0;
+	u32 draminit1 = 0;
+	u32 miscinit1 = 0;
+	u32 lfbsize = 0;
+	int sgram_p = 0;
+
+	draminit0 = tdfx_inl(DRAMINIT0);
+	draminit1 = tdfx_inl(DRAMINIT1);
+
+	if ((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) ||
+	    (fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3)) {
+		sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
+
+		lfbsize = sgram_p ?
+		    (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) *
+		     ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 *
+		     1024) : 16 * 1024 * 1024;
+	} else {
+		/* Voodoo4/5 */
+		u32 chips, psize, banks;
+
+		chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8;
+		psize = 1 << ((draminit0 & 0x38000000) >> 28);
+		banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4;
+		lfbsize = chips * psize * banks;
+		lfbsize <<= 20;
+	}
+
+	/* disable block writes for SDRAM (why?) */
+	miscinit1 = tdfx_inl(MISCINIT1);
+	miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
+	miscinit1 |= MISCINIT1_CLUT_INV;
+
+	banshee_make_room(1);
+	tdfx_outl(MISCINIT1, miscinit1);
+
+	return lfbsize;
 }
 
 /* ------------------------------------------------------------------------- 
@@ -1013,876 +901,868 @@
 #define tdfx_cfb24_putcs tdfx_cfb32_putcs
 #define tdfx_cfb24_clear tdfx_cfb32_clear
 
-static void tdfx_cfbX_clear_margins(struct vc_data* conp, struct display* p,
-				    int bottom_only)
+static void tdfx_cfbX_clear_margins(struct vc_data *conp,
+				    struct display *p, int bottom_only)
 {
-   unsigned int cw=fontwidth(p);
-   unsigned int ch=fontheight(p);
-   unsigned int rw=p->var.xres % cw;   // it be in a non-standard mode or not?
-   unsigned int bh=p->var.yres % ch;
-   unsigned int rs=p->var.xres - rw;
-   unsigned int bs=p->var.yres - bh;
-
-   if (!bottom_only && rw) { 
-      do_fillrect( p->var.xoffset+rs, 0, 
-		  rw, p->var.yres_virtual, 0, 
-		  fb_info.current_par.lpitch,
-		  fb_info.current_par.bpp, TDFX_ROP_COPY);
-   }
-   
-   if (bh) { 
-      do_fillrect( p->var.xoffset, p->var.yoffset+bs, 
-		  rs, bh, 0, 
-		  fb_info.current_par.lpitch,
-		  fb_info.current_par.bpp, TDFX_ROP_COPY);
-   }
-}
-static void tdfx_cfbX_bmove(struct display* p, 
-				int sy, 
-				int sx, 
-				int dy,
-				int dx, 
-				int height, 
-				int width) {
-   do_bitblt(fontwidth(p)*sx,
-		 fontheight(p)*sy, 
-		 fontwidth(p)*dx,
-		 fontheight(p)*dy, 
-		 fontwidth(p)*width, 
-		 fontheight(p)*height, 
-		 fb_info.current_par.lpitch, 
-		 fb_info.current_par.bpp);
-}
-static void tdfx_cfb8_putc(struct vc_data* conp,
-			       struct display* p,
-			       int c, int yy,int xx)
-{   
-   u32 fgx,bgx;
-   fgx=attr_fgcol(p, c);
-   bgx=attr_bgcol(p, c);
-   do_putc( fgx,bgx,p,c,yy,xx );
-}
-
-static void tdfx_cfb16_putc(struct vc_data* conp,
-			       struct display* p,
-			       int c, int yy,int xx)
-{   
-   u32 fgx,bgx;
-   fgx=((u16*)p->dispsw_data)[attr_fgcol(p,c)];
-   bgx=((u16*)p->dispsw_data)[attr_bgcol(p,c)];
-   do_putc( fgx,bgx,p,c,yy,xx );
-}
-
-static void tdfx_cfb32_putc(struct vc_data* conp,
-			       struct display* p,
-			       int c, int yy,int xx)
-{   
-   u32 fgx,bgx;
-   fgx=((u32*)p->dispsw_data)[attr_fgcol(p,c)];
-   bgx=((u32*)p->dispsw_data)[attr_bgcol(p,c)];
-   do_putc( fgx,bgx,p,c,yy,xx );
-}
-static void tdfx_cfb8_putcs(struct vc_data* conp,
-			    struct display* p,
-			    const unsigned short *s,int count,int yy,int xx)
-{
-   u16 c = scr_readw(s);
-   u32 fgx = attr_fgcol(p, c);
-   u32 bgx = attr_bgcol(p, c);
-   do_putcs( fgx,bgx,p,s,count,yy,xx );
-}
-static void tdfx_cfb16_putcs(struct vc_data* conp,
-			    struct display* p,
-			    const unsigned short *s,int count,int yy,int xx)
-{
-   u16 c = scr_readw(s);
-   u32 fgx = ((u16*)p->dispsw_data)[attr_fgcol(p, c)];
-   u32 bgx = ((u16*)p->dispsw_data)[attr_bgcol(p, c)];
-   do_putcs( fgx,bgx,p,s,count,yy,xx );
-}
-static void tdfx_cfb32_putcs(struct vc_data* conp,
-			    struct display* p,
-			    const unsigned short *s,int count,int yy,int xx)
-{
-   u16 c = scr_readw(s);
-   u32 fgx = ((u32*)p->dispsw_data)[attr_fgcol(p, c)];
-   u32 bgx = ((u32*)p->dispsw_data)[attr_bgcol(p, c)];
-   do_putcs( fgx,bgx,p,s,count,yy,xx );
-}
-
-static void tdfx_cfb8_clear(struct vc_data* conp, 
-				struct display* p, 
-				int sy,
-				int sx, 
-				int height, 
-				int width) {
-  u32 bg;
-
-  bg = attr_bgcol_ec(p,conp);
-  do_fillrect(fontwidth(p)*sx,
-		   fontheight(p)*sy,
-		   fontwidth(p)*width, 
-		   fontheight(p)*height,
-		   bg, 
-		   fb_info.current_par.lpitch, 
-		   fb_info.current_par.bpp, TDFX_ROP_COPY);
-}
-
-static void tdfx_cfb16_clear(struct vc_data* conp, 
-				struct display* p, 
-				int sy,
-				int sx, 
-				int height, 
-				int width) {
-  u32 bg;
-
-  bg = ((u16*)p->dispsw_data)[attr_bgcol_ec(p,conp)];
-  do_fillrect(fontwidth(p)*sx,
-		   fontheight(p)*sy,
-		   fontwidth(p)*width, 
-		   fontheight(p)*height,
-		   bg, 
-		   fb_info.current_par.lpitch, 
-		   fb_info.current_par.bpp, TDFX_ROP_COPY);
-}
-
-static void tdfx_cfb32_clear(struct vc_data* conp, 
-				struct display* p, 
-				int sy,
-				int sx, 
-				int height, 
-				int width) {
-  u32 bg;
-
-  bg = ((u32*)p->dispsw_data)[attr_bgcol_ec(p,conp)];
-  do_fillrect(fontwidth(p)*sx,
-		   fontheight(p)*sy,
-		   fontwidth(p)*width, 
-		   fontheight(p)*height,
-		   bg, 
-		   fb_info.current_par.lpitch, 
-		   fb_info.current_par.bpp, TDFX_ROP_COPY);
+	unsigned int cw = fontwidth(p);
+	unsigned int ch = fontheight(p);
+	unsigned int rw = p->var.xres % cw;	// it be in a non-standard mode or not?
+	unsigned int bh = p->var.yres % ch;
+	unsigned int rs = p->var.xres - rw;
+	unsigned int bs = p->var.yres - bh;
+
+	if (!bottom_only && rw) {
+		do_fillrect(p->var.xoffset + rs, 0,
+			    rw, p->var.yres_virtual, 0,
+			    fb_info.current_par.lpitch,
+			    fb_info.current_par.bpp, TDFX_ROP_COPY);
+	}
+
+	if (bh) {
+		do_fillrect(p->var.xoffset, p->var.yoffset + bs,
+			    rs, bh, 0,
+			    fb_info.current_par.lpitch,
+			    fb_info.current_par.bpp, TDFX_ROP_COPY);
+	}
+}
+static void tdfx_cfbX_bmove(struct display *p,
+			    int sy,
+			    int sx, int dy, int dx, int height, int width)
+{
+	do_bitblt(fontwidth(p) * sx,
+		  fontheight(p) * sy,
+		  fontwidth(p) * dx,
+		  fontheight(p) * dy,
+		  fontwidth(p) * width,
+		  fontheight(p) * height,
+		  fb_info.current_par.lpitch, fb_info.current_par.bpp);
+}
+static void tdfx_cfb8_putc(struct vc_data *conp,
+			   struct display *p, int c, int yy, int xx)
+{
+	u32 fgx, bgx;
+	fgx = attr_fgcol(p, c);
+	bgx = attr_bgcol(p, c);
+	do_putc(fgx, bgx, p, c, yy, xx);
+}
+
+static void tdfx_cfb16_putc(struct vc_data *conp,
+			    struct display *p, int c, int yy, int xx)
+{
+	u32 fgx, bgx;
+	fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
+	bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
+	do_putc(fgx, bgx, p, c, yy, xx);
+}
+
+static void tdfx_cfb32_putc(struct vc_data *conp,
+			    struct display *p, int c, int yy, int xx)
+{
+	u32 fgx, bgx;
+	fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
+	bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
+	do_putc(fgx, bgx, p, c, yy, xx);
+}
+static void tdfx_cfb8_putcs(struct vc_data *conp,
+			    struct display *p,
+			    const unsigned short *s, int count, int yy,
+			    int xx)
+{
+	u16 c = scr_readw(s);
+	u32 fgx = attr_fgcol(p, c);
+	u32 bgx = attr_bgcol(p, c);
+	do_putcs(fgx, bgx, p, s, count, yy, xx);
+}
+static void tdfx_cfb16_putcs(struct vc_data *conp,
+			     struct display *p,
+			     const unsigned short *s, int count, int yy,
+			     int xx)
+{
+	u16 c = scr_readw(s);
+	u32 fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
+	u32 bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
+	do_putcs(fgx, bgx, p, s, count, yy, xx);
+}
+static void tdfx_cfb32_putcs(struct vc_data *conp,
+			     struct display *p,
+			     const unsigned short *s, int count, int yy,
+			     int xx)
+{
+	u16 c = scr_readw(s);
+	u32 fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
+	u32 bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
+	do_putcs(fgx, bgx, p, s, count, yy, xx);
+}
+
+static void tdfx_cfb8_clear(struct vc_data *conp,
+			    struct display *p,
+			    int sy, int sx, int height, int width)
+{
+	u32 bg;
+
+	bg = attr_bgcol_ec(p, conp);
+	do_fillrect(fontwidth(p) * sx,
+		    fontheight(p) * sy,
+		    fontwidth(p) * width,
+		    fontheight(p) * height,
+		    bg,
+		    fb_info.current_par.lpitch,
+		    fb_info.current_par.bpp, TDFX_ROP_COPY);
+}
+
+static void tdfx_cfb16_clear(struct vc_data *conp,
+			     struct display *p,
+			     int sy, int sx, int height, int width)
+{
+	u32 bg;
+
+	bg = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	do_fillrect(fontwidth(p) * sx,
+		    fontheight(p) * sy,
+		    fontwidth(p) * width,
+		    fontheight(p) * height,
+		    bg,
+		    fb_info.current_par.lpitch,
+		    fb_info.current_par.bpp, TDFX_ROP_COPY);
+}
+
+static void tdfx_cfb32_clear(struct vc_data *conp,
+			     struct display *p,
+			     int sy, int sx, int height, int width)
+{
+	u32 bg;
+
+	bg = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	do_fillrect(fontwidth(p) * sx,
+		    fontheight(p) * sy,
+		    fontwidth(p) * width,
+		    fontheight(p) * height,
+		    bg,
+		    fb_info.current_par.lpitch,
+		    fb_info.current_par.bpp, TDFX_ROP_COPY);
 }
 static void tdfx_cfbX_revc(struct display *p, int xx, int yy)
 {
-   int bpp=fb_info.current_par.bpp;
-   
-   do_fillrect( xx * fontwidth(p), yy * fontheight(p), 
-	        fontwidth(p), fontheight(p), 
-	        (bpp==8) ? 0x0f : 0xffffffff, 
-	        fb_info.current_par.lpitch, bpp, TDFX_ROP_XOR);
-   
-}
-static void tdfx_cfbX_cursor(struct display *p, int mode, int x, int y) 
-{
-   unsigned long flags;
-   int tip;
-   struct fb_info_tdfx *info=(struct fb_info_tdfx *)p->fb_info;
-     
-   tip=p->conp->vc_cursor_type & CUR_HWMASK;
-   if (mode==CM_ERASE) {
-	if (info->cursor.state != CM_ERASE) {
-	     spin_lock_irqsave(&info->DAClock,flags);
-	     info->cursor.state=CM_ERASE;
-	     del_timer(&(info->cursor.timer));
-	     tdfx_outl(VIDPROCCFG,info->cursor.disable); 
-	     spin_unlock_irqrestore(&info->DAClock,flags);
+	int bpp = fb_info.current_par.bpp;
+
+	do_fillrect(xx * fontwidth(p), yy * fontheight(p),
+		    fontwidth(p), fontheight(p),
+		    (bpp == 8) ? 0x0f : 0xffffffff,
+		    fb_info.current_par.lpitch, bpp, TDFX_ROP_XOR);
+
+}
+static void tdfx_cfbX_cursor(struct display *p, int mode, int x, int y)
+{
+	unsigned long flags;
+	int tip;
+	struct fb_info_tdfx *info = (struct fb_info_tdfx *) p->fb_info;
+
+	tip = p->conp->vc_cursor_type & CUR_HWMASK;
+	if (mode == CM_ERASE) {
+		if (info->cursor.state != CM_ERASE) {
+			spin_lock_irqsave(&info->DAClock, flags);
+			info->cursor.state = CM_ERASE;
+			del_timer(&(info->cursor.timer));
+			tdfx_outl(VIDPROCCFG, info->cursor.disable);
+			spin_unlock_irqrestore(&info->DAClock, flags);
+		}
+		return;
 	}
+	if ((p->conp->vc_cursor_type & CUR_HWMASK) != info->cursor.type)
+		tdfxfb_createcursor(p);
+	x *= fontwidth(p);
+	y *= fontheight(p);
+	y -= p->var.yoffset;
+	spin_lock_irqsave(&info->DAClock, flags);
+	if ((x != info->cursor.x) ||
+	    (y != info->cursor.y) || (info->cursor.redraw)) {
+		info->cursor.x = x;
+		info->cursor.y = y;
+		info->cursor.redraw = 0;
+		x += 63;
+		y += 63;
+		banshee_make_room(2);
+		tdfx_outl(VIDPROCCFG, info->cursor.disable);
+		tdfx_outl(HWCURLOC, (y << 16) + x);
+		/* fix cursor color - XFree86 forgets to restore it properly */
+		tdfx_outl(HWCURC0, 0);
+		tdfx_outl(HWCURC1, 0xffffff);
+	}
+	info->cursor.state = CM_DRAW;
+	mod_timer(&info->cursor.timer, jiffies + HZ / 2);
+	banshee_make_room(1);
+	tdfx_outl(VIDPROCCFG, info->cursor.enable);
+	spin_unlock_irqrestore(&info->DAClock, flags);
 	return;
-   }
-   if ((p->conp->vc_cursor_type & CUR_HWMASK) != info->cursor.type)
-	 tdfxfb_createcursor(p);
-   x *= fontwidth(p);
-   y *= fontheight(p);
-   y -= p->var.yoffset;
-   spin_lock_irqsave(&info->DAClock,flags);
-   if ((x!=info->cursor.x) ||
-      (y!=info->cursor.y) ||
-      (info->cursor.redraw)) {
-          info->cursor.x=x;
-	  info->cursor.y=y;
-	  info->cursor.redraw=0;
-	  x += 63;
-	  y += 63;    
-          banshee_make_room(2);
-	  tdfx_outl(VIDPROCCFG, info->cursor.disable);
-	  tdfx_outl(HWCURLOC, (y << 16) + x);
-	  /* fix cursor color - XFree86 forgets to restore it properly */
-	  tdfx_outl(HWCURC0, 0);
-	  tdfx_outl(HWCURC1, 0xffffff);
-   }
-   info->cursor.state = CM_DRAW;
-   mod_timer(&info->cursor.timer,jiffies+HZ/2);
-   banshee_make_room(1);
-   tdfx_outl(VIDPROCCFG, info->cursor.enable);
-   spin_unlock_irqrestore(&info->DAClock,flags);
-   return;     
 }
+
 #ifdef FBCON_HAS_CFB8
 static struct display_switch fbcon_banshee8 = {
-   setup:		fbcon_cfb8_setup, 
-   bmove:		tdfx_cfbX_bmove, 
-   clear:		tdfx_cfb8_clear, 
-   putc:		tdfx_cfb8_putc,
-   putcs:		tdfx_cfb8_putcs, 
-   revc:		tdfx_cfbX_revc,   
-   cursor:		tdfx_cfbX_cursor, 
-   clear_margins:	tdfx_cfbX_clear_margins,
-   fontwidthmask:	FONTWIDTHRANGE(8, 12)
+	setup:fbcon_cfb8_setup,
+	bmove:tdfx_cfbX_bmove,
+	clear:tdfx_cfb8_clear,
+	putc:tdfx_cfb8_putc,
+	putcs:tdfx_cfb8_putcs,
+	revc:tdfx_cfbX_revc,
+	cursor:tdfx_cfbX_cursor,
+	clear_margins:tdfx_cfbX_clear_margins,
+	fontwidthmask:FONTWIDTHRANGE(8, 12)
 };
 #endif
 #ifdef FBCON_HAS_CFB16
 static struct display_switch fbcon_banshee16 = {
-   setup:		fbcon_cfb16_setup, 
-   bmove:		tdfx_cfbX_bmove, 
-   clear:		tdfx_cfb16_clear, 
-   putc:		tdfx_cfb16_putc,
-   putcs:		tdfx_cfb16_putcs, 
-   revc:		tdfx_cfbX_revc, 
-   cursor:		tdfx_cfbX_cursor, 
-   clear_margins:	tdfx_cfbX_clear_margins,
-   fontwidthmask:	FONTWIDTHRANGE(8, 12)
+	setup:fbcon_cfb16_setup,
+	bmove:tdfx_cfbX_bmove,
+	clear:tdfx_cfb16_clear,
+	putc:tdfx_cfb16_putc,
+	putcs:tdfx_cfb16_putcs,
+	revc:tdfx_cfbX_revc,
+	cursor:tdfx_cfbX_cursor,
+	clear_margins:tdfx_cfbX_clear_margins,
+	fontwidthmask:FONTWIDTHRANGE(8, 12)
 };
 #endif
 #ifdef FBCON_HAS_CFB24
 static struct display_switch fbcon_banshee24 = {
-   setup:		fbcon_cfb24_setup, 
-   bmove:		tdfx_cfbX_bmove, 
-   clear:		tdfx_cfb24_clear, 
-   putc:		tdfx_cfb24_putc,
-   putcs:		tdfx_cfb24_putcs, 
-   revc:		tdfx_cfbX_revc, 
-   cursor:		tdfx_cfbX_cursor, 
-   clear_margins:	tdfx_cfbX_clear_margins,
-   fontwidthmask:	FONTWIDTHRANGE(8, 12)
+	setup:fbcon_cfb24_setup,
+	bmove:tdfx_cfbX_bmove,
+	clear:tdfx_cfb24_clear,
+	putc:tdfx_cfb24_putc,
+	putcs:tdfx_cfb24_putcs,
+	revc:tdfx_cfbX_revc,
+	cursor:tdfx_cfbX_cursor,
+	clear_margins:tdfx_cfbX_clear_margins,
+	fontwidthmask:FONTWIDTHRANGE(8, 12)
 };
 #endif
 #ifdef FBCON_HAS_CFB32
 static struct display_switch fbcon_banshee32 = {
-   setup:		fbcon_cfb32_setup, 
-   bmove:		tdfx_cfbX_bmove, 
-   clear:		tdfx_cfb32_clear, 
-   putc:		tdfx_cfb32_putc,
-   putcs:		tdfx_cfb32_putcs, 
-   revc:		tdfx_cfbX_revc, 
-   cursor:		tdfx_cfbX_cursor, 
-   clear_margins:	tdfx_cfbX_clear_margins,
-   fontwidthmask:	FONTWIDTHRANGE(8, 12)
+	setup:fbcon_cfb32_setup,
+	bmove:tdfx_cfbX_bmove,
+	clear:tdfx_cfb32_clear,
+	putc:tdfx_cfb32_putc,
+	putcs:tdfx_cfb32_putcs,
+	revc:tdfx_cfbX_revc,
+	cursor:tdfx_cfbX_cursor,
+	clear_margins:tdfx_cfbX_clear_margins,
+	fontwidthmask:FONTWIDTHRANGE(8, 12)
 };
 #endif
 
 /* ------------------------------------------------------------------------- */
 
-static void tdfxfb_set_par(const struct tdfxfb_par* par,
-			   struct fb_info_tdfx*     info) {
-  struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
-  struct banshee_reg reg;
-  u32 cpp;
-  u32 hd, hs, he, ht, hbs, hbe;
-  u32 vd, vs, ve, vt, vbs, vbe;
-  u32 wd;
-  int fout;
-  int freq;
-   
-  memset(&reg, 0, sizeof(reg));
-
-  cpp = (par->bpp + 7)/8;
-  
-  wd = (par->hdispend >> 3) - 1;
-
-  hd  = (par->hdispend >> 3) - 1;
-  hs  = (par->hsyncsta >> 3) - 1;
-  he  = (par->hsyncend >> 3) - 1;
-  ht  = (par->htotal   >> 3) - 1;
-  hbs = hd;
-  hbe = ht;
-
-  vd  = par->vdispend - 1;
-  vs  = par->vsyncsta - 1;
-  ve  = par->vsyncend - 1;
-  vt  = par->vtotal   - 2;
-  vbs = vd;
-  vbe = vt;
-  
-  /* this is all pretty standard VGA register stuffing */
-  reg.misc[0x00] = 
-    0x0f |
-    (par->hdispend < 400 ? 0xa0 :
-     par->hdispend < 480 ? 0x60 :
-     par->hdispend < 768 ? 0xe0 : 0x20);
-     
-  reg.gra[0x00] = 0x00;
-  reg.gra[0x01] = 0x00;
-  reg.gra[0x02] = 0x00;
-  reg.gra[0x03] = 0x00;
-  reg.gra[0x04] = 0x00;
-  reg.gra[0x05] = 0x40;
-  reg.gra[0x06] = 0x05;
-  reg.gra[0x07] = 0x0f;
-  reg.gra[0x08] = 0xff;
-
-  reg.att[0x00] = 0x00;
-  reg.att[0x01] = 0x01;
-  reg.att[0x02] = 0x02;
-  reg.att[0x03] = 0x03;
-  reg.att[0x04] = 0x04;
-  reg.att[0x05] = 0x05;
-  reg.att[0x06] = 0x06;
-  reg.att[0x07] = 0x07;
-  reg.att[0x08] = 0x08;
-  reg.att[0x09] = 0x09;
-  reg.att[0x0a] = 0x0a;
-  reg.att[0x0b] = 0x0b;
-  reg.att[0x0c] = 0x0c;
-  reg.att[0x0d] = 0x0d;
-  reg.att[0x0e] = 0x0e;
-  reg.att[0x0f] = 0x0f;
-  reg.att[0x10] = 0x41;
-  reg.att[0x11] = 0x00;
-  reg.att[0x12] = 0x0f;
-  reg.att[0x13] = 0x00;
-  reg.att[0x14] = 0x00;
-
-  reg.seq[0x00] = 0x03;
-  reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
-  reg.seq[0x02] = 0x0f;
-  reg.seq[0x03] = 0x00;
-  reg.seq[0x04] = 0x0e;
-
-  reg.crt[0x00] = ht - 4;
-  reg.crt[0x01] = hd;
-  reg.crt[0x02] = hbs;
-  reg.crt[0x03] = 0x80 | (hbe & 0x1f);
-  reg.crt[0x04] = hs;
-  reg.crt[0x05] = 
-    ((hbe & 0x20) << 2) | 
-    (he & 0x1f);
-  reg.crt[0x06] = vt;
-  reg.crt[0x07] = 
-    ((vs & 0x200) >> 2) |
-    ((vd & 0x200) >> 3) |
-    ((vt & 0x200) >> 4) |
-    0x10 |
-    ((vbs & 0x100) >> 5) |
-    ((vs  & 0x100) >> 6) |
-    ((vd  & 0x100) >> 7) |
-    ((vt  & 0x100) >> 8);
-  reg.crt[0x08] = 0x00;
-  reg.crt[0x09] = 
-    0x40 |
-    ((vbs & 0x200) >> 4);
-  reg.crt[0x0a] = 0x00;
-  reg.crt[0x0b] = 0x00;
-  reg.crt[0x0c] = 0x00;
-  reg.crt[0x0d] = 0x00;
-  reg.crt[0x0e] = 0x00;
-  reg.crt[0x0f] = 0x00;
-  reg.crt[0x10] = vs;
-  reg.crt[0x11] = 
-    (ve & 0x0f) |
-    0x20;
-  reg.crt[0x12] = vd;
-  reg.crt[0x13] = wd;
-  reg.crt[0x14] = 0x00;
-  reg.crt[0x15] = vbs;
-  reg.crt[0x16] = vbe + 1; 
-  reg.crt[0x17] = 0xc3;
-  reg.crt[0x18] = 0xff;
-  
-  /* Banshee's nonvga stuff */
-  reg.ext[0x00] = (((ht  & 0x100) >> 8) | 
-		   ((hd  & 0x100) >> 6) |
-		   ((hbs & 0x100) >> 4) |
-		   ((hbe &  0x40) >> 1) |
-		   ((hs  & 0x100) >> 2) |
-		   ((he  &  0x20) << 2)); 
-  reg.ext[0x01] = (((vt  & 0x400) >> 10) |
-		   ((vd  & 0x400) >>  8) | 
-		   ((vbs & 0x400) >>  6) |
-		   ((vbe & 0x400) >>  4));
-  
-  reg.vgainit0 = 
-    VGAINIT0_8BIT_DAC     |
-    VGAINIT0_EXT_ENABLE   |
-    VGAINIT0_WAKEUP_3C3   |
-    VGAINIT0_ALT_READBACK |
-    VGAINIT0_EXTSHIFTOUT;
-  reg.vgainit1 = tdfx_inl(VGAINIT1) & 0x1fffff;
-
-  reg.vidcfg = 
-    VIDCFG_VIDPROC_ENABLE |
-    VIDCFG_DESK_ENABLE    |
-    VIDCFG_CURS_X11 |
-    ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
-    (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
-  
-  fb_info.cursor.enable=reg.vidcfg | VIDCFG_HWCURSOR_ENABLE;
-  fb_info.cursor.disable=reg.vidcfg;
-   
-  reg.stride    = par->width*cpp;
-  reg.cursloc   = 0;
-   
-  reg.cursc0    = 0; 
-  reg.cursc1    = 0xffffff;
-   
-  reg.curspataddr = fb_info.cursor.cursorimage;   
-  
-  reg.startaddr = par->baseline*reg.stride;
-  reg.srcbase   = reg.startaddr;
-  reg.dstbase   = reg.startaddr;
-
-  /* PLL settings */
-  freq = par->pixclock;
-
-  reg.dacmode &= ~DACMODE_2X;
-  reg.vidcfg  &= ~VIDCFG_2X;
-  if(freq > i->max_pixclock/2) {
-    freq = freq > i->max_pixclock ? i->max_pixclock : freq;
-    reg.dacmode |= DACMODE_2X;
-    reg.vidcfg  |= VIDCFG_2X;
-  }
-  reg.vidpll = do_calc_pll(freq, &fout);
+static void tdfxfb_set_par(const struct tdfxfb_par *par,
+			   struct fb_info_tdfx *info)
+{
+	struct fb_info_tdfx *i = (struct fb_info_tdfx *) info;
+	struct banshee_reg reg;
+	u32 cpp;
+	u32 hd, hs, he, ht, hbs, hbe;
+	u32 vd, vs, ve, vt, vbs, vbe;
+	u32 wd;
+	int fout;
+	int freq;
+
+	memset(&reg, 0, sizeof(reg));
+
+	cpp = (par->bpp + 7) / 8;
+
+	wd = (par->hdispend >> 3) - 1;
+
+	hd = (par->hdispend >> 3) - 1;
+	hs = (par->hsyncsta >> 3) - 1;
+	he = (par->hsyncend >> 3) - 1;
+	ht = (par->htotal >> 3) - 1;
+	hbs = hd;
+	hbe = ht;
+
+	vd = par->vdispend - 1;
+	vs = par->vsyncsta - 1;
+	ve = par->vsyncend - 1;
+	vt = par->vtotal - 2;
+	vbs = vd;
+	vbe = vt;
+
+	/* this is all pretty standard VGA register stuffing */
+	reg.misc[0x00] =
+	    0x0f |
+	    (par->hdispend < 400 ? 0xa0 :
+	     par->hdispend < 480 ? 0x60 :
+	     par->hdispend < 768 ? 0xe0 : 0x20);
+
+	reg.gra[0x00] = 0x00;
+	reg.gra[0x01] = 0x00;
+	reg.gra[0x02] = 0x00;
+	reg.gra[0x03] = 0x00;
+	reg.gra[0x04] = 0x00;
+	reg.gra[0x05] = 0x40;
+	reg.gra[0x06] = 0x05;
+	reg.gra[0x07] = 0x0f;
+	reg.gra[0x08] = 0xff;
+
+	reg.att[0x00] = 0x00;
+	reg.att[0x01] = 0x01;
+	reg.att[0x02] = 0x02;
+	reg.att[0x03] = 0x03;
+	reg.att[0x04] = 0x04;
+	reg.att[0x05] = 0x05;
+	reg.att[0x06] = 0x06;
+	reg.att[0x07] = 0x07;
+	reg.att[0x08] = 0x08;
+	reg.att[0x09] = 0x09;
+	reg.att[0x0a] = 0x0a;
+	reg.att[0x0b] = 0x0b;
+	reg.att[0x0c] = 0x0c;
+	reg.att[0x0d] = 0x0d;
+	reg.att[0x0e] = 0x0e;
+	reg.att[0x0f] = 0x0f;
+	reg.att[0x10] = 0x41;
+	reg.att[0x11] = 0x00;
+	reg.att[0x12] = 0x0f;
+	reg.att[0x13] = 0x00;
+	reg.att[0x14] = 0x00;
+
+	reg.seq[0x00] = 0x03;
+	reg.seq[0x01] = 0x01;	/* fixme: clkdiv2? */
+	reg.seq[0x02] = 0x0f;
+	reg.seq[0x03] = 0x00;
+	reg.seq[0x04] = 0x0e;
+
+	reg.crt[0x00] = ht - 4;
+	reg.crt[0x01] = hd;
+	reg.crt[0x02] = hbs;
+	reg.crt[0x03] = 0x80 | (hbe & 0x1f);
+	reg.crt[0x04] = hs;
+	reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
+	reg.crt[0x06] = vt;
+	reg.crt[0x07] =
+	    ((vs & 0x200) >> 2) |
+	    ((vd & 0x200) >> 3) |
+	    ((vt & 0x200) >> 4) |
+	    0x10 |
+	    ((vbs & 0x100) >> 5) |
+	    ((vs & 0x100) >> 6) |
+	    ((vd & 0x100) >> 7) | ((vt & 0x100) >> 8);
+	reg.crt[0x08] = 0x00;
+	reg.crt[0x09] = 0x40 | ((vbs & 0x200) >> 4);
+	reg.crt[0x0a] = 0x00;
+	reg.crt[0x0b] = 0x00;
+	reg.crt[0x0c] = 0x00;
+	reg.crt[0x0d] = 0x00;
+	reg.crt[0x0e] = 0x00;
+	reg.crt[0x0f] = 0x00;
+	reg.crt[0x10] = vs;
+	reg.crt[0x11] = (ve & 0x0f) | 0x20;
+	reg.crt[0x12] = vd;
+	reg.crt[0x13] = wd;
+	reg.crt[0x14] = 0x00;
+	reg.crt[0x15] = vbs;
+	reg.crt[0x16] = vbe + 1;
+	reg.crt[0x17] = 0xc3;
+	reg.crt[0x18] = 0xff;
+
+	/* Banshee's nonvga stuff */
+	reg.ext[0x00] = (((ht & 0x100) >> 8) |
+			 ((hd & 0x100) >> 6) |
+			 ((hbs & 0x100) >> 4) |
+			 ((hbe & 0x40) >> 1) |
+			 ((hs & 0x100) >> 2) | ((he & 0x20) << 2));
+	reg.ext[0x01] = (((vt & 0x400) >> 10) |
+			 ((vd & 0x400) >> 8) |
+			 ((vbs & 0x400) >> 6) | ((vbe & 0x400) >> 4));
+
+	reg.vgainit0 =
+	    VGAINIT0_8BIT_DAC |
+	    VGAINIT0_EXT_ENABLE |
+	    VGAINIT0_WAKEUP_3C3 |
+	    VGAINIT0_ALT_READBACK | VGAINIT0_EXTSHIFTOUT;
+	reg.vgainit1 = tdfx_inl(VGAINIT1) & 0x1fffff;
+
+	reg.vidcfg =
+	    VIDCFG_VIDPROC_ENABLE |
+	    VIDCFG_DESK_ENABLE |
+	    VIDCFG_CURS_X11 |
+	    ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
+	    (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
+
+	fb_info.cursor.enable = reg.vidcfg | VIDCFG_HWCURSOR_ENABLE;
+	fb_info.cursor.disable = reg.vidcfg;
+
+	reg.stride = par->width * cpp;
+	reg.cursloc = 0;
+
+	reg.cursc0 = 0;
+	reg.cursc1 = 0xffffff;
+
+	reg.curspataddr = fb_info.cursor.cursorimage;
+
+	reg.startaddr = par->baseline * reg.stride;
+	reg.srcbase = reg.startaddr;
+	reg.dstbase = reg.startaddr;
+
+	/* PLL settings */
+	freq = par->pixclock;
+
+	reg.dacmode &= ~DACMODE_2X;
+	reg.vidcfg &= ~VIDCFG_2X;
+	if (freq > i->max_pixclock / 2) {
+		freq = freq > i->max_pixclock ? i->max_pixclock : freq;
+		reg.dacmode |= DACMODE_2X;
+		reg.vidcfg |= VIDCFG_2X;
+	}
+	reg.vidpll = do_calc_pll(freq, &fout);
 #if 0
-  reg.mempll = do_calc_pll(..., &fout);
-  reg.gfxpll = do_calc_pll(..., &fout);
+	reg.mempll = do_calc_pll(..., &fout);
+	reg.gfxpll = do_calc_pll(..., &fout);
 #endif
 
-  reg.screensize = par->width | (par->height << 12);
-  reg.vidcfg &= ~VIDCFG_HALF_MODE;
+	reg.screensize = par->width | (par->height << 12);
+	reg.vidcfg &= ~VIDCFG_HALF_MODE;
 
-  reg.miscinit0 = tdfx_inl(MISCINIT0);
+	reg.miscinit0 = tdfx_inl(MISCINIT0);
 
 #if defined(__BIG_ENDIAN)
-  switch (par->bpp) {
-    case 8:
-      reg.miscinit0 &= ~(1 << 30);
-      reg.miscinit0 &= ~(1 << 31);
-      break;
-    case 16:
-      reg.miscinit0 |= (1 << 30);
-      reg.miscinit0 |= (1 << 31);
-      break;
-    case 24:
-    case 32:
-      reg.miscinit0 |= (1 << 30);
-      reg.miscinit0 &= ~(1 << 31);
-      break;
-  }
-#endif
-
-  do_write_regs(&reg);
-
-  i->current_par = *par;
-
-}
-
-static int tdfxfb_decode_var(const struct fb_var_screeninfo* var,
-			     struct tdfxfb_par*              par,
-			     const struct fb_info_tdfx*      info) {
-  struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
-
-  if(var->bits_per_pixel != 8  &&
-     var->bits_per_pixel != 16 &&
-     var->bits_per_pixel != 24 &&
-     var->bits_per_pixel != 32) {
-    DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
-    return -EINVAL;
-  }
-
-  if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
-    DPRINTK("interlace not supported\n");
-    return -EINVAL;
-  }
-
-  if(var->xoffset) {
-    DPRINTK("xoffset not supported\n");
-    return -EINVAL;
-  }
-
-  if(var->xres != var->xres_virtual) {
-    DPRINTK("virtual x resolution != physical x resolution not supported\n");
-    return -EINVAL;
-  }
-
-  if(var->yres > var->yres_virtual) {
-    DPRINTK("virtual y resolution < physical y resolution not possible\n");
-    return -EINVAL;
-  }
-
-  /* fixme: does Voodoo3 support interlace? Banshee doesn't */
-  if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
-    DPRINTK("interlace not supported\n");
-    return -EINVAL;
-  }
-
-  memset(par, 0, sizeof(struct tdfxfb_par));
-
-  switch(i->dev) {
-  case PCI_DEVICE_ID_3DFX_BANSHEE:
-  case PCI_DEVICE_ID_3DFX_VOODOO3:
-  case PCI_DEVICE_ID_3DFX_VOODOO5:
-    par->width       = (var->xres + 15) & ~15; /* could sometimes be 8 */
-    par->width_virt  = par->width;
-    par->height      = var->yres;
-    par->height_virt = var->yres_virtual;
-    par->bpp         = var->bits_per_pixel;
-    par->ppitch      = var->bits_per_pixel;
-    par->lpitch      = par->width* ((par->ppitch+7)>>3);
-    par->cmap_len    = (par->bpp == 8) ? 256 : 16;
-     
-    par->baseline = 0;
-
-    if(par->width < 320 || par->width > 2048) {
-      DPRINTK("width not supported: %u\n", par->width);
-      return -EINVAL;
-    }
-    if(par->height < 200 || par->height > 2048) {
-      DPRINTK("height not supported: %u\n", par->height);
-      return -EINVAL;
-    }
-    if(par->lpitch*par->height_virt > i->bufbase_size) {
-      DPRINTK("no memory for screen (%ux%ux%u)\n",
-	      par->width, par->height_virt, par->bpp);
-      return -EINVAL;
-    }
-    par->pixclock = PICOS2KHZ(var->pixclock);
-    if(par->pixclock > i->max_pixclock) {
-      DPRINTK("pixclock too high (%uKHz)\n", par->pixclock);
-      return -EINVAL;
-    }
-
-    par->hdispend = var->xres;
-    par->hsyncsta = par->hdispend + var->right_margin;
-    par->hsyncend = par->hsyncsta + var->hsync_len;
-    par->htotal   = par->hsyncend + var->left_margin;
-
-    par->vdispend = var->yres;
-    par->vsyncsta = par->vdispend + var->lower_margin;
-    par->vsyncend = par->vsyncsta + var->vsync_len;
-    par->vtotal   = par->vsyncend + var->upper_margin;
-
-    if(var->sync & FB_SYNC_HOR_HIGH_ACT)
-      par->video |= TDFXF_HSYNC_ACT_HIGH;
-    else
-      par->video |= TDFXF_HSYNC_ACT_LOW;
-    if(var->sync & FB_SYNC_VERT_HIGH_ACT)
-      par->video |= TDFXF_VSYNC_ACT_HIGH;
-    else
-      par->video |= TDFXF_VSYNC_ACT_LOW;
-    if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
-      par->video |= TDFXF_LINE_DOUBLE;
-    if(var->activate == FB_ACTIVATE_NOW)
-      par->video |= TDFXF_VIDEO_ENABLE;
-  }
-
-  if(var->accel_flags & FB_ACCELF_TEXT)
-    par->accel_flags = FB_ACCELF_TEXT;
-  else
-    par->accel_flags = 0;
-
-  return 0;
-}
-
-static int tdfxfb_encode_var(struct fb_var_screeninfo* var,
-			    const struct tdfxfb_par* par,
-			    const struct fb_info_tdfx* info) {
-  struct fb_var_screeninfo v;
-
-  memset(&v, 0, sizeof(struct fb_var_screeninfo));
-  v.xres_virtual   = par->width_virt;
-  v.yres_virtual   = par->height_virt;
-  v.xres           = par->width;
-  v.yres           = par->height;
-  v.right_margin   = par->hsyncsta - par->hdispend;
-  v.hsync_len      = par->hsyncend - par->hsyncsta;
-  v.left_margin    = par->htotal   - par->hsyncend;
-  v.lower_margin   = par->vsyncsta - par->vdispend;
-  v.vsync_len      = par->vsyncend - par->vsyncsta;
-  v.upper_margin   = par->vtotal   - par->vsyncend;
-  v.bits_per_pixel = par->bpp;
-  switch(par->bpp) {
-  case 8:
-    v.red.length = v.green.length = v.blue.length = 8;
-    break;
-  case 16:
-    v.red.offset   = 11;
-    v.red.length   = 5;
-    v.green.offset = 5;
-    v.green.length = 6;
-    v.blue.offset  = 0;
-    v.blue.length  = 5;
-    break;
-  case 24:
-    v.red.offset=16;
-    v.green.offset=8;
-    v.blue.offset=0;
-    v.red.length = v.green.length = v.blue.length = 8;
-  case 32:
-    v.red.offset   = 16;
-    v.green.offset = 8;
-    v.blue.offset  = 0;
-    v.red.length = v.green.length = v.blue.length = 8;
-    break;
-  }
-  v.height = v.width = -1;
-  v.pixclock = KHZ2PICOS(par->pixclock);
-  if((par->video & TDFXF_HSYNC_MASK) == TDFXF_HSYNC_ACT_HIGH)
-    v.sync |= FB_SYNC_HOR_HIGH_ACT;
-  if((par->video & TDFXF_VSYNC_MASK) == TDFXF_VSYNC_ACT_HIGH)
-    v.sync |= FB_SYNC_VERT_HIGH_ACT;
-  if(par->video & TDFXF_LINE_DOUBLE)
-    v.vmode = FB_VMODE_DOUBLE;
-  *var = v;
-  return 0;
-}
-
-static int tdfxfb_encode_fix(struct fb_fix_screeninfo*  fix,
-			     const struct tdfxfb_par*   par,
-			     const struct fb_info_tdfx* info) {
-  memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-
-  switch(info->dev) {
-  case PCI_DEVICE_ID_3DFX_BANSHEE:
-    strcpy(fix->id, "3Dfx Banshee");
-    break;
-  case PCI_DEVICE_ID_3DFX_VOODOO3:
-    strcpy(fix->id, "3Dfx Voodoo3");
-    break;
-  case PCI_DEVICE_ID_3DFX_VOODOO5:
-    strcpy(fix->id, "3Dfx Voodoo5");
-    break;
-  default:
-    return -EINVAL;
-  }
-
-  fix->smem_start  = info->bufbase_phys;
-  fix->smem_len    = info->bufbase_size;
-  fix->mmio_start  = info->regbase_phys;
-  fix->mmio_len    = info->regbase_size;
-  fix->accel       = FB_ACCEL_3DFX_BANSHEE;
-  fix->type        = FB_TYPE_PACKED_PIXELS;
-  fix->type_aux    = 0;
-  fix->line_length = par->lpitch;
-  fix->visual      = (par->bpp == 8) 
-                     ? FB_VISUAL_PSEUDOCOLOR
-                     : FB_VISUAL_DIRECTCOLOR;
-
-  fix->xpanstep    = 0; 
-  fix->ypanstep    = nopan ? 0 : 1;
-  fix->ywrapstep   = nowrap ? 0 : 1;
-
-  return 0;
-}
-
-static int tdfxfb_get_fix(struct fb_fix_screeninfo *fix, 
-			  int con,
-			  struct fb_info *fb) {
-  const struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
-  struct tdfxfb_par par;
-
-  if(con == -1)
-    par = info->default_par;
-  else
-    tdfxfb_decode_var(&fb_display[con].var, &par, info);
-  tdfxfb_encode_fix(fix, &par, info);
-  return 0;
-}
-
-static int tdfxfb_get_var(struct fb_var_screeninfo *var, 
-			  int con,
-			  struct fb_info *fb) {
-  const struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
-
-  if(con == -1)
-    tdfxfb_encode_var(var, &info->default_par, info);
-  else
-    *var = fb_display[con].var;
-  return 0;
+	switch (par->bpp) {
+	case 8:
+		reg.miscinit0 &= ~(1 << 30);
+		reg.miscinit0 &= ~(1 << 31);
+		break;
+	case 16:
+		reg.miscinit0 |= (1 << 30);
+		reg.miscinit0 |= (1 << 31);
+		break;
+	case 24:
+	case 32:
+		reg.miscinit0 |= (1 << 30);
+		reg.miscinit0 &= ~(1 << 31);
+		break;
+	}
+#endif
+
+	do_write_regs(&reg);
+
+	i->current_par = *par;
+
+}
+
+static int tdfxfb_decode_var(const struct fb_var_screeninfo *var,
+			     struct tdfxfb_par *par,
+			     const struct fb_info_tdfx *info)
+{
+	struct fb_info_tdfx *i = (struct fb_info_tdfx *) info;
+
+	if (var->bits_per_pixel != 8 &&
+	    var->bits_per_pixel != 16 &&
+	    var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
+		DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		DPRINTK("interlace not supported\n");
+		return -EINVAL;
+	}
+
+	if (var->xoffset) {
+		DPRINTK("xoffset not supported\n");
+		return -EINVAL;
+	}
+
+	if (var->xres != var->xres_virtual) {
+		DPRINTK
+		    ("virtual x resolution != physical x resolution not supported\n");
+		return -EINVAL;
+	}
+
+	if (var->yres > var->yres_virtual) {
+		DPRINTK
+		    ("virtual y resolution < physical y resolution not possible\n");
+		return -EINVAL;
+	}
+
+	/* fixme: does Voodoo3 support interlace? Banshee doesn't */
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		DPRINTK("interlace not supported\n");
+		return -EINVAL;
+	}
+
+	memset(par, 0, sizeof(struct tdfxfb_par));
+
+	switch (i->dev) {
+	case PCI_DEVICE_ID_3DFX_BANSHEE:
+	case PCI_DEVICE_ID_3DFX_VOODOO3:
+	case PCI_DEVICE_ID_3DFX_VOODOO5:
+		par->width = (var->xres + 15) & ~15;	/* could sometimes be 8 */
+		par->width_virt = par->width;
+		par->height = var->yres;
+		par->height_virt = var->yres_virtual;
+		par->bpp = var->bits_per_pixel;
+		par->ppitch = var->bits_per_pixel;
+		par->lpitch = par->width * ((par->ppitch + 7) >> 3);
+		par->cmap_len = (par->bpp == 8) ? 256 : 16;
+
+		par->baseline = 0;
+
+		if (par->width < 320 || par->width > 2048) {
+			DPRINTK("width not supported: %u\n", par->width);
+			return -EINVAL;
+		}
+		if (par->height < 200 || par->height > 2048) {
+			DPRINTK("height not supported: %u\n", par->height);
+			return -EINVAL;
+		}
+		if (par->lpitch * par->height_virt > i->bufbase_size) {
+			DPRINTK("no memory for screen (%ux%ux%u)\n",
+				par->width, par->height_virt, par->bpp);
+			return -EINVAL;
+		}
+		par->pixclock = PICOS2KHZ(var->pixclock);
+		if (par->pixclock > i->max_pixclock) {
+			DPRINTK("pixclock too high (%uKHz)\n",
+				par->pixclock);
+			return -EINVAL;
+		}
+
+		par->hdispend = var->xres;
+		par->hsyncsta = par->hdispend + var->right_margin;
+		par->hsyncend = par->hsyncsta + var->hsync_len;
+		par->htotal = par->hsyncend + var->left_margin;
+
+		par->vdispend = var->yres;
+		par->vsyncsta = par->vdispend + var->lower_margin;
+		par->vsyncend = par->vsyncsta + var->vsync_len;
+		par->vtotal = par->vsyncend + var->upper_margin;
+
+		if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+			par->video |= TDFXF_HSYNC_ACT_HIGH;
+		else
+			par->video |= TDFXF_HSYNC_ACT_LOW;
+		if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+			par->video |= TDFXF_VSYNC_ACT_HIGH;
+		else
+			par->video |= TDFXF_VSYNC_ACT_LOW;
+		if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
+			par->video |= TDFXF_LINE_DOUBLE;
+		if (var->activate == FB_ACTIVATE_NOW)
+			par->video |= TDFXF_VIDEO_ENABLE;
+	}
+
+	if (var->accel_flags & FB_ACCELF_TEXT)
+		par->accel_flags = FB_ACCELF_TEXT;
+	else
+		par->accel_flags = 0;
+
+	return 0;
 }
- 
-static void tdfxfb_set_dispsw(struct display *disp, 
+
+static int tdfxfb_encode_var(struct fb_var_screeninfo *var,
+			     const struct tdfxfb_par *par,
+			     const struct fb_info_tdfx *info)
+{
+	struct fb_var_screeninfo v;
+
+	memset(&v, 0, sizeof(struct fb_var_screeninfo));
+	v.xres_virtual = par->width_virt;
+	v.yres_virtual = par->height_virt;
+	v.xres = par->width;
+	v.yres = par->height;
+	v.right_margin = par->hsyncsta - par->hdispend;
+	v.hsync_len = par->hsyncend - par->hsyncsta;
+	v.left_margin = par->htotal - par->hsyncend;
+	v.lower_margin = par->vsyncsta - par->vdispend;
+	v.vsync_len = par->vsyncend - par->vsyncsta;
+	v.upper_margin = par->vtotal - par->vsyncend;
+	v.bits_per_pixel = par->bpp;
+	switch (par->bpp) {
+	case 8:
+		v.red.length = v.green.length = v.blue.length = 8;
+		break;
+	case 16:
+		v.red.offset = 11;
+		v.red.length = 5;
+		v.green.offset = 5;
+		v.green.length = 6;
+		v.blue.offset = 0;
+		v.blue.length = 5;
+		break;
+	case 24:
+		v.red.offset = 16;
+		v.green.offset = 8;
+		v.blue.offset = 0;
+		v.red.length = v.green.length = v.blue.length = 8;
+	case 32:
+		v.red.offset = 16;
+		v.green.offset = 8;
+		v.blue.offset = 0;
+		v.red.length = v.green.length = v.blue.length = 8;
+		break;
+	}
+	v.height = v.width = -1;
+	v.pixclock = KHZ2PICOS(par->pixclock);
+	if ((par->video & TDFXF_HSYNC_MASK) == TDFXF_HSYNC_ACT_HIGH)
+		v.sync |= FB_SYNC_HOR_HIGH_ACT;
+	if ((par->video & TDFXF_VSYNC_MASK) == TDFXF_VSYNC_ACT_HIGH)
+		v.sync |= FB_SYNC_VERT_HIGH_ACT;
+	if (par->video & TDFXF_LINE_DOUBLE)
+		v.vmode = FB_VMODE_DOUBLE;
+	*var = v;
+	return 0;
+}
+
+static int tdfxfb_encode_fix(struct fb_fix_screeninfo *fix,
+			     const struct tdfxfb_par *par,
+			     const struct fb_info_tdfx *info)
+{
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+	switch (info->dev) {
+	case PCI_DEVICE_ID_3DFX_BANSHEE:
+		strcpy(fix->id, "3Dfx Banshee");
+		break;
+	case PCI_DEVICE_ID_3DFX_VOODOO3:
+		strcpy(fix->id, "3Dfx Voodoo3");
+		break;
+	case PCI_DEVICE_ID_3DFX_VOODOO5:
+		strcpy(fix->id, "3Dfx Voodoo5");
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	fix->smem_start = info->bufbase_phys;
+	fix->smem_len = info->bufbase_size;
+	fix->mmio_start = info->regbase_phys;
+	fix->mmio_len = info->regbase_size;
+	fix->accel = FB_ACCEL_3DFX_BANSHEE;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+	fix->line_length = par->lpitch;
+	fix->visual = (par->bpp == 8)
+	    ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+
+	fix->xpanstep = 0;
+	fix->ypanstep = nopan ? 0 : 1;
+	fix->ywrapstep = nowrap ? 0 : 1;
+
+	return 0;
+}
+
+static int tdfxfb_get_fix(struct fb_fix_screeninfo *fix,
+			  int con, struct fb_info *fb)
+{
+	const struct fb_info_tdfx *info = (struct fb_info_tdfx *) fb;
+	struct tdfxfb_par par;
+
+	if (con == -1)
+		par = info->default_par;
+	else
+		tdfxfb_decode_var(&fb_display[con].var, &par, info);
+	tdfxfb_encode_fix(fix, &par, info);
+	return 0;
+}
+
+static int tdfxfb_get_var(struct fb_var_screeninfo *var,
+			  int con, struct fb_info *fb)
+{
+	const struct fb_info_tdfx *info = (struct fb_info_tdfx *) fb;
+
+	if (con == -1)
+		tdfxfb_encode_var(var, &info->default_par, info);
+	else
+		*var = fb_display[con].var;
+	return 0;
+}
+
+static void tdfxfb_set_dispsw(struct display *disp,
 			      struct fb_info_tdfx *info,
-			      int bpp, 
-			      int accel) {
+			      int bpp, int accel)
+{
 
-  if (disp->dispsw && disp->conp) 
-     fb_con.con_cursor(disp->conp, CM_ERASE);
-  switch(bpp) {
+	if (disp->dispsw && disp->conp)
+		fb_con.con_cursor(disp->conp, CM_ERASE);
+	switch (bpp) {
 #ifdef FBCON_HAS_CFB8
-  case 8:
-    disp->dispsw = noaccel ? &fbcon_cfb8 : &fbcon_banshee8;
-    if (nohwcursor) fbcon_banshee8.cursor = NULL;
-    break;
+	case 8:
+		disp->dispsw = noaccel ? &fbcon_cfb8 : &fbcon_banshee8;
+		if (nohwcursor)
+			fbcon_banshee8.cursor = NULL;
+		break;
 #endif
 #ifdef FBCON_HAS_CFB16
-  case 16:
-    disp->dispsw = noaccel ? &fbcon_cfb16 : &fbcon_banshee16;
-    disp->dispsw_data = info->fbcon_cmap.cfb16;
-    if (nohwcursor) fbcon_banshee16.cursor = NULL;
-    break;
+	case 16:
+		disp->dispsw = noaccel ? &fbcon_cfb16 : &fbcon_banshee16;
+		disp->dispsw_data = info->fbcon_cmap.cfb16;
+		if (nohwcursor)
+			fbcon_banshee16.cursor = NULL;
+		break;
 #endif
 #ifdef FBCON_HAS_CFB24
-  case 24:
-    disp->dispsw = noaccel ? &fbcon_cfb24 : &fbcon_banshee24; 
-    disp->dispsw_data = info->fbcon_cmap.cfb24;
-    if (nohwcursor) fbcon_banshee24.cursor = NULL;
-    break;
+	case 24:
+		disp->dispsw = noaccel ? &fbcon_cfb24 : &fbcon_banshee24;
+		disp->dispsw_data = info->fbcon_cmap.cfb24;
+		if (nohwcursor)
+			fbcon_banshee24.cursor = NULL;
+		break;
 #endif
 #ifdef FBCON_HAS_CFB32
-  case 32:
-    disp->dispsw = noaccel ? &fbcon_cfb32 : &fbcon_banshee32;
-    disp->dispsw_data = info->fbcon_cmap.cfb32;
-    if (nohwcursor) fbcon_banshee32.cursor = NULL;
-    break;
-#endif
-  default:
-    disp->dispsw = &fbcon_dummy;
-  }
-   
-}
-
-static int tdfxfb_set_var(struct fb_var_screeninfo *var, 
-			  int con,
-			  struct fb_info *fb) {
-   struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
-   struct tdfxfb_par par;
-   struct display *display;
-   int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
-   int activate = var->activate;
-   int j,k;
-   
-   if(con >= 0)
-     display = &fb_display[con];
-   else
-     display = fb->disp;	/* used during initialization */
-   
-   if((err = tdfxfb_decode_var(var, &par, info)))
-     return err;
-   
-   tdfxfb_encode_var(var, &par, info);
-   
-   if((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-      oldxres  = display->var.xres;
-      oldyres  = display->var.yres;
-      oldvxres = display->var.xres_virtual;
-      oldvyres = display->var.yres_virtual;
-      oldbpp   = display->var.bits_per_pixel;
-      oldaccel = display->var.accel_flags;
-      display->var = *var;
-      if(con < 0                         ||
-	 oldxres  != var->xres           || 
-	 oldyres  != var->yres           ||
-	 oldvxres != var->xres_virtual   || 
-	 oldvyres != var->yres_virtual   ||
-	 oldbpp   != var->bits_per_pixel || 
-	 oldaccel != var->accel_flags) {
-	 struct fb_fix_screeninfo fix;
-	 
-	 tdfxfb_encode_fix(&fix, &par, info);
-	 display->visual         = fix.visual;
-	 display->type           = fix.type;
-	 display->type_aux       = fix.type_aux;
-	 display->ypanstep       = fix.ypanstep;
-	 display->ywrapstep      = fix.ywrapstep;
-	 display->line_length    = fix.line_length;
-	 display->next_line      = fix.line_length;
-	 display->can_soft_blank = 1;
-	 display->inverse        = inverse;
-	 accel = var->accel_flags & FB_ACCELF_TEXT;
-	 tdfxfb_set_dispsw(display, info, par.bpp, accel);
-	 
-	 if(nopan) display->scrollmode = SCROLL_YREDRAW;
-	
-	 if (info->fb_info.changevar)
-	   (*info->fb_info.changevar)(con);
-      }
-      if (var->bits_per_pixel==8)
-	for(j = 0; j < 16; j++) {
-	   k = color_table[j];
-	   fb_info.palette[j].red   = default_red[k];
-	   fb_info.palette[j].green = default_grn[k];
-	   fb_info.palette[j].blue  = default_blu[k];
-	}
-      
-      del_timer(&(info->cursor.timer)); 
-      fb_info.cursor.state=CM_ERASE; 
-      if(!info->fb_info.display_fg ||
-	 info->fb_info.display_fg->vc_num == con ||
-	 con < 0)
-	tdfxfb_set_par(&par, info);
-      if (!nohwcursor) 
-	if (display && display->conp)
-	  tdfxfb_createcursor( display );
-      info->cursor.redraw=1;
-      if(oldbpp != var->bits_per_pixel || con < 0) {
-	 if((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-	   return err;
-	 do_install_cmap(con, &(info->fb_info));
-      }
-   }
-  
-   return 0;
-}
-
-static int tdfxfb_pan_display(struct fb_var_screeninfo* var, 
-			      int con,
-			      struct fb_info* fb) {
-  struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
-
-  if(nopan)                return -EINVAL;
-  if(var->xoffset)         return -EINVAL;
-  if(var->yoffset > var->yres_virtual)   return -EINVAL;
-  if(nowrap && 
-     (var->yoffset + var->yres > var->yres_virtual)) return -EINVAL;
- 
-  if (con == fb->currcon)
-    do_pan_var(var,i);
-   
-  fb_display[con].var.xoffset=var->xoffset;
-  fb_display[con].var.yoffset=var->yoffset; 
-  return 0;
-}
-
-static int tdfxfb_get_cmap(struct fb_cmap *cmap, 
-			   int kspc, 
-			   int con,
-			   struct fb_info *fb) {
-
-   struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
-   struct display *d=(con<0) ? fb->disp : fb_display + con;
-   
-   if(con == fb->currcon) {
-      /* current console? */
-      return fb_get_cmap(cmap, kspc, tdfxfb_getcolreg, fb);
-   } else if(d->cmap.len) {
-      /* non default colormap? */
-      fb_copy_cmap(&d->cmap, cmap, kspc ? 0 : 2);
-   } else {
-      fb_copy_cmap(fb_default_cmap(i->current_par.cmap_len), cmap, kspc ? 0 : 2);
-   }
-   return 0;
-}
-
-static int tdfxfb_set_cmap(struct fb_cmap *cmap, 
-			   int kspc, 
-			   int con,
-			   struct fb_info *fb) {
-   struct display *d=(con<0) ? fb->disp : fb_display + con;
-   struct fb_info_tdfx *i = (struct fb_info_tdfx*)fb;
-
-   int cmap_len= (i->current_par.bpp == 8) ? 256 : 16;
-   if (d->cmap.len!=cmap_len) {
-      int err;
-      if((err = fb_alloc_cmap(&d->cmap, cmap_len, 0)))
-	return err;
-   }
-   if(con == fb->currcon) {
-      /* current console? */
-      return fb_set_cmap(cmap, kspc, fb);
-   } else {
-      fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1);
-   }
-   return 0;
+	case 32:
+		disp->dispsw = noaccel ? &fbcon_cfb32 : &fbcon_banshee32;
+		disp->dispsw_data = info->fbcon_cmap.cfb32;
+		if (nohwcursor)
+			fbcon_banshee32.cursor = NULL;
+		break;
+#endif
+	default:
+		disp->dispsw = &fbcon_dummy;
+	}
+
+}
+
+static int tdfxfb_set_var(struct fb_var_screeninfo *var,
+			  int con, struct fb_info *fb)
+{
+	struct fb_info_tdfx *info = (struct fb_info_tdfx *) fb;
+	struct tdfxfb_par par;
+	struct display *display;
+	int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel,
+	    err;
+	int activate = var->activate;
+	int j, k;
+
+	if (con >= 0)
+		display = &fb_display[con];
+	else
+		display = fb->disp;	/* used during initialization */
+
+	if ((err = tdfxfb_decode_var(var, &par, info)))
+		return err;
+
+	tdfxfb_encode_var(var, &par, info);
+
+	if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+		oldxres = display->var.xres;
+		oldyres = display->var.yres;
+		oldvxres = display->var.xres_virtual;
+		oldvyres = display->var.yres_virtual;
+		oldbpp = display->var.bits_per_pixel;
+		oldaccel = display->var.accel_flags;
+		display->var = *var;
+		if (con < 0 ||
+		    oldxres != var->xres ||
+		    oldyres != var->yres ||
+		    oldvxres != var->xres_virtual ||
+		    oldvyres != var->yres_virtual ||
+		    oldbpp != var->bits_per_pixel ||
+		    oldaccel != var->accel_flags) {
+			struct fb_fix_screeninfo fix;
+
+			tdfxfb_encode_fix(&fix, &par, info);
+			display->visual = fix.visual;
+			display->type = fix.type;
+			display->type_aux = fix.type_aux;
+			display->ypanstep = fix.ypanstep;
+			display->ywrapstep = fix.ywrapstep;
+			display->line_length = fix.line_length;
+			display->next_line = fix.line_length;
+			display->can_soft_blank = 1;
+			display->inverse = inverse;
+			accel = var->accel_flags & FB_ACCELF_TEXT;
+			tdfxfb_set_dispsw(display, info, par.bpp, accel);
+
+			if (nopan)
+				display->scrollmode = SCROLL_YREDRAW;
+
+			if (info->fb_info.changevar)
+				(*info->fb_info.changevar) (con);
+		}
+		if (var->bits_per_pixel == 8)
+			for (j = 0; j < 16; j++) {
+				k = color_table[j];
+				fb_info.palette[j].red = default_red[k];
+				fb_info.palette[j].green = default_grn[k];
+				fb_info.palette[j].blue = default_blu[k];
+			}
+
+		del_timer(&(info->cursor.timer));
+		fb_info.cursor.state = CM_ERASE;
+		if (!info->fb_info.display_fg ||
+		    info->fb_info.display_fg->vc_num == con || con < 0)
+			tdfxfb_set_par(&par, info);
+		if (!nohwcursor)
+			if (display && display->conp)
+				tdfxfb_createcursor(display);
+		info->cursor.redraw = 1;
+		if (oldbpp != var->bits_per_pixel || con < 0) {
+			if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+				return err;
+			do_install_cmap(con, &(info->fb_info));
+		}
+	}
+
+	return 0;
+}
+
+static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
+			      int con, struct fb_info *fb)
+{
+	struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
+
+	if (nopan)
+		return -EINVAL;
+	if (var->xoffset)
+		return -EINVAL;
+	if (var->yoffset > var->yres_virtual)
+		return -EINVAL;
+	if (nowrap && (var->yoffset + var->yres > var->yres_virtual))
+		return -EINVAL;
+
+	if (con == fb->currcon)
+		do_pan_var(var, i);
+
+	fb_display[con].var.xoffset = var->xoffset;
+	fb_display[con].var.yoffset = var->yoffset;
+	return 0;
+}
+
+static int tdfxfb_get_cmap(struct fb_cmap *cmap,
+			   int kspc, int con, struct fb_info *fb)
+{
+
+	struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
+	struct display *d = (con < 0) ? fb->disp : fb_display + con;
+
+	if (con == fb->currcon) {
+		/* current console? */
+		return fb_get_cmap(cmap, kspc, tdfxfb_getcolreg, fb);
+	} else if (d->cmap.len) {
+		/* non default colormap? */
+		fb_copy_cmap(&d->cmap, cmap, kspc ? 0 : 2);
+	} else {
+		fb_copy_cmap(fb_default_cmap(i->current_par.cmap_len),
+			     cmap, kspc ? 0 : 2);
+	}
+	return 0;
+}
+
+static int tdfxfb_set_cmap(struct fb_cmap *cmap,
+			   int kspc, int con, struct fb_info *fb)
+{
+	struct display *d = (con < 0) ? fb->disp : fb_display + con;
+	struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
+
+	int cmap_len = (i->current_par.bpp == 8) ? 256 : 16;
+	if (d->cmap.len != cmap_len) {
+		int err;
+		if ((err = fb_alloc_cmap(&d->cmap, cmap_len, 0)))
+			return err;
+	}
+	if (con == fb->currcon) {
+		/* current console? */
+		return fb_set_cmap(cmap, kspc, fb);
+	} else {
+		fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1);
+	}
+	return 0;
 }
 
 /**
@@ -1901,50 +1781,53 @@
 	char *name = NULL;
 
 	fb_info.dev = pdev->device;
-	
+
 	switch (pdev->device) {
-		case PCI_DEVICE_ID_3DFX_BANSHEE:
-			fb_info.max_pixclock = BANSHEE_MAX_PIXCLOCK;
-			name = "Banshee";
-			break;
-		case PCI_DEVICE_ID_3DFX_VOODOO3:
-			fb_info.max_pixclock = VOODOO3_MAX_PIXCLOCK;
-			name = "Voodoo3";
-			break;
-		case PCI_DEVICE_ID_3DFX_VOODOO5:
-			fb_info.max_pixclock = VOODOO5_MAX_PIXCLOCK;
-			name = "Voodoo5";
-			break;
+	case PCI_DEVICE_ID_3DFX_BANSHEE:
+		fb_info.max_pixclock = BANSHEE_MAX_PIXCLOCK;
+		name = "Banshee";
+		break;
+	case PCI_DEVICE_ID_3DFX_VOODOO3:
+		fb_info.max_pixclock = VOODOO3_MAX_PIXCLOCK;
+		name = "Voodoo3";
+		break;
+	case PCI_DEVICE_ID_3DFX_VOODOO5:
+		fb_info.max_pixclock = VOODOO5_MAX_PIXCLOCK;
+		name = "Voodoo5";
+		break;
 	}
-	
+
 	fb_info.regbase_phys = pci_resource_start(pdev, 0);
 	fb_info.regbase_size = 1 << 24;
-	fb_info.regbase_virt = ioremap_nocache(fb_info.regbase_phys, 1 << 24);
-	
+	fb_info.regbase_virt =
+	    ioremap_nocache(fb_info.regbase_phys, 1 << 24);
+
 	if (!fb_info.regbase_virt) {
-		printk(KERN_WARNING "fb: Can't remap %s register area.\n", name);
+		printk(KERN_WARNING "fb: Can't remap %s register area.\n",
+		       name);
 		return -ENXIO;
 	}
-      
-	fb_info.bufbase_phys = pci_resource_start (pdev, 1);
-	
+
+	fb_info.bufbase_phys = pci_resource_start(pdev, 1);
+
 	if (!(fb_info.bufbase_size = do_lfb_size())) {
 		iounmap(fb_info.regbase_virt);
 		printk(KERN_WARNING "fb: Can't count %s memory.\n", name);
 		return -ENXIO;
 	}
-	
+
 	fb_info.bufbase_virt = ioremap_nocache(fb_info.bufbase_phys,
 					       fb_info.bufbase_size);
-					       
+
 	if (!fb_info.regbase_virt) {
-		printk(KERN_WARNING "fb: Can't remap %s framebuffer.\n", name);
+		printk(KERN_WARNING "fb: Can't remap %s framebuffer.\n",
+		       name);
 		iounmap(fb_info.regbase_virt);
 		return -ENXIO;
 	}
 
-	fb_info.iobase = pci_resource_start (pdev, 2);
-      
+	fb_info.iobase = pci_resource_start(pdev, 2);
+
 	printk("fb: %s memory = %ldK\n", name, fb_info.bufbase_size >> 10);
 
 #ifdef CONFIG_MTRR
@@ -1962,33 +1845,33 @@
 
 	if (!nohwcursor)
 		tdfxfb_hwcursor_init();
-       
+
 	init_timer(&fb_info.cursor.timer);
-	fb_info.cursor.timer.function = do_flashcursor; 
-	fb_info.cursor.timer.data = (unsigned long)(&fb_info);
+	fb_info.cursor.timer.function = do_flashcursor;
+	fb_info.cursor.timer.data = (unsigned long) (&fb_info);
 	fb_info.cursor.state = CM_ERASE;
 	spin_lock_init(&fb_info.DAClock);
-       
-	strcpy(fb_info.fb_info.modename, "3Dfx "); 
+
+	strcpy(fb_info.fb_info.modename, "3Dfx ");
 	strcat(fb_info.fb_info.modename, name);
-	fb_info.fb_info.changevar  = NULL;
-	fb_info.fb_info.node       = NODEV;
-	fb_info.fb_info.fbops      = &tdfxfb_ops;
-	fb_info.fb_info.disp       = &fb_info.disp;
-	fb_info.fb_info.currcon	   = -1;
+	fb_info.fb_info.changevar = NULL;
+	fb_info.fb_info.node = NODEV;
+	fb_info.fb_info.fbops = &tdfxfb_ops;
+	fb_info.fb_info.disp = &fb_info.disp;
+	fb_info.fb_info.currcon = -1;
 	strcpy(fb_info.fb_info.fontname, fontname);
 	fb_info.fb_info.switch_con = &tdfxfb_switch_con;
-	fb_info.fb_info.updatevar  = &tdfxfb_updatevar;
-	fb_info.fb_info.flags      = FBINFO_FLAG_DEFAULT;
-      
+	fb_info.fb_info.updatevar = &tdfxfb_updatevar;
+	fb_info.fb_info.flags = FBINFO_FLAG_DEFAULT;
+
 	memset(&var, 0, sizeof(var));
-	
+
 	if (!mode_option || !fb_find_mode(&var, &fb_info.fb_info,
 					  mode_option, NULL, 0, NULL, 8))
 		var = default_mode[0].var;
 
 	noaccel ? (var.accel_flags &= ~FB_ACCELF_TEXT) :
-		  (var.accel_flags |=  FB_ACCELF_TEXT) ;
+	    (var.accel_flags |= FB_ACCELF_TEXT);
 
 	if (tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
 		/* 
@@ -1996,37 +1879,42 @@
 		 * line), so try the default
 		 */
 
-		printk(KERN_NOTICE "tdfxfb: can't decode the supplied video mode, using default\n");
+		printk(KERN_NOTICE
+		       "tdfxfb: can't decode the supplied video mode, using default\n");
 
 		var = default_mode[0].var;
 
 		noaccel ? (var.accel_flags &= ~FB_ACCELF_TEXT) :
-			  (var.accel_flags |=  FB_ACCELF_TEXT) ;
+		    (var.accel_flags |= FB_ACCELF_TEXT);
 
-		if (tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
+		if (tdfxfb_decode_var
+		    (&var, &fb_info.default_par, &fb_info)) {
 			/* this is getting really bad!... */
-			printk(KERN_WARNING "tdfxfb: can't decode default video mode\n");
+			printk(KERN_WARNING
+			       "tdfxfb: can't decode default video mode\n");
 			return -ENXIO;
 		}
 	}
 
 	fb_info.fb_info.screen_base = fb_info.bufbase_virt;
-	fb_info.disp.var         = var;
-      
+	fb_info.disp.var = var;
+
 	if (tdfxfb_set_var(&var, -1, &fb_info.fb_info)) {
-		printk(KERN_WARNING "tdfxfb: can't set default video mode\n");
+		printk(KERN_WARNING
+		       "tdfxfb: can't set default video mode\n");
 		return -ENXIO;
 	}
 
 	if (register_framebuffer(&fb_info.fb_info) < 0) {
-		printk(KERN_WARNING "tdfxfb: can't register framebuffer\n");
+		printk(KERN_WARNING
+		       "tdfxfb: can't register framebuffer\n");
 		return -ENXIO;
 	}
 
-	printk(KERN_INFO "fb%d: %s frame buffer device\n", 
-	     GET_FB_IDX(fb_info.fb_info.node), fb_info.fb_info.modename);
-      
-  	return 0;
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       GET_FB_IDX(fb_info.fb_info.node), fb_info.fb_info.modename);
+
+	return 0;
 }
 
 /**
@@ -2044,10 +1932,11 @@
 	del_timer_sync(&fb_info.cursor.timer);
 
 #ifdef CONFIG_MTRR
-       if (!nomtrr) {
-          mtrr_del(fb_info.mtrr_idx, fb_info.bufbase_phys, fb_info.bufbase_size);
-	    printk("fb: MTRR's turned off\n");
-       }
+	if (!nomtrr) {
+		mtrr_del(fb_info.mtrr_idx, fb_info.bufbase_phys,
+			 fb_info.bufbase_size);
+		printk("fb: MTRR's turned off\n");
+	}
 #endif
 
 	iounmap(fb_info.regbase_virt);
@@ -2076,301 +1965,301 @@
 
 
 #ifndef MODULE
-void tdfxfb_setup(char *options, 
-		  int *ints) {
-  char* this_opt;
-
-  if(!options || !*options)
-    return;
-
-  while((this_opt = strsep(&options, ",")) != NULL) {
-    if(!*this_opt)
-      continue;
-    if(!strcmp(this_opt, "inverse")) {
-      inverse = 1;
-      fb_invert_cmaps();
-    } else if(!strcmp(this_opt, "noaccel")) {
-      noaccel = nopan = nowrap = nohwcursor = 1; 
-    } else if(!strcmp(this_opt, "nopan")) {
-      nopan = 1;
-    } else if(!strcmp(this_opt, "nowrap")) {
-      nowrap = 1;
-    } else if (!strcmp(this_opt, "nohwcursor")) {
-      nohwcursor = 1;
+void tdfxfb_setup(char *options, int *ints)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+		if (!strcmp(this_opt, "inverse")) {
+			inverse = 1;
+			fb_invert_cmaps();
+		} else if (!strcmp(this_opt, "noaccel")) {
+			noaccel = nopan = nowrap = nohwcursor = 1;
+		} else if (!strcmp(this_opt, "nopan")) {
+			nopan = 1;
+		} else if (!strcmp(this_opt, "nowrap")) {
+			nowrap = 1;
+		} else if (!strcmp(this_opt, "nohwcursor")) {
+			nohwcursor = 1;
 #ifdef CONFIG_MTRR
-    } else if (!strcmp(this_opt, "nomtrr")) {
-      nomtrr = 1;
+		} else if (!strcmp(this_opt, "nomtrr")) {
+			nomtrr = 1;
 #endif
-    } else if (!strncmp(this_opt, "font:", 5)) {
-      strncpy(fontname, this_opt + 5, 40);
-    } else {
-      mode_option = this_opt;
-    }
-  } 
+		} else if (!strncmp(this_opt, "font:", 5)) {
+			strncpy(fontname, this_opt + 5, 40);
+		} else {
+			mode_option = this_opt;
+		}
+	}
 }
 #endif
 
-static int tdfxfb_switch_con(int con, 
-			     struct fb_info *fb) {
-   struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
-   struct tdfxfb_par par;
-   int old_con = fb->currcon;
-   int set_par = 1;
-
-   /* Do we have to save the colormap? */
-   if (fb->currcon>=0)
-     if(fb_display[fb->currcon].cmap.len)
-       fb_get_cmap(&fb_display[fb->currcon].cmap, 1, tdfxfb_getcolreg, fb);
-   
-   fb->currcon = con;
-   fb_display[fb->currcon].var.activate = FB_ACTIVATE_NOW; 
-   tdfxfb_decode_var(&fb_display[con].var, &par, info);
-   if (old_con>=0 && vt_cons[old_con]->vc_mode!=KD_GRAPHICS) {
-     /* check if we have to change video registers */
-     struct tdfxfb_par old_par;
-     tdfxfb_decode_var(&fb_display[old_con].var, &old_par, info);
-     if (!memcmp(&par,&old_par,sizeof(par)))
-	set_par = 0;	/* avoid flicker */
-   }
-   if (set_par)
-     tdfxfb_set_par(&par, info);
-
-   if (fb_display[con].dispsw && fb_display[con].conp)
-     fb_con.con_cursor(fb_display[con].conp, CM_ERASE);
-   
-   del_timer(&(info->cursor.timer));
-   fb_info.cursor.state=CM_ERASE; 
-   
-   if (!nohwcursor) 
-     if (fb_display[con].conp)
-       tdfxfb_createcursor( &fb_display[con] );
-   
-   info->cursor.redraw=1;
-   
-   tdfxfb_set_dispsw(&fb_display[con], 
-		     info, 
-		     par.bpp,
-		     par.accel_flags & FB_ACCELF_TEXT);
-   
-   do_install_cmap(con, fb);
-   tdfxfb_updatevar(con, fb);
-   
-   return 1;
+static int tdfxfb_switch_con(int con, struct fb_info *fb)
+{
+	struct fb_info_tdfx *info = (struct fb_info_tdfx *) fb;
+	struct tdfxfb_par par;
+	int old_con = fb->currcon;
+	int set_par = 1;
+
+	/* Do we have to save the colormap? */
+	if (fb->currcon >= 0)
+		if (fb_display[fb->currcon].cmap.len)
+			fb_get_cmap(&fb_display[fb->currcon].cmap, 1,
+				    tdfxfb_getcolreg, fb);
+
+	fb->currcon = con;
+	fb_display[fb->currcon].var.activate = FB_ACTIVATE_NOW;
+	tdfxfb_decode_var(&fb_display[con].var, &par, info);
+	if (old_con >= 0 && vt_cons[old_con]->vc_mode != KD_GRAPHICS) {
+		/* check if we have to change video registers */
+		struct tdfxfb_par old_par;
+		tdfxfb_decode_var(&fb_display[old_con].var, &old_par,
+				  info);
+		if (!memcmp(&par, &old_par, sizeof(par)))
+			set_par = 0;	/* avoid flicker */
+	}
+	if (set_par)
+		tdfxfb_set_par(&par, info);
+
+	if (fb_display[con].dispsw && fb_display[con].conp)
+		fb_con.con_cursor(fb_display[con].conp, CM_ERASE);
+
+	del_timer(&(info->cursor.timer));
+	fb_info.cursor.state = CM_ERASE;
+
+	if (!nohwcursor)
+		if (fb_display[con].conp)
+			tdfxfb_createcursor(&fb_display[con]);
+
+	info->cursor.redraw = 1;
+
+	tdfxfb_set_dispsw(&fb_display[con],
+			  info, par.bpp, par.accel_flags & FB_ACCELF_TEXT);
+
+	do_install_cmap(con, fb);
+	tdfxfb_updatevar(con, fb);
+
+	return 1;
 }
 
 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
-static int tdfxfb_blank(int blank, 
-			 struct fb_info *fb)
+static int tdfxfb_blank(int blank, struct fb_info *fb)
+{
+	u32 dacmode, state = 0, vgablank = 0;
+
+	dacmode = tdfx_inl(DACMODE);
+
+	switch (blank) {
+	case 0:		/* Screen: On; HSync: On, VSync: On */
+		state = 0;
+		vgablank = 0;
+		break;
+	case 1:		/* Screen: Off; HSync: On, VSync: On */
+		state = 0;
+		vgablank = 1;
+		break;
+	case 2:		/* Screen: Off; HSync: On, VSync: Off */
+		state = BIT(3);
+		vgablank = 1;
+		break;
+	case 3:		/* Screen: Off; HSync: Off, VSync: On */
+		state = BIT(1);
+		vgablank = 1;
+		break;
+	case 4:		/* Screen: Off; HSync: Off, VSync: Off */
+		state = BIT(1) | BIT(3);
+		vgablank = 1;
+		break;
+	}
+
+	dacmode &= ~(BIT(1) | BIT(3));
+	dacmode |= state;
+	banshee_make_room(1);
+	tdfx_outl(DACMODE, dacmode);
+	if (vgablank)
+		vga_disable_video();
+	else
+		vga_enable_video();
+	return 0;
+}
+
+static int tdfxfb_updatevar(int con, struct fb_info *fb)
 {
-  u32 dacmode, state = 0, vgablank = 0;
 
-  dacmode = tdfx_inl(DACMODE);
+	struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
+	if ((con == fb->currcon) && (!nopan))
+		do_pan_var(&fb_display[con].var, i);
+	return 0;
+}
 
-  switch(blank) {
-  case 0: /* Screen: On; HSync: On, VSync: On */    
-    state    = 0;
-    vgablank = 0;
-    break;
-  case 1: /* Screen: Off; HSync: On, VSync: On */
-    state    = 0;
-    vgablank = 1;
-    break;
-  case 2: /* Screen: Off; HSync: On, VSync: Off */
-    state    = BIT(3);
-    vgablank = 1;
-    break;
-  case 3: /* Screen: Off; HSync: Off, VSync: On */
-    state    = BIT(1);
-    vgablank = 1;
-    break;
-  case 4: /* Screen: Off; HSync: Off, VSync: Off */
-    state    = BIT(1) | BIT(3);
-    vgablank = 1;
-    break;
-  }
-
-  dacmode &= ~(BIT(1) | BIT(3));
-  dacmode |= state;
-  banshee_make_room(1); 
-  tdfx_outl(DACMODE, dacmode);
-  if(vgablank) 
-    vga_disable_video();
-  else
-    vga_enable_video();
-  return 0;
-}
-
-static int  tdfxfb_updatevar(int con, 
-			     struct fb_info* fb) {
-
-   struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
-   if ((con==fb->currcon) && (!nopan)) 
-     do_pan_var(&fb_display[con].var,i);
-   return 0;
-}
-
-static int tdfxfb_getcolreg(unsigned        regno, 
-			    unsigned*       red, 
-			    unsigned*       green,
-			    unsigned*       blue, 
-			    unsigned*       transp,
-			    struct fb_info* fb) {
-   struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
-
-   if (regno > i->current_par.cmap_len) return 1;
-   
-   *red    = i->palette[regno].red; 
-   *green  = i->palette[regno].green; 
-   *blue   = i->palette[regno].blue; 
-   *transp = 0;
-   
-   return 0;
-}
-
-static int tdfxfb_setcolreg(unsigned        regno, 
-			    unsigned        red, 
-			    unsigned        green,
-			    unsigned        blue, 
-			    unsigned        transp,
-			    struct fb_info* info) {
-   struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
-#ifdef FBCON_HAS_CFB8   
-   u32 rgbcol;
-#endif
-   if (regno >= i->current_par.cmap_len) return 1;
-   
-   i->palette[regno].red    = red;
-   i->palette[regno].green  = green;
-   i->palette[regno].blue   = blue;
-   
-   switch(i->current_par.bpp) {
+static int tdfxfb_getcolreg(unsigned regno,
+			    unsigned *red,
+			    unsigned *green,
+			    unsigned *blue,
+			    unsigned *transp, struct fb_info *fb)
+{
+	struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
+
+	if (regno > i->current_par.cmap_len)
+		return 1;
+
+	*red = i->palette[regno].red;
+	*green = i->palette[regno].green;
+	*blue = i->palette[regno].blue;
+	*transp = 0;
+
+	return 0;
+}
+
+static int tdfxfb_setcolreg(unsigned regno,
+			    unsigned red,
+			    unsigned green,
+			    unsigned blue,
+			    unsigned transp, struct fb_info *info)
+{
+	struct fb_info_tdfx *i = (struct fb_info_tdfx *) info;
 #ifdef FBCON_HAS_CFB8
-    case 8:
-      rgbcol=(((u32)red   & 0xff00) << 8) |
-	(((u32)green & 0xff00) << 0) |
-	(((u32)blue  & 0xff00) >> 8);
-      do_setpalentry(regno,rgbcol);
-      break;
+	u32 rgbcol;
+#endif
+	if (regno >= i->current_par.cmap_len)
+		return 1;
+
+	i->palette[regno].red = red;
+	i->palette[regno].green = green;
+	i->palette[regno].blue = blue;
+
+	switch (i->current_par.bpp) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		rgbcol = (((u32) red & 0xff00) << 8) |
+		    (((u32) green & 0xff00) << 0) |
+		    (((u32) blue & 0xff00) >> 8);
+		do_setpalentry(regno, rgbcol);
+		break;
 #endif
 #ifdef FBCON_HAS_CFB16
-    case 16:
-      i->fbcon_cmap.cfb16[regno] =
-	(((u32)red   & 0xf800) >> 0) |
-	(((u32)green & 0xfc00) >> 5) |
-	(((u32)blue  & 0xf800) >> 11);
-	 break;
+	case 16:
+		i->fbcon_cmap.cfb16[regno] =
+		    (((u32) red & 0xf800) >> 0) |
+		    (((u32) green & 0xfc00) >> 5) |
+		    (((u32) blue & 0xf800) >> 11);
+		break;
 #endif
 #ifdef FBCON_HAS_CFB24
-    case 24:
-      i->fbcon_cmap.cfb24[regno] =
-	(((u32)red & 0xff00) << 8) |
-	(((u32)green & 0xff00) << 0) |
-	(((u32)blue & 0xff00) >> 8);
-      break;
+	case 24:
+		i->fbcon_cmap.cfb24[regno] =
+		    (((u32) red & 0xff00) << 8) |
+		    (((u32) green & 0xff00) << 0) |
+		    (((u32) blue & 0xff00) >> 8);
+		break;
 #endif
 #ifdef FBCON_HAS_CFB32
-    case 32:
-      i->fbcon_cmap.cfb32[regno] =
-	(((u32)red   & 0xff00) << 8) |
-	(((u32)green & 0xff00) << 0) |
-	(((u32)blue  & 0xff00) >> 8);
-      break;
-#endif
-    default:
-      DPRINTK("bad depth %u\n", i->current_par.bpp);
-      break;
-   }
-   return 0;
-}
-
-static void tdfxfb_createcursorshape(struct display* p) 
-{
-   unsigned int h,cu,cd;
-   
-   h=fontheight(p);
-   cd=h;
-   if (cd >= 10) cd --; 
-   fb_info.cursor.type=p->conp->vc_cursor_type & CUR_HWMASK;
-   switch (fb_info.cursor.type) {
-      case CUR_NONE: 
-	cu=cd; 
-	break;
-      case CUR_UNDERLINE: 
-	cu=cd - 2; 
-	break;
-      case CUR_LOWER_THIRD: 
-	cu=(h * 2) / 3; 
-	break;
-      case CUR_LOWER_HALF: 
-	cu=h / 2; 
-	break;
-      case CUR_TWO_THIRDS: 
-	cu=h / 3; 
-	break;
-      case CUR_BLOCK:
-      default:
-	cu=0;
+	case 32:
+		i->fbcon_cmap.cfb32[regno] =
+		    (((u32) red & 0xff00) << 8) |
+		    (((u32) green & 0xff00) << 0) |
+		    (((u32) blue & 0xff00) >> 8);
+		break;
+#endif
+	default:
+		DPRINTK("bad depth %u\n", i->current_par.bpp);
+		break;
+	}
+	return 0;
+}
+
+static void tdfxfb_createcursorshape(struct display *p)
+{
+	unsigned int h, cu, cd;
+
+	h = fontheight(p);
 	cd = h;
-	break;
-   }
-   fb_info.cursor.w=fontwidth(p);
-   fb_info.cursor.u=cu;
-   fb_info.cursor.d=cd;
+	if (cd >= 10)
+		cd--;
+	fb_info.cursor.type = p->conp->vc_cursor_type & CUR_HWMASK;
+	switch (fb_info.cursor.type) {
+	case CUR_NONE:
+		cu = cd;
+		break;
+	case CUR_UNDERLINE:
+		cu = cd - 2;
+		break;
+	case CUR_LOWER_THIRD:
+		cu = (h * 2) / 3;
+		break;
+	case CUR_LOWER_HALF:
+		cu = h / 2;
+		break;
+	case CUR_TWO_THIRDS:
+		cu = h / 3;
+		break;
+	case CUR_BLOCK:
+	default:
+		cu = 0;
+		cd = h;
+		break;
+	}
+	fb_info.cursor.w = fontwidth(p);
+	fb_info.cursor.u = cu;
+	fb_info.cursor.d = cd;
 }
-   
+
 static void tdfxfb_createcursor(struct display *p)
 {
-   u8 *cursorbase;
-   u32 xline;
-   unsigned int i;
-   unsigned int h,to;
+	u8 *cursorbase;
+	u32 xline;
+	unsigned int i;
+	unsigned int h, to;
 
-   tdfxfb_createcursorshape(p);
-   xline = ~((1 << (32 - fb_info.cursor.w)) - 1);
+	tdfxfb_createcursorshape(p);
+	xline = ~((1 << (32 - fb_info.cursor.w)) - 1);
 
 #ifdef __LITTLE_ENDIAN
-   xline = swab32(xline);
+	xline = swab32(xline);
 #endif
 
-   cursorbase=(u8*)fb_info.bufbase_virt;
-   h=fb_info.cursor.cursorimage;     
-   
-   to=fb_info.cursor.u;
-   for (i = 0; i < to; i++) {
-	writel(0, cursorbase+h);
-	writel(0, cursorbase+h+4);
-	writel(~0, cursorbase+h+8);
-	writel(~0, cursorbase+h+12);
-	h += 16;
-   }
-   
-   to = fb_info.cursor.d;
-   
-   for (; i < to; i++) {
-	writel(xline, cursorbase+h);
-	writel(0, cursorbase+h+4);
-	writel(~0, cursorbase+h+8);
-	writel(~0, cursorbase+h+12);
-	h += 16;
-   }
-   
-   for (; i < 64; i++) {
-	writel(0, cursorbase+h);
-	writel(0, cursorbase+h+4);
-	writel(~0, cursorbase+h+8);
-	writel(~0, cursorbase+h+12);
-	h += 16;
-   }
+	cursorbase = (u8 *) fb_info.bufbase_virt;
+	h = fb_info.cursor.cursorimage;
+
+	to = fb_info.cursor.u;
+	for (i = 0; i < to; i++) {
+		writel(0, cursorbase + h);
+		writel(0, cursorbase + h + 4);
+		writel(~0, cursorbase + h + 8);
+		writel(~0, cursorbase + h + 12);
+		h += 16;
+	}
+
+	to = fb_info.cursor.d;
+
+	for (; i < to; i++) {
+		writel(xline, cursorbase + h);
+		writel(0, cursorbase + h + 4);
+		writel(~0, cursorbase + h + 8);
+		writel(~0, cursorbase + h + 12);
+		h += 16;
+	}
+
+	for (; i < 64; i++) {
+		writel(0, cursorbase + h);
+		writel(0, cursorbase + h + 4);
+		writel(~0, cursorbase + h + 8);
+		writel(~0, cursorbase + h + 12);
+		h += 16;
+	}
 }
-   
+
 static void tdfxfb_hwcursor_init(void)
 {
-   unsigned int start;
-   start = (fb_info.bufbase_size-1024) & PAGE_MASK;
-   fb_info.bufbase_size=start; 
-   fb_info.cursor.cursorimage=fb_info.bufbase_size;
-   printk("tdfxfb: reserving 1024 bytes for the hwcursor at %p\n",
-	  fb_info.regbase_virt+fb_info.cursor.cursorimage);
+	unsigned int start;
+	start = (fb_info.bufbase_size - 1024) & PAGE_MASK;
+	fb_info.bufbase_size = start;
+	fb_info.cursor.cursorimage = fb_info.bufbase_size;
+	printk("tdfxfb: reserving 1024 bytes for the hwcursor at %p\n",
+	       fb_info.regbase_virt + fb_info.cursor.cursorimage);
 }
-
- 
diff -Nru a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/video/tridentfb.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,1305 @@
+/*
+ * Frame buffer driver for Trident Blade and Image series
+ *
+ * Copyright 2001,2002 - Jani Monoses   <jani@astechnix.ro>
+ *
+ * $Id: tridentfb.c,v 1.3 2002/02/25 20:09:41 marcelo Exp $
+ *
+ * CREDITS:(in order of appearance)
+ * 	skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video
+ * 	Special thanks ;) to Mattia Crivellini <tia@mclink.it>
+ * 	much inspired by the XFree86 4.1.0 Trident driver sources by Alan Hourihane
+ * 	the FreeVGA project
+ *	Francesco Salvestrini <salvestrini@users.sf.net> XP support,code,suggestions
+ * NOTES:
+ * 	Tested on Compaq Presario 12XL300 with CyberBladei1
+ * 	Tested on Toshiba 1800-514 with CyberBladeXPAi1
+ * 	No monitors were harmed during the writing of this driver
+ * TODO:
+ * 	timing value tweaking so it looks good on every monitor in every mode
+ * 	test text acceleration for the Image series
+ *	test DPMS stuff
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include "tridentfb.h"
+
+#define VERSION		"0.6.9"
+
+struct tridentfb_par {
+	struct fb_var_screeninfo var;
+	int bpp;
+	int hres;
+	int vres;
+	int linelength;
+	int vclk;		//in MHz
+
+	int vtotal;
+	int vdispend;
+	int vsyncstart;
+	int vsyncend;
+	int vblankstart;
+	int vblankend;
+
+	int htotal;
+	int hdispend;
+	int hsyncstart;
+	int hsyncend;
+	int hblankstart;
+	int hblankend;
+};
+
+struct tridentfb_info {
+	struct fb_info_gen gen;
+	unsigned int fbmem_virt;	//framebuffer virtual memory address
+	unsigned int fbmem;		//framebuffer physical memory address
+	unsigned int memsize;		//size of fbmem
+	unsigned int io;		//io space address
+	unsigned int io_virt;		//iospace virtual memory address
+	unsigned int nativex;		//flat panel xres
+	struct tridentfb_par currentmode;
+};
+
+static struct fb_ops tridentfb_ops;
+
+static struct tridentfb_info fb_info;
+static struct display disp;
+
+static struct { unsigned char red,green,blue,transp; } palette[256];
+
+static struct fb_var_screeninfo default_var;
+
+static char * tridentfb_name = "Trident";
+
+static int family;
+static int pci_id;
+
+static int defaultaccel;
+static int displaytype;
+
+static int pseudo_pal[16];
+
+
+/* defaults which are normally overriden by user values */
+
+/* video mode */
+static char * mode = "640x480";
+static int bpp = 8;
+
+static int noaccel;
+static int accel;
+
+static int center;
+static int stretch;
+
+static int fp;
+static int crt;
+
+static int memsize;
+static int memdiff;
+static int nativex;
+
+
+MODULE_PARM(mode,"s");
+MODULE_PARM(bpp,"i");
+MODULE_PARM(center,"i");
+MODULE_PARM(stretch,"i");
+MODULE_PARM(noaccel,"i");
+MODULE_PARM(accel,"i");
+MODULE_PARM(memsize,"i");
+MODULE_PARM(memdiff,"i");
+MODULE_PARM(nativex,"i");
+MODULE_PARM(fp,"i");
+MODULE_PARM(crt,"i");
+
+
+
+#define CRT 0x3D0		//CRTC registers offset for color display
+
+#ifndef TRIDENT_MMIO
+	#define TRIDENT_MMIO 1
+#endif
+
+#if TRIDENT_MMIO
+	#define t_outb(val,reg)	writeb(val,fb_info.io_virt + reg)
+	#define t_inb(reg)	readb(fb_info.io_virt + reg)
+#else
+	#define t_outb(val,reg) outb(val,reg)
+	#define t_inb(reg) inb(reg)
+#endif
+
+
+static struct accel_switch {
+	void (*init_accel)(int,int);
+	void (*wait_engine)(void);
+	void (*fill_rect)(int,int,int,int,int);
+	void (*copy_rect)(int,int,int,int,int,int);
+} *acc;
+
+#define writemmr(r,v)	writel(v, fb_info.io_virt + r)
+#define readmmr(r)	readl(fb_info.io_virt + r)
+
+/*
+ * Blade specific acceleration.Not XP's though those are
+ * unaccelerated.
+ */
+
+#define point(x,y) ((y)<<16|(x))
+#define STA	0x2120
+#define CMD	0x2144
+#define ROP	0x2148
+#define CLR	0x2160
+#define SR1	0x2100
+#define SR2	0x2104
+#define DR1	0x2108
+#define DR2	0x210C
+
+#define REPL(x)	x = x | x<<16
+#define ROP_S	0xCC
+
+static void blade_init_accel(int pitch,int bpp)
+{
+	int v1 = (pitch>>3)<<20;
+	int tmp = 0,v2;
+	switch (bpp) {
+		case 8:tmp = 0;break;
+		case 15:tmp = 5;break;
+		case 16:tmp = 1;break;
+		case 24:
+		case 32:tmp = 2;break;
+	}
+	v2 = v1 | (tmp<<29);
+	writemmr(0x21C0,v2);
+	writemmr(0x21C4,v2);
+	writemmr(0x21B8,v2);
+	writemmr(0x21BC,v2);
+	writemmr(0x21D0,v1);
+	writemmr(0x21D4,v1);
+	writemmr(0x21C8,v1);
+	writemmr(0x21CC,v1);
+	writemmr(0x216C,0);
+}
+
+static void blade_wait_engine(void)
+{
+	while(readmmr(STA) & 0xFA800000);
+}
+
+static void blade_fill_rect(int x,int y,int w,int h,int c)
+{
+	writemmr(CLR,c);
+	writemmr(ROP,ROP_S);
+	writemmr(CMD,0x20000000|1<<19|1<<4|2<<2);
+
+	writemmr(DR1,point(x,y));
+	writemmr(DR2,point(x+w-1,y+h-1));
+}
+
+static void blade_copy_rect(int x1,int y1,int x2,int y2,int w,int h)
+{
+	int s1,s2,d1,d2;
+	int direction = 2;
+	s1 = point(x1,y1);
+	s2 = point(x1+w-1,y1+h-1);
+	d1 = point(x2,y2);
+	d2 = point(x2+w-1,y2+h-1);
+
+	if ((y1 > y2) || ((y1 == y2) && (x1 >x2)))
+			direction = 0;
+
+
+	writemmr(ROP,ROP_S);
+	writemmr(CMD,0xE0000000|1<<19|1<<4|1<<2|direction);
+
+	writemmr(SR1,direction?s2:s1);
+	writemmr(SR2,direction?s1:s2);
+	writemmr(DR1,direction?d2:d1);
+	writemmr(DR2,direction?d1:d2);
+}
+
+static struct accel_switch accel_blade = {
+	blade_init_accel,
+	blade_wait_engine,
+	blade_fill_rect,
+	blade_copy_rect,
+};
+
+/*
+ * Image specific acceleration functions
+ */
+static void image_init_accel(int pitch,int bpp)
+{
+	int tmp = 0;
+   	switch (bpp) {
+		case 8:tmp = 0;break;
+		case 15:tmp = 5;break;
+		case 16:tmp = 1;break;
+		case 24:
+		case 32:tmp = 2;break;
+	}
+	writemmr(0x2120, 0xF0000000);
+	writemmr(0x2120, 0x40000000|tmp);
+	writemmr(0x2120, 0x80000000);
+	writemmr(0x2144, 0x00000000);
+	writemmr(0x2148, 0x00000000);
+	writemmr(0x2150, 0x00000000);
+	writemmr(0x2154, 0x00000000);
+	writemmr(0x2120, 0x60000000 |(pitch<<16) |pitch);
+	writemmr(0x216C, 0x00000000);
+	writemmr(0x2170, 0x00000000);
+	writemmr(0x217C, 0x00000000);
+	writemmr(0x2120, 0x10000000);
+	writemmr(0x2130, (2047 << 16) | 2047);
+}
+
+static void image_wait_engine(void)
+{
+	while(readmmr(0x2164) & 0xF0000000);
+}
+
+static void image_fill_rect(int x,int y,int w,int h,int c)
+{
+	writemmr(0x2120,0x80000000);
+	writemmr(0x2120,0x90000000|ROP_S);
+
+	writemmr(0x2144,c);
+
+	writemmr(DR1,point(x,y));
+	writemmr(DR2,point(x+w-1,y+h-1));
+
+	writemmr(0x2124,0x80000000|3<<22|1<<10|1<<9);
+}
+
+static void image_copy_rect(int x1,int y1,int x2,int y2,int w,int h)
+{
+	int s1,s2,d1,d2;
+	int direction = 2;
+	s1 = point(x1,y1);
+	s2 = point(x1+w-1,y1+h-1);
+	d1 = point(x2,y2);
+	d2 = point(x2+w-1,y2+h-1);
+
+	if ((y1 > y2) || ((y1 == y2) && (x1 >x2)))
+			direction = 0;
+
+	writemmr(0x2120,0x80000000);
+	writemmr(0x2120,0x90000000|ROP_S);
+
+	writemmr(SR1,direction?s2:s1);
+	writemmr(SR2,direction?s1:s2);
+	writemmr(DR1,direction?d2:d1);
+	writemmr(DR2,direction?d1:d2);
+	writemmr(0x2124,0x80000000|1<<22|1<<10|1<<7|direction);
+}
+
+
+static struct accel_switch accel_image = {
+	image_init_accel,
+	image_wait_engine,
+	image_fill_rect,
+	image_copy_rect,
+};
+
+/*
+ * Accel functions called by the upper layers
+ */
+
+static void trident_bmove (struct display *p, int sy, int sx,
+				int dy, int dx, int height, int width)
+{
+	sx *= fontwidth(p);
+	dx *= fontwidth(p);
+	width *= fontwidth(p);
+	sy *= fontheight(p);
+	dy *= fontheight(p);
+	height *= fontheight(p);
+	acc->copy_rect(sx,sy,dx,dy,width,height);
+	acc->wait_engine();
+}
+static void trident_clear_helper (int c, struct display *p,
+				int sy, int sx, int height, int width)
+{
+	sx *= fontwidth(p);
+	sy *= fontheight(p);
+	width *= fontwidth(p);
+	height *= fontheight(p);
+	acc->fill_rect(sx,sy,width,height,c);
+	acc->wait_engine();
+}
+
+
+#ifdef FBCON_HAS_CFB8
+static void trident_8bpp_clear (struct vc_data *conp, struct display *p,
+				int sy, int sx, int height, int width)
+{
+	int c;
+	c = attr_bgcol_ec(p,conp) & 0xFF;
+	c |= c<<8;
+	c |= c<<16;
+	trident_clear_helper(c,p,sy,sx,height,width);
+}
+
+static struct display_switch trident_8bpp = {
+	setup:		fbcon_cfb8_setup,
+	bmove:		trident_bmove,
+	clear:		trident_8bpp_clear,
+	putc:		fbcon_cfb8_putc,
+	putcs:		fbcon_cfb8_putcs,
+	revc:		fbcon_cfb8_revc,
+	clear_margins:	fbcon_cfb8_clear_margins,
+	fontwidthmask:	FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
+};
+#endif
+#ifdef FBCON_HAS_CFB16
+static void trident_16bpp_clear (struct vc_data *conp, struct display *p,
+				int sy, int sx, int height, int width)
+{
+	int c;
+	c = ((u16*)p->dispsw_data)[attr_bgcol_ec(p,conp)];
+	c = c | c<<16;
+	trident_clear_helper(c,p,sy,sx,height,width);
+}
+
+static struct display_switch trident_16bpp = {
+	setup:		fbcon_cfb16_setup,
+	bmove:		trident_bmove,
+	clear:		trident_16bpp_clear,
+	putc:		fbcon_cfb16_putc,
+	putcs:		fbcon_cfb16_putcs,
+	revc:		fbcon_cfb16_revc,
+	clear_margins:	fbcon_cfb16_clear_margins,
+	fontwidthmask:	FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
+};
+#endif
+#ifdef FBCON_HAS_CFB32
+static void trident_32bpp_clear (struct vc_data *conp, struct display *p,
+				int sy, int sx, int height, int width)
+{
+	int c;
+	c = ((u32*)p->dispsw_data)[attr_bgcol_ec(p,conp)];
+	trident_clear_helper(c,p,sy,sx,height,width);
+}
+
+static struct display_switch trident_32bpp = {
+	setup:		fbcon_cfb32_setup,
+	bmove:		trident_bmove,
+	clear:		trident_32bpp_clear,
+	putc:		fbcon_cfb32_putc,
+	putcs:		fbcon_cfb32_putcs,
+	revc:		fbcon_cfb32_revc,
+	clear_margins:	fbcon_cfb32_clear_margins,
+	fontwidthmask:	FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
+};
+#endif
+
+/*
+ * Hardware access functions
+ */
+
+static inline unsigned char read3X4(int reg)
+{
+	writeb(reg, fb_info.io_virt + CRT + 4);
+	return readb(fb_info.io_virt + CRT + 5);
+}
+
+static inline void write3X4(int reg, unsigned char val)
+{
+	writeb(reg, fb_info.io_virt + CRT + 4);
+	writeb(val, fb_info.io_virt + CRT + 5);
+}
+
+static inline unsigned char read3C4(int reg)
+{
+	t_outb(reg, 0x3C4);
+	return t_inb(0x3C5);
+}
+
+static inline void write3C4(int reg, unsigned char val)
+{
+	t_outb(reg, 0x3C4);
+	t_outb(val, 0x3C5);
+}
+
+static inline unsigned char read3CE(int reg)
+{
+	t_outb(reg, 0x3CE);
+	return t_inb(0x3CF);
+}
+
+static inline void writeAttr(int reg, unsigned char val)
+{
+	readb(fb_info.io_virt + CRT + 0x0A);	//flip-flop to index
+	t_outb(reg, 0x3C0);
+	t_outb(val, 0x3C0);
+}
+
+static inline unsigned char readAttr(int reg)
+{
+	readb(fb_info.io_virt + CRT + 0x0A);	//flip-flop to index
+	t_outb(reg, 0x3C0);
+	return t_inb(0x3C1);
+}
+
+static inline void write3CE(int reg, unsigned char val)
+{
+	t_outb(reg, 0x3CE);
+	t_outb(val, 0x3CF);
+}
+
+#define unprotect_all()	write3C4(Protection, 0x92);unprotect()
+#define unprotect()	write3C4(NewMode1,0xC2)
+#define bios_reg(reg) 	write3CE(BiosReg, reg)
+#define enable_mmio()	outb(PCIReg, 0x3D4); \
+			outb(inb(0x3D5) | 0x01, 0x3D5)
+#define crtc_unlock()	write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
+
+/*  Return flat panel's maximum x resolution */
+static int __init get_nativex(void)
+{
+	int x,y,tmp;
+
+	if (nativex)
+		return nativex;
+
+       	tmp = (read3CE(VertStretch) >> 4) & 3;
+
+	/* detection broken on XPAi ??? misdetects 1024 for 800 */
+	if (pci_id == CYBERBLADEXPAi1 && tmp == 3)
+		tmp = 2;
+
+	switch (tmp) {
+		case 0:x = 1280;y = 1024;break;
+		case 1:x = 640;y = 480;break;
+		case 2:x = 1024;y = 768;break;
+		default:x = 800;y = 600;break;
+	}
+
+	output("%dx%d flat panel found\n", x, y);
+	return x;
+}
+
+/* Set pitch */
+static void set_lwidth(int width)
+{
+	write3X4(Offset, width & 0xFF);
+	write3X4(AddColReg, (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >>4));
+}
+
+/* For resolutions smaller than FP resolution stretch */
+static void screen_stretch(void)
+{
+	write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 1);
+	write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 1);
+}
+
+/* For resolutions smaller than FP resolution center */
+static void screen_center(void)
+{
+	bios_reg(0);		// no stretch
+	write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 0x80);
+	write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 0x80);
+}
+
+/* Address of first shown pixel in display memory */
+static void set_screen_start(int base)
+{
+	write3X4(StartAddrLow, base & 0xFF);
+	write3X4(StartAddrHigh, (base & 0xFF00) >>8);
+	write3X4(CRTCModuleTest, (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >>11));
+	write3X4(CRTHiOrd, (read3X4(CRTHiOrd) & 0xF8) | (base & 0xE0000) >> 17);
+}
+
+/* Use 20.12 fixed-point for NTSC value and frequency calculation */
+#define calc_freq(n,m,k)  ( (unsigned long)0xE517 * (n+8) / (m+2)*(1<<k) )
+
+/* Set dotclock frequency */
+static void set_vclk(int freq)
+{
+	int m,n,k;
+	int f,fi,d,di;
+	unsigned char lo=0,hi=0;
+
+	d = 20;
+	for(k = 2;k>=0;k--)
+	for(m = 0;m<63;m++)
+	for(n = 0;n<128;n++) {
+		fi = calc_freq(n,m,k);
+		if ((di = abs(fi - freq)) < d) {
+			d = di;
+			f = fi;
+			lo = n;
+			hi = (k<<6) | m;
+		}
+	}
+	write3C4(ClockHigh,hi);
+	write3C4(ClockLow,lo);
+	debug("VCLK = %X %X\n",hi,lo);
+}
+
+/* Set number of lines for flat panels*/
+static void set_number_of_lines(int lines)
+{
+	int tmp = read3CE(CyberEnhance) & 0x8F;
+	if (lines > 768)
+		tmp |= 0x30;
+	else if (lines > 600)
+		tmp |= 0x20;
+	else if (lines > 480)
+		tmp |= 0x10;
+	write3CE(CyberEnhance, tmp);
+}
+
+/*
+ * If we see that FP is active we assume we have one.
+ * Otherwise we have a CRT display.User can override.
+ */
+static unsigned int __init get_displaytype(void)
+{
+	if (fp)
+		return DISPLAY_FP;
+	if (crt)
+		return DISPLAY_CRT;
+	return (read3CE(FPConfig) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
+}
+
+/* Try detecting the video memory size */
+static unsigned int __init get_memsize(void)
+{
+	unsigned char tmp;
+	unsigned int k;
+
+	/* If memory size provided by user */
+	if (memsize)
+		k = memsize * Kb;
+	else
+	switch (pci_id) {
+		case CYBER9525DVD:k = 2560 * Kb;break;
+		case CYBERBLADEXPAi1:k = 16 * Mb;break;
+		case CYBERBLADEXPm16:k = 16 * Mb;break;
+		case CYBERBLADEXPm8:k = 8 * Mb;break;
+		default:
+			tmp = read3X4(SPR) & 0x0F;
+			switch (tmp) {
+				case 3:k = 1 * Mb;break;
+				case 7:k = 2 * Mb;break;
+				case 15:k = 4 * Mb;break;
+				case 4:k = 8 * Mb;break;
+				default:k = 1 * Mb;
+			}
+	}
+
+	k -= memdiff * Kb;
+	output("framebuffer size = %d Kb\n", k/Kb);
+	return k;
+}
+
+
+/* Fill in fix */
+static int trident_encode_fix(struct fb_fix_screeninfo *fix,
+				  const void *par,
+				  struct fb_info_gen *info)
+{
+	struct tridentfb_info * i = (struct tridentfb_info *)info;
+	struct tridentfb_par * p = (struct tridentfb_par *)par;
+
+	debug("enter\n");
+
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id,tridentfb_name);
+
+	fix->smem_start = i->fbmem;
+	fix->smem_len = i->memsize;
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+
+	fix->visual = p->bpp==8 ? FB_VISUAL_PSEUDOCOLOR:FB_VISUAL_TRUECOLOR;
+
+	fix->xpanstep = fix->ywrapstep = 0;
+	fix->ypanstep = 1;
+	fix->line_length = p->linelength;
+	fix->mmio_start = 0;
+	fix->mmio_len = 0;
+
+	fix->accel = FB_ACCEL_NONE;
+
+	debug("exit\n");
+	return 0;
+}
+
+/* Fill in par from var */
+static int trident_decode_var(const struct fb_var_screeninfo *var,
+				  void *par,
+				  struct fb_info_gen *info)
+{
+	struct tridentfb_par * p = (struct tridentfb_par *)par;
+	struct tridentfb_info * i = (struct tridentfb_info *)info;
+	int vres,vfront,vback,vsync;
+	debug("enter\n");
+	p->var = *var;
+	p->bpp = var->bits_per_pixel;
+
+	if (p->bpp == 24 )
+		p->bpp = 32;
+
+	p->linelength = var->xres_virtual * p->bpp/8;
+
+	switch (p->bpp) {
+		case 8:
+			p->var.red.offset = 0;
+			p->var.green.offset = 0;
+			p->var.blue.offset = 0;
+			p->var.red.length = 6;
+			p->var.green.length = 6;
+			p->var.blue.length = 6;
+			break;
+		case 16:
+			p->var.red.offset = 11;
+			p->var.green.offset = 5;
+			p->var.blue.offset = 0;
+			p->var.red.length = 5;
+			p->var.green.length = 6;
+			p->var.blue.length = 5;
+			break;
+		case 32:
+			p->var.red.offset = 16;
+			p->var.green.offset = 8;
+			p->var.blue.offset = 0;
+			p->var.red.length = 8;
+			p->var.green.length = 8;
+			p->var.blue.length = 8;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	/* convert from picoseconds to MHz */
+	p->vclk = 1000000/var->pixclock;
+
+	if (p->bpp == 32)
+		p->vclk *=2;
+
+	p->hres = var->xres;
+	vres = p->vres = var->yres;
+
+	/* See if requested resolution is larger than flat panel */
+	if (p->hres > i->nativex && flatpanel) {
+		return -EINVAL;
+	}
+
+	/* See if requested resolution fits in available memory */
+	if (p->hres * p->vres * p->bpp/8 > i->memsize) {
+		return -EINVAL;
+	}
+
+	vfront = var->upper_margin;
+	vback =	var->lower_margin;
+	vsync =	var->vsync_len;
+
+	/* Compute horizontal and vertical VGA CRTC timing values */
+	if (var->vmode & FB_VMODE_INTERLACED) {
+		vres /= 2;
+		vfront /=2;
+		vback /=2;
+		vsync /=2;
+	}
+
+	if (var->vmode & FB_VMODE_DOUBLE) {
+		vres *= 2;
+		vfront *=2;
+		vback *=2;
+		vsync *=2;
+	}
+
+	p->htotal = (p->hres + var->left_margin + var->right_margin + var->hsync_len)/8 - 10;
+	p->hdispend = p->hres/8 - 1;
+	p->hsyncstart = (p->hres + var->right_margin)/8;
+	p->hsyncend = var->hsync_len/8;
+	p->hblankstart = p->hdispend + 1;
+	p->hblankend = p->htotal + 5;
+
+	p->vtotal = vres + vfront + vback + vsync - 2;
+	p->vdispend = vres - 1;
+	p->vsyncstart = vres + vback;
+	p->vsyncend = vsync;
+	p->vblankstart = vres;
+	p->vblankend = p->vtotal + 2;
+
+	debug("exit\n");
+
+	return 0;
+}
+
+
+/* Fill in var from info */
+static int trident_encode_var(struct fb_var_screeninfo *var,
+				  const void *par,
+				  struct fb_info_gen *info)
+{
+	struct tridentfb_par * p = (struct tridentfb_par *)par;
+	debug("enter\n");
+	*var = p->var;
+	var->bits_per_pixel = p->bpp;
+	debug("exit\n");
+	return 0;
+}
+
+/* Fill in par from hardware */
+static void trident_get_par(void *par, struct fb_info_gen *info)
+{
+	struct tridentfb_par * p = (struct tridentfb_par *)par;
+	struct tridentfb_info * i = (struct tridentfb_info *)info;
+
+	debug("enter\n");
+	*p = i->currentmode;
+	debug("exit\n");
+}
+
+/* Pan the display */
+static int trident_pan_display(const struct fb_var_screeninfo *var,
+				   struct fb_info_gen *info)
+{
+	unsigned int offset;
+	struct tridentfb_info * i = (struct tridentfb_info *)info;
+
+	debug("enter\n");
+
+	offset = (var->xoffset + (var->yoffset * var->xres))
+			* var->bits_per_pixel/32;
+	i->currentmode.var.xoffset = var->xoffset;
+	i->currentmode.var.yoffset = var->yoffset;
+	set_screen_start(offset);
+	debug("exit\n");
+	return 0;
+}
+
+/* Set the hardware from par */
+static void trident_set_par(const void *par, struct fb_info_gen *info)
+{
+	struct tridentfb_par * p = (struct tridentfb_par *)par;
+	struct tridentfb_info * i = (struct tridentfb_info *)info;
+	unsigned char tmp;
+	debug("enter\n");
+
+	i->currentmode = *p;
+	unprotect_all();
+	crtc_unlock();
+	enable_mmio();
+
+	write3CE(CyberControl,8);
+	if (flatpanel && p->hres < i->nativex) {
+		/*
+		 * on flat panels with native size larger
+		 * than requested resolution decide whether
+		 * we stretch or center
+		 */
+		t_outb(0xEB,0x3C2);
+		write3CE(CyberControl,0x81);
+		if (center) //|| (p->bpp==32 && pci_id == CYBERBLADEi1D))
+			screen_center();
+		else if (stretch)
+			screen_stretch();
+
+	} else {
+		t_outb(0x2B,0x3C2);
+		write3CE(CyberControl,8);
+	}
+
+	/* vertical timing values */
+	write3X4(CRTVTotal, p->vtotal & 0xFF);
+	write3X4(CRTVDispEnd, p->vdispend & 0xFF);
+	write3X4(CRTVSyncStart, p->vsyncstart & 0xFF);
+	write3X4(CRTVSyncEnd, (p->vsyncend & 0x0F));
+	write3X4(CRTVBlankStart, p->vblankstart & 0xFF);
+	write3X4(CRTVBlankEnd, 0/*p->vblankend & 0xFF*/);
+
+	/* horizontal timing values */
+	write3X4(CRTHTotal, p->htotal & 0xFF);
+	write3X4(CRTHDispEnd, p->hdispend & 0xFF);
+	write3X4(CRTHSyncStart, p->hsyncstart & 0xFF);
+	write3X4(CRTHSyncEnd, (p->hsyncend & 0x1F) | ((p->hblankend & 0x20)<<2));
+	write3X4(CRTHBlankStart, p->hblankstart & 0xFF);
+	write3X4(CRTHBlankEnd, 0/*(p->hblankend & 0x1F)*/);
+
+	/* higher bits of vertical timing values */
+	tmp = 0x10;
+	if (p->vtotal & 0x100) tmp |= 0x01;
+	if (p->vdispend & 0x100) tmp |= 0x02;
+	if (p->vsyncstart & 0x100) tmp |= 0x04;
+	if (p->vblankstart & 0x100) tmp |= 0x08;
+
+	if (p->vtotal & 0x200) tmp |= 0x20;
+	if (p->vdispend & 0x200) tmp |= 0x40;
+	if (p->vsyncstart & 0x200) tmp |= 0x80;
+
+	write3X4(CRTOverflow, tmp);
+
+
+	tmp = read3X4(CRTHiOrd) | 0x08;	//line compare bit 10
+
+	if (p->vtotal & 0x400) tmp |= 0x80;
+	if (p->vblankstart & 0x400) tmp |= 0x40;
+	if (p->vsyncstart & 0x400) tmp |= 0x20;
+	if (p->vdispend & 0x400) tmp |= 0x10;
+	write3X4(CRTHiOrd, tmp);
+
+	write3X4(HorizOverflow, 0);
+
+	tmp = 0x40;
+	if (p->vblankstart & 0x200) tmp |= 0x20;
+	if (p->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80;  //double scan for 200 line modes
+	write3X4(CRTMaxScanLine, tmp);
+	write3X4(CRTLineCompare,0xFF);
+	write3X4(CRTPRowScan,0);
+	write3X4(CRTModeControl,0xC3);
+	write3X4(LinearAddReg,0x20);	//enable linear addressing
+	tmp = (p->var.vmode & FB_VMODE_INTERLACED) ? 0x84:0x80;
+	write3X4(CRTCModuleTest,tmp);	//enable access extended memory
+	write3X4(GraphEngReg, 0x80);	//enable GE for text acceleration
+
+	if (p->var.accel_flags & FB_ACCELF_TEXT)
+		acc->init_accel(p->hres,p->bpp);
+
+	switch (p->bpp) {
+		case 8:tmp=0;break;
+		case 16:tmp=5;break;
+		case 24:
+			/* tmp=0x29;break; */
+			/* seems like 24bpp is same as 32bpp when using vesafb */
+		case 32:tmp=9;break;
+	}
+	write3X4(PixelBusReg, tmp);
+
+	write3X4(InterfaceSel, 0x5B);	//32bit internal data path
+	write3X4(DRAMControl, 0x30);	//both IO,linear enable
+	write3X4(Performance, 0xBF);
+	write3X4(PCIReg,0x07);		//MMIO & PCI read and write burst enable
+
+	set_vclk(p->vclk);
+
+	write3C4(0,3);
+	write3C4(1,1);		//set char clock 8 dots wide
+	write3C4(2,0x0F);	//enable 4 maps because needed in chain4 mode
+	write3C4(3,0);
+	write3C4(4,0x0E);	//memory mode enable bitmaps ??
+
+	write3CE(MiscExtFunc,(p->bpp==32)?0x1A:0x12);	//divide clock by 2 if 32bpp
+							//chain4 mode display and CPU path
+	write3CE(0x5,0x40);	//no CGA compat,allow 256 col
+	write3CE(0x6,0x05);	//graphics mode
+	write3CE(0x7,0x0F);	//planes?
+
+	writeAttr(0x10,0x41);	//graphics mode and support 256 color modes
+	writeAttr(0x12,0x0F);	//planes
+	writeAttr(0x13,0);	//horizontal pel panning
+
+	//colors
+	for(tmp = 0;tmp < 0x10;tmp++)
+		writeAttr(tmp,tmp);
+	readb(fb_info.io_virt + CRT + 0x0A);	//flip-flop to index
+	t_outb(0x20, 0x3C0);			//enable attr
+
+	switch (p->bpp) {
+		case 8:	tmp = 0;break;		//256 colors
+		case 15: tmp = 0x10;break;
+		case 16: tmp = 0x30;break;	//hicolor
+		case 24: 			//truecolor
+		case 32: tmp = 0xD0;break;
+	}
+
+	t_inb(0x3C8);
+	t_inb(0x3C6);
+	t_inb(0x3C6);
+	t_inb(0x3C6);
+	t_inb(0x3C6);
+	t_outb(tmp,0x3C6);
+	t_inb(0x3C8);
+
+	if (flatpanel)
+		set_number_of_lines(p->vres);
+	set_lwidth(p->hres*p->bpp/(4*16));
+
+	trident_pan_display(&p->var,info);
+	debug("exit\n");
+}
+
+/* Get value of one color register */
+static int trident_getcolreg(unsigned regno, unsigned *red,
+				 unsigned *green, unsigned *blue,
+				 unsigned *transp, struct fb_info *info)
+{
+	struct tridentfb_info * i = (struct tridentfb_info *)info;
+	int m = i->currentmode.bpp==8?256:16;
+
+	debug("enter %d\n",regno);
+
+	if (regno >= m)
+		return 1;
+
+	*red = palette[regno].red;
+	*green = palette[regno].green;
+	*blue = palette[regno].blue;
+	*transp = palette[regno].transp;
+
+	debug("exit\n");
+	return 0;
+}
+
+/* Set one color register */
+static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+				 unsigned blue, unsigned transp,
+				 struct fb_info *info)
+{
+	struct tridentfb_info * i = (struct tridentfb_info *)info;
+	int bpp = i->currentmode.bpp;
+	int m = bpp==8?256:16;
+
+	debug("enter %d\n",regno);
+
+	if (regno >= m)
+		return 1;
+
+	palette[regno].red = red;
+	palette[regno].green = green;
+	palette[regno].blue = blue;
+	palette[regno].transp = transp;
+
+	if (bpp==8) {
+		t_outb(0xFF,0x3C6);
+		t_outb(regno,0x3C8);
+
+		t_outb(red>>10,0x3C9);
+		t_outb(green>>10,0x3C9);
+		t_outb(blue>>10,0x3C9);
+
+	} else
+	if (bpp == 16) 			/* RGB 565 */
+			((u16*)info->pseudo_palette)[regno] = (red & 0xF800) |
+			((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+	else
+	if (bpp == 32)		/* ARGB 8888 */
+		((u32*)info->pseudo_palette)[regno] =
+			((transp & 0xFF00) <<16) 	|
+			((red & 0xFF00) << 8) 		|
+			((green & 0xFF00))		|
+			((blue & 0xFF00)>>8);
+
+	debug("exit\n");
+	return 0;
+}
+
+/* Try blanking the screen.For flat panels it does nothing */
+static int trident_blank(int blank_mode, struct fb_info_gen *info)
+{
+	unsigned char PMCont,DPMSCont;
+
+	debug("enter\n");
+	if (flatpanel)
+		return 0;
+	t_outb(0x04,0x83C8); /* Read DPMS Control */
+	PMCont = t_inb(0x83C6) & 0xFC;
+	DPMSCont = read3CE(PowerStatus) & 0xFC;
+	switch (blank_mode)
+	{
+	case VESA_NO_BLANKING:
+		/* Screen: On, HSync: On, VSync: On */
+		PMCont |= 0x03;
+		DPMSCont |= 0x00;
+		break;
+	case VESA_HSYNC_SUSPEND:
+		/* Screen: Off, HSync: Off, VSync: On */
+		PMCont |= 0x02;
+		DPMSCont |= 0x01;
+		break;
+	case VESA_VSYNC_SUSPEND:
+		/* Screen: Off, HSync: On, VSync: Off */
+		PMCont |= 0x02;
+		DPMSCont |= 0x02;
+		break;
+	case VESA_POWERDOWN:
+		/* Screen: Off, HSync: Off, VSync: Off */
+		PMCont |= 0x00;
+		DPMSCont |= 0x03;
+		break;
+    	}
+
+	write3CE(PowerStatus,DPMSCont);
+    	t_outb(4,0x83C8);
+    	t_outb(PMCont,0x83C6);
+
+	debug("exit\n");
+	return 0;
+}
+
+/* Set display switch used by console */
+static void trident_set_disp(const void *par, struct display *disp,
+				 struct fb_info_gen *info)
+{
+	struct tridentfb_info * i = (struct tridentfb_info *)info;
+	struct fb_info * ii = (struct fb_info *)info;
+	struct tridentfb_par * p = (struct tridentfb_par *)par;
+	int isaccel = p->var.accel_flags & FB_ACCELF_TEXT;
+
+	info->info.screen_base = (char *)i->fbmem_virt;
+	debug("enter\n");
+#ifdef FBCON_HAS_CFB8
+	if (p->bpp == 8 ) {
+		if (isaccel)
+			disp->dispsw = &trident_8bpp;
+		else
+			disp->dispsw = &fbcon_cfb8;
+	} else
+#endif
+#ifdef FBCON_HAS_CFB16
+	if (p->bpp == 16) {
+		if (isaccel)
+			disp->dispsw = &trident_16bpp;
+		else
+			disp->dispsw = &fbcon_cfb16;
+		disp->dispsw_data =ii->pseudo_palette;	/* console palette */
+	} else
+#endif
+#ifdef FBCON_HAS_CFB32
+	if (p->bpp == 32) {
+		if (isaccel)
+			disp->dispsw = &trident_32bpp;
+		else
+			disp->dispsw = &fbcon_cfb32;
+		disp->dispsw_data =ii->pseudo_palette;	/* console palette */
+	} else
+#endif
+	disp->dispsw = &fbcon_dummy;
+	debug("exit\n");
+}
+
+static struct fbgen_hwswitch trident_hwswitch = {
+	NULL, /* detect not needed */
+	trident_encode_fix,
+	trident_decode_var,
+	trident_encode_var,
+	trident_get_par,
+	trident_set_par,
+	trident_getcolreg,
+	trident_pan_display,
+	trident_blank,
+	trident_set_disp
+};
+
+/* List of boards that we are trying to support */
+static struct almost_supported_board {
+	int pci_id;
+	int family;
+	struct accel_switch * acc;
+	char* board_name;
+	int accel;
+} asb[] __initdata = {
+	{ BLADE3D,		BLADE,	&accel_blade, "Blade3D",	ACCEL	},
+	{ CYBERBLADEi7,	BLADE,	&accel_blade, "CyberBladei7",	ACCEL	},
+	{ CYBERBLADEi7D,	BLADE,	&accel_blade, "CyberBladei7D",	ACCEL	},
+	{ CYBERBLADEi1,	BLADE,	&accel_blade, "CyberBladei1",	ACCEL	},
+	{ CYBERBLADEi1D,	BLADE,	&accel_blade, "CyberBladei1D",	ACCEL	},
+	{ CYBERBLADEAi1,	BLADE,	&accel_blade, "CyberBladeAi1",	ACCEL	},
+	{ CYBERBLADEAi1D,	BLADE,	&accel_blade, "CyberBladeAi1D",	ACCEL	},
+	{ CYBERBLADEE4,	BLADE,	&accel_blade, "CyberBladeE4",	ACCEL	},
+
+	{ IMAGE975,	IMAGE,	&accel_image,	"IMAGE975",	NOACCEL	},
+	{ IMAGE985,	IMAGE,	&accel_image,	"IMAGE985",	NOACCEL	},
+	{ CYBER9320,	IMAGE,	&accel_image,	"Cyber9320",	NOACCEL	},
+	{ CYBER9388,	IMAGE,	&accel_image,	"Cyber9388",	NOACCEL	},
+	{ CYBER9520,	IMAGE,	&accel_image,	"Cyber9520",	NOACCEL	},
+	{ CYBER9525DVD,	IMAGE,	&accel_image,	"Cyber9525DVD",	NOACCEL	},
+	{ CYBER9397,	IMAGE,	&accel_image,	"Cyber9397",	NOACCEL	},
+	{ CYBER9397DVD,	IMAGE,	&accel_image,	"Cyber9397DVD",	NOACCEL	},
+
+	{ CYBERBLADEXPAi1,	XP,	&accel_blade,	"CyberBladeXPAi1",	NOACCEL },
+	{ CYBERBLADEXPm8,	XP,	&accel_blade,	"CyberBladeXPm8",	NOACCEL },
+	{ CYBERBLADEXPm16,	XP,	&accel_blade,	"CyberBladeXPm16",	NOACCEL },
+};
+
+static __init int trident_find_board(void)
+{
+	int i;
+	struct pci_dev * board;
+
+	for (i = 0;i < ARRAY_SIZE(asb);i++) {
+      		if ((board = pci_find_device(PCI_VENDOR_ID_TRIDENT,
+				   asb[i].pci_id,
+				   NULL))) {
+	 		family = asb[i].family;
+	 		acc = asb[i].acc;
+	 		pci_id = asb[i].pci_id;
+	 		defaultaccel = asb[i].accel;
+
+			fb_info.io = pci_resource_start(board,1);
+			fb_info.fbmem = pci_resource_start(board,0);
+	 		output("%s board found\n", asb[i].board_name);
+	 		return 1;
+      		}
+   	}
+	output("No Trident board found\n");
+	return 0;
+}
+
+int __init tridentfb_init(void)
+{
+
+	output("Trident framebuffer  %s initializing\n", VERSION);
+
+	if (!trident_find_board())
+     		return -1;
+
+	if (!request_mem_region(fb_info.io, TRIDENT_IOSIZE, "tridentfb")) {
+		debug("request_region failed!\n");
+		return -1;
+	};
+
+	fb_info.io_virt = (unsigned int)ioremap_nocache(fb_info.io, TRIDENT_IOSIZE);
+
+	if (!fb_info.io_virt) {
+		release_region(fb_info.io, TRIDENT_IOSIZE);
+		debug("ioremap failed\n");
+		return -1;
+	}
+
+	fb_info.memsize = get_memsize();
+	if (!request_mem_region(fb_info.fbmem, fb_info.memsize, "tridentfb")) {
+		debug("request_mem_region failed!\n");
+		return -1;
+	}
+
+	fb_info.fbmem_virt = (unsigned int)ioremap_nocache(fb_info.fbmem, fb_info.memsize);
+
+	if (!fb_info.fbmem_virt) {
+		release_mem_region(fb_info.fbmem, fb_info.memsize);
+		debug("ioremap failed\n");
+		return -1;
+	}
+
+	debug("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n",
+		fb_info.fbmem, fb_info.io, fb_info.fbmem_virt, fb_info.io_virt);
+
+	fb_info.gen.parsize = sizeof (struct tridentfb_par);
+	fb_info.gen.fbhw = &trident_hwswitch;
+
+	strcpy(fb_info.gen.info.modename, tridentfb_name);
+	displaytype = get_displaytype();
+	if(flatpanel)
+		fb_info.nativex = get_nativex();
+	fb_info.gen.info.changevar = NULL;
+	fb_info.gen.info.node = NODEV;
+	fb_info.gen.info.fbops = &tridentfb_ops;
+	fb_info.gen.info.disp = &disp;
+
+	fb_info.gen.info.switch_con = &fbgen_switch;
+	fb_info.gen.info.updatevar = &fbgen_update_var;
+
+	fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+	fb_info.gen.info.fontname[0] = '\0';
+	fb_info.gen.info.pseudo_palette = pseudo_pal;
+
+	/* This should give a reasonable default video mode */
+	fb_find_mode(&default_var,&fb_info.gen.info,mode,NULL,0,NULL,bpp);
+	/*
+	 * Unless user explicitly requires accel/noaccel use
+	 * per chip defaults.Accel has priority over noaccel.
+	 */
+	if (accel)
+		defaultaccel = ACCEL;
+	else if (noaccel)
+		defaultaccel = NOACCEL;
+
+	if (defaultaccel == ACCEL)
+		default_var.accel_flags |= FB_ACCELF_TEXT;
+	else
+		default_var.accel_flags &= ~FB_ACCELF_TEXT;
+
+	trident_decode_var(&default_var, &fb_info.currentmode, &fb_info.gen);
+	fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+	default_var.activate |= FB_ACTIVATE_NOW;
+	fbgen_set_disp(-1, &fb_info.gen);
+
+	if (register_framebuffer(&fb_info.gen.info) < 0) {
+		printk("Could not register Trident framebuffer\n");
+		return -EINVAL;
+	}
+
+	output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
+	   GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename,default_var.xres,
+	   default_var.yres,default_var.bits_per_pixel);
+	return 0;
+}
+
+void __exit tridentfb_exit(void)
+{
+	unregister_framebuffer(&fb_info.gen.info);
+	iounmap((void *)fb_info.io_virt);
+	iounmap((void *)fb_info.fbmem_virt);
+}
+
+/*
+ * Parse user specified options (`video=trident:')
+ * example:
+ * 	video=trident:800x600,bpp=16,noaccel
+ */
+int tridentfb_setup(char *options)
+{
+	char * opt;
+	if (!options || !*options)
+		return 0;
+	while((opt=strsep(&options,",")) != NULL) {
+		if (!*opt) continue;
+		if (!strncmp(opt,"noaccel",7))
+			noaccel = 1;
+		else if (!strncmp(opt,"accel",5))
+			accel = 1;
+		else if (!strncmp(opt,"fp",2))
+			displaytype = DISPLAY_FP;
+		else if (!strncmp(opt,"crt",3))
+			displaytype = DISPLAY_CRT;
+		else if (!strncmp(opt,"bpp=",4))
+			bpp = simple_strtoul(opt+4,NULL,0);
+		else if (!strncmp(opt,"center",6))
+			center = 1;
+		else if (!strncmp(opt,"stretch",7))
+			stretch = 1;
+		else if (!strncmp(opt,"memsize=",8))
+			memsize = simple_strtoul(opt+8,NULL,0);
+		else if (!strncmp(opt,"memdiff=",8))
+			memdiff = simple_strtoul(opt+8,NULL,0);
+		else if (!strncmp(opt,"nativex=",8))
+			nativex = simple_strtoul(opt+8,NULL,0);
+		else
+			mode = opt;
+	}
+	return 0;
+}
+
+static struct fb_ops tridentfb_ops = {
+	fb_get_fix:	fbgen_get_fix,
+	fb_get_var:	fbgen_get_var,
+	fb_set_var:	fbgen_set_var,
+	fb_get_cmap:	fbgen_get_cmap,
+	fb_set_cmap:	fbgen_set_cmap,
+	fb_setcolreg:	tridentfb_setcolreg,
+	fb_pan_display:	fbgen_pan_display,
+};
+
+#ifdef MODULE
+module_init(tridentfb_init);
+#endif
+module_exit(tridentfb_exit);
+
+MODULE_AUTHOR("Jani Monoses <jani@astechnix.ro>");
+MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/tridentfb.h b/drivers/video/tridentfb.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/video/tridentfb.h	Wed May 29 11:43:03 2002
@@ -0,0 +1,169 @@
+
+#ifndef TRIDENTFB_DEBUG
+#define TRIDENTFB_DEBUG 0
+#endif
+
+#if TRIDENTFB_DEBUG
+#define debug(f,a...)	printk("%s:" f,  __FUNCTION__ , ## a)
+#else
+#define debug(f,a...)
+#endif
+
+#define output(f, a...) printk("tridentfb: " f, ## a)
+
+#define Kb	(1024)
+#define Mb	(Kb*Kb)
+
+/* PCI IDS of supported cards temporarily here */
+
+#define CYBER9320	0x9320
+#define CYBER9388	0x9388
+#define CYBER9397	0x9397
+#define CYBER9397DVD	0x939A
+#define CYBER9520	0x9520
+#define CYBER9525DVD	0x9525
+#define IMAGE975	0x9750
+#define IMAGE985	0x9850
+#define BLADE3D		0x9880
+#define CYBERBLADEE4	0x9540
+#define CYBERBLADEi7	0x8400
+#define CYBERBLADEi7D	0x8420
+#define CYBERBLADEi1	0x8500
+#define CYBERBLADEi1D	0x8520
+#define CYBERBLADEAi1	0x8600
+#define CYBERBLADEAi1D	0x8620
+#define CYBERBLADEXPAi1 0x8820
+#define CYBERBLADEXPm8  0x9910
+#define CYBERBLADEXPm16 0x9930
+
+/* acceleration families */
+#define IMAGE	0
+#define BLADE	1
+#define XP	2
+
+#define is_image()	(family == IMAGE)
+#define is_blade()	(family == BLADE)
+#define is_xp()		(family == XP)
+
+/* these defines are for 'lcd' variable */
+#define LCD_STRETCH	0
+#define LCD_CENTER	1
+#define LCD_BIOS	2
+
+/* display types */
+#define DISPLAY_CRT	0
+#define DISPLAY_FP	1
+
+#define flatpanel (displaytype == DISPLAY_FP)
+/* these are for defaultaccel variable */
+#define ACCEL	1
+#define NOACCEL	0
+
+#define TRIDENT_IOSIZE	0x20000
+#define NTSC 14.31818
+#define PAL  17.73448
+
+/* General Registers */
+#define SPR	0x1F		/* Software Programming Register (videoram) */
+
+/* 3C4 */
+#define RevisionID 0x09
+#define OldOrNew 0x0B
+#define ConfPort1 0x0C
+#define ConfPort2 0x0C
+#define NewMode2 0x0D
+#define NewMode1 0x0E
+#define Protection 0x11
+#define MCLKLow 0x16
+#define MCLKHigh 0x17
+#define ClockLow 0x18
+#define ClockHigh 0x19
+#define SSetup 0x20
+#define SKey 0x37
+#define SPKey 0x57
+
+/* 0x3x4 */
+#define CRTHTotal	0x00
+#define CRTHDispEnd	0x01
+#define CRTHBlankStart	0x02
+#define CRTHBlankEnd	0x03
+#define CRTHSyncStart	0x04
+#define CRTHSyncEnd	0x05
+
+#define CRTVTotal	0x06
+#define CRTVDispEnd	0x12
+#define CRTVBlankStart	0x15
+#define CRTVBlankEnd	0x16
+#define CRTVSyncStart	0x10
+#define CRTVSyncEnd	0x11
+
+#define CRTOverflow	0x07
+#define CRTPRowScan	0x08
+#define CRTMaxScanLine	0x09
+#define CRTModeControl	0x17
+#define CRTLineCompare	0x18
+
+/* 3x4 */
+#define StartAddrHigh 0x0C
+#define StartAddrLow 0x0D
+#define Offset 0x13
+#define Underline 0x14
+#define CRTCMode 0x17
+#define CRTCModuleTest 0x1E
+#define FIFOControl 0x20
+#define LinearAddReg 0x21
+#define DRAMTiming 0x23
+#define New32 0x23
+#define RAMDACTiming 0x25
+#define CRTHiOrd 0x27
+#define AddColReg 0x29
+#define InterfaceSel 0x2A
+#define HorizOverflow 0x2B
+#define GETest 0x2D
+#define Performance 0x2F
+#define GraphEngReg 0x36
+#define I2C 0x37
+#define PixelBusReg 0x38
+#define PCIReg 0x39
+#define DRAMControl 0x3A
+#define MiscContReg 0x3C
+#define CursorXLow 0x40
+#define CursorXHigh 0x41
+#define CursorYLow 0x42
+#define CursorYHigh 0x43
+#define CursorLocLow 0x44
+#define CursorLocHigh 0x45
+#define CursorXOffset 0x46
+#define CursorYOffset 0x47
+#define CursorFG1 0x48
+#define CursorFG2 0x49
+#define CursorFG3 0x4A
+#define CursorFG4 0x4B
+#define CursorBG1 0x4C
+#define CursorBG2 0x4D
+#define CursorBG3 0x4E
+#define CursorBG4 0x4F
+#define CursorControl 0x50
+#define PCIRetry 0x55
+#define PreEndControl 0x56
+#define PreEndFetch 0x57
+#define PCIMaster 0x60
+#define Enhancement0 0x62
+#define NewEDO 0x64
+#define TVinterface 0xC0
+#define TVMode 0xC1
+#define ClockControl 0xCF
+
+
+/* 3CE */
+#define MiscExtFunc 0x0F
+#define PowerStatus 0x23
+#define MiscIntContReg 0x2F
+#define CyberControl 0x30
+#define CyberEnhance 0x31
+#define FPConfig     0x33
+#define VertStretch  0x52
+#define HorStretch   0x53
+#define BiosMode     0x5c
+#define BiosReg      0x5d
+
diff -Nru a/drivers/video/vesafb.c b/drivers/video/vesafb.c
--- a/drivers/video/vesafb.c	Wed May 29 11:43:01 2002
+++ b/drivers/video/vesafb.c	Wed May 29 11:43:01 2002
@@ -26,71 +26,28 @@
 #include <asm/mtrr.h>
 
 #include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-#include <video/fbcon-mac.h>
 
 #define dac_reg	(0x3c8)
 #define dac_val	(0x3c9)
 
 /* --------------------------------------------------------------------- */
 
-/*
- * card parameters
- */
-
-/* card */
-unsigned long video_base; /* physical addr */
-int   video_size;
-char *video_vbase;        /* mapped */
-
-/* mode */
-static int  video_bpp;
-static int  video_width;
-static int  video_height;
-static int  video_height_virtual;
-static int  video_type = FB_TYPE_PACKED_PIXELS;
-static int  video_visual;
-static int  video_linelength;
-static int  video_cmap_len;
-
-/* --------------------------------------------------------------------- */
-
 static struct fb_var_screeninfo vesafb_defined = {
-	0,0,0,0,	/* W,H, W, H (virtual) load xres,xres_virtual*/
-	0,0,		/* virtual -> visible no offset */
-	8,		/* depth -> load bits_per_pixel */
-	0,		/* greyscale ? */
-	{0,0,0},	/* R */
-	{0,0,0},	/* G */
-	{0,0,0},	/* B */
-	{0,0,0},	/* transparency */
-	0,		/* standard pixel format */
-	FB_ACTIVATE_NOW,
-	-1,-1,
-	0,
-	0L,0L,0L,0L,0L,
-	0L,0L,0,	/* No sync info */
-	FB_VMODE_NONINTERLACED,
-	{0,0,0,0,0,0}
+	activate:	FB_ACTIVATE_NOW,
+	height:		-1,
+	width:		-1,
+	vmode:		FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo vesafb_fix = {
+	id:	"VESA VGA",
+	type:	FB_TYPE_PACKED_PIXELS,
+	accel:	FB_ACCEL_NONE,
 };
 
 static struct display disp;
 static struct fb_info fb_info;
-static struct { u_short blue, green, red, pad; } palette[256];
-static union {
-#ifdef FBCON_HAS_CFB16
-    u16 cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB24
-    u32 cfb24[16];
-#endif
-#ifdef FBCON_HAS_CFB32
-    u32 cfb32[16];
-#endif
-} fbcon_cmap;
+static u32 pseudo_palette[17];
 
 static int             inverse   = 0;
 static int             mtrr      = 0;
@@ -101,8 +58,6 @@
 static void            (*pmi_start)(void);
 static void            (*pmi_pal)(void);
 
-static struct display_switch vesafb_sw;
-
 /* --------------------------------------------------------------------- */
 
 static int vesafb_pan_display(struct fb_var_screeninfo *var, int con,
@@ -119,7 +74,7 @@
 	if ((ypan==1) && var->yoffset+var->yres > var->yres_virtual)
 		return -EINVAL;
 
-	offset = (var->yoffset * video_linelength + var->xoffset) / 4;
+	offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4;
 
         __asm__ __volatile__(
                 "call *(%%edi)"
@@ -132,172 +87,6 @@
 	return 0;
 }
 
-static int vesafb_update_var(int con, struct fb_info *info)
-{
-	if (con == info->currcon && ypan) {
-		struct fb_var_screeninfo *var = &fb_display[info->currcon].var;
-		return vesafb_pan_display(var,con,info);
-	}
-	return 0;
-}
-
-static int vesafb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id,"VESA VGA");
-
-	fix->smem_start=video_base;
-	fix->smem_len=video_size;
-	fix->type = video_type;
-	fix->visual = video_visual;
-	fix->xpanstep  = 0;
-	fix->ypanstep  = ypan     ? 1 : 0;
-	fix->ywrapstep = (ypan>1) ? 1 : 0;
-	fix->line_length=video_linelength;
-	return 0;
-}
-
-static int vesafb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
-{
-	if(con==-1)
-		memcpy(var, &vesafb_defined, sizeof(struct fb_var_screeninfo));
-	else
-		*var=fb_display[con].var;
-	return 0;
-}
-
-static void vesafb_set_disp(int con)
-{
-	struct fb_fix_screeninfo fix;
-	struct display *display;
-	struct display_switch *sw;
-	
-	if (con >= 0)
-		display = &fb_display[con];
-	else
-		display = &disp;	/* used during initialization */
-
-	vesafb_get_fix(&fix, con, 0);
-
-	memset(display, 0, sizeof(struct display));
-	display->visual = fix.visual;
-	display->type = fix.type;
-	display->type_aux = fix.type_aux;
-	display->ypanstep = fix.ypanstep;
-	display->ywrapstep = fix.ywrapstep;
-	display->line_length = fix.line_length;
-	display->next_line = fix.line_length;
-	display->can_soft_blank = 0;
-	display->inverse = inverse;
-	vesafb_get_var(&display->var, -1, &fb_info);
-
-	switch (video_bpp) {
-#ifdef FBCON_HAS_CFB8
-	case 8:
-		sw = &fbcon_cfb8;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB16
-	case 15:
-	case 16:
-		sw = &fbcon_cfb16;
-		display->dispsw_data = fbcon_cmap.cfb16;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB24
-	case 24:
-		sw = &fbcon_cfb24;
-		display->dispsw_data = fbcon_cmap.cfb24;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB32
-	case 32:
-		sw = &fbcon_cfb32;
-		display->dispsw_data = fbcon_cmap.cfb32;
-		break;
-#endif
-	default:
-#ifdef FBCON_HAS_MAC
-		sw = &fbcon_mac;
-		break;
-#else
-		sw = &fbcon_dummy;
-		return;
-#endif
-	}
-	memcpy(&vesafb_sw, sw, sizeof(*sw));
-	display->dispsw = &vesafb_sw;
-	if (!ypan) {
-		display->scrollmode = SCROLL_YREDRAW;
-		vesafb_sw.bmove = fbcon_redraw_bmove;
-	}
-}
-
-static int vesafb_set_var(struct fb_var_screeninfo *var, int con,
-			  struct fb_info *info)
-{
-	static int first = 1;
-
-	if (var->xres           != vesafb_defined.xres           ||
-	    var->yres           != vesafb_defined.yres           ||
-	    var->xres_virtual   != vesafb_defined.xres_virtual   ||
-	    var->yres_virtual   >  video_height_virtual          ||
-	    var->yres_virtual   <  video_height                  ||
-	    var->xoffset                                         ||
-	    var->bits_per_pixel != vesafb_defined.bits_per_pixel ||
-	    var->nonstd) {
-		if (first) {
-			printk(KERN_ERR "Vesafb does not support changing the video mode\n");
-			first = 0;
-		}
-		return -EINVAL;
-	}
-
-	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
-		return 0;
-
-	if (ypan) {
-		if (vesafb_defined.yres_virtual != var->yres_virtual) {
-			vesafb_defined.yres_virtual = var->yres_virtual;
-			if (con != -1) {
-				fb_display[con].var = vesafb_defined;
-				info->changevar(con);
-			}
-		}
-
-		if (var->yoffset != vesafb_defined.yoffset)
-			return vesafb_pan_display(var,con,info);
-		return 0;
-	}
-
-	if (var->yoffset)
-		return -EINVAL;
-	return 0;
-}
-
-static int vesa_getcolreg(unsigned regno, unsigned *red, unsigned *green,
-			  unsigned *blue, unsigned *transp,
-			  struct fb_info *fb_info)
-{
-	/*
-	 *  Read a single color register and split it into colors/transparent.
-	 *  Return != 0 for invalid regno.
-	 */
-
-	if (regno >= video_cmap_len)
-		return 1;
-
-	*red   = palette[regno].red;
-	*green = palette[regno].green;
-	*blue  = palette[regno].blue;
-	*transp = 0;
-	return 0;
-}
-
-#ifdef FBCON_HAS_CFB8
-
 static void vesa_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
 {
 	struct { u_char blue, green, red, pad; } entry;
@@ -325,11 +114,9 @@
 	}
 }
 
-#endif
-
 static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
 			    unsigned blue, unsigned transp,
-			    struct fb_info *fb_info)
+			    struct fb_info *info)
 {
 	/*
 	 *  Set a single color register. The values supplied are
@@ -338,85 +125,62 @@
 	 *  != 0 for invalid regno.
 	 */
 	
-	if (regno >= video_cmap_len)
+	if (regno >= info->cmap.len)
 		return 1;
 
-	palette[regno].red   = red;
-	palette[regno].green = green;
-	palette[regno].blue  = blue;
-	
-	switch (video_bpp) {
-#ifdef FBCON_HAS_CFB8
+	switch (info->var.bits_per_pixel) {
 	case 8:
 		vesa_setpalette(regno,red,green,blue);
 		break;
-#endif
-#ifdef FBCON_HAS_CFB16
-	case 15:
 	case 16:
-		if (vesafb_defined.red.offset == 10) {
+		if (info->var.red.offset == 10) {
 			/* 1:5:5:5 */
-			fbcon_cmap.cfb16[regno] =
-				((red   & 0xf800) >>  1) |
-				((green & 0xf800) >>  6) |
-				((blue  & 0xf800) >> 11);
+			((u32*) (info->pseudo_palette))[regno] =	
+					((red   & 0xf800) >>  1) |
+					((green & 0xf800) >>  6) |
+					((blue  & 0xf800) >> 11);
 		} else {
 			/* 0:5:6:5 */
-			fbcon_cmap.cfb16[regno] =
-				((red   & 0xf800)      ) |
-				((green & 0xfc00) >>  5) |
-				((blue  & 0xf800) >> 11);
+			((u32*) (info->pseudo_palette))[regno] =	
+					((red   & 0xf800)      ) |
+					((green & 0xfc00) >>  5) |
+					((blue  & 0xf800) >> 11);
 		}
 		break;
-#endif
-#ifdef FBCON_HAS_CFB24
 	case 24:
 		red   >>= 8;
 		green >>= 8;
 		blue  >>= 8;
-		fbcon_cmap.cfb24[regno] =
-			(red   << vesafb_defined.red.offset)   |
-			(green << vesafb_defined.green.offset) |
-			(blue  << vesafb_defined.blue.offset);
+		((u32 *)(info->pseudo_palette))[regno] =
+			(red   << info->var.red.offset)   |
+			(green << info->var.green.offset) |
+			(blue  << info->var.blue.offset);
 		break;
-#endif
-#ifdef FBCON_HAS_CFB32
 	case 32:
 		red   >>= 8;
 		green >>= 8;
 		blue  >>= 8;
-		fbcon_cmap.cfb32[regno] =
-			(red   << vesafb_defined.red.offset)   |
-			(green << vesafb_defined.green.offset) |
-			(blue  << vesafb_defined.blue.offset);
+		((u32 *)(info->pseudo_palette))[regno] =
+			(red   << info->var.red.offset)   |
+			(green << info->var.green.offset) |
+			(blue  << info->var.blue.offset);
 		break;
-#endif
     }
     return 0;
 }
 
-static int vesafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			   struct fb_info *info)
-{
-	if (con == info->currcon) /* current console? */
-		return fb_get_cmap(cmap, kspc, vesa_getcolreg, info);
-	else if (fb_display[con].cmap.len) /* non default colormap? */
-		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		fb_copy_cmap(fb_default_cmap(video_cmap_len),
-		     cmap, kspc ? 0 : 2);
-	return 0;
-}
-
 static struct fb_ops vesafb_ops = {
 	owner:		THIS_MODULE,
-	fb_get_fix:	vesafb_get_fix,
-	fb_get_var:	vesafb_get_var,
-	fb_set_var:	vesafb_set_var,
-	fb_get_cmap:	vesafb_get_cmap,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
 	fb_set_cmap:	gen_set_cmap,
 	fb_setcolreg:	vesafb_setcolreg,
 	fb_pan_display:	vesafb_pan_display,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
 };
 
 int __init vesafb_setup(char *options)
@@ -451,59 +215,46 @@
 	return 0;
 }
 
-static int vesafb_switch(int con, struct fb_info *info)
-{
-	/* Do we have to save the colormap? */
-	if (fb_display[info->currcon].cmap.len)
-		fb_get_cmap(&fb_display[info->currcon].cmap, 1, vesa_getcolreg,
-			    info);
-	
-	info->currcon = con;
-	/* Install new colormap */
-	do_install_cmap(con, info);
-	vesafb_update_var(con,info);
-	return 1;
-}
-
 int __init vesafb_init(void)
 {
-	int i,j;
+	int video_cmap_len;
+	int i;
 
 	if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
 		return -ENXIO;
 
-	video_base          = screen_info.lfb_base;
-	video_bpp           = screen_info.lfb_depth;
-	if (15 == video_bpp)
-		video_bpp = 16;
-	video_width         = screen_info.lfb_width;
-	video_height        = screen_info.lfb_height;
-	video_linelength    = screen_info.lfb_linelength;
-	video_size          = screen_info.lfb_size * 65536;
-	video_visual = (video_bpp == 8) ?
+	vesafb_fix.smem_start = screen_info.lfb_base;
+	vesafb_defined.bits_per_pixel = screen_info.lfb_depth;
+	if (15 == vesafb_defined.bits_per_pixel)
+		vesafb_defined.bits_per_pixel = 16;
+	vesafb_defined.xres = screen_info.lfb_width;
+	vesafb_defined.yres = screen_info.lfb_height;
+	vesafb_fix.line_length = screen_info.lfb_linelength;
+	vesafb_fix.smem_len = screen_info.lfb_size * 65536;
+	vesafb_fix.visual   = (vesafb_defined.bits_per_pixel == 8) ?
 		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
 
-	if (!request_mem_region(video_base, video_size, "vesafb")) {
+	if (!request_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len, "vesafb")) {
 		printk(KERN_WARNING
 		       "vesafb: abort, cannot reserve video memory at 0x%lx\n",
-			video_base);
+			vesafb_fix.smem_start);
 		/* We cannot make this fatal. Sometimes this comes from magic
 		   spaces our resource handlers simply don't know about */
 	}
 
-        video_vbase = ioremap(video_base, video_size);
-	if (!video_vbase) {
-		release_mem_region(video_base, video_size);
+        fb_info.screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
+	if (!fb_info.screen_base) {
+		release_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len);
 		printk(KERN_ERR
 		       "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
-			video_size, video_base);
+			vesafb_fix.smem_len, vesafb_fix.smem_start);
 		return -EIO;
 	}
 
 	printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
-	       video_base, video_vbase, video_size/1024);
+	       vesafb_fix.smem_start, fb_info.screen_base, vesafb_fix.smem_len/1024);
 	printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
-	       video_width, video_height, video_bpp, video_linelength, screen_info.pages);
+	       vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages);
 
 	if (screen_info.vesapm_seg) {
 		printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n",
@@ -536,32 +287,27 @@
 		}
 	}
 
-	vesafb_defined.xres=video_width;
-	vesafb_defined.yres=video_height;
-	vesafb_defined.xres_virtual=video_width;
-	vesafb_defined.yres_virtual=video_size / video_linelength;
-	vesafb_defined.bits_per_pixel=video_bpp;
-
-	if (ypan && vesafb_defined.yres_virtual > video_height) {
+	vesafb_defined.xres_virtual = vesafb_defined.xres;
+	vesafb_defined.yres_virtual = vesafb_fix.smem_len / vesafb_fix.line_length;
+	if (ypan && vesafb_defined.yres_virtual > vesafb_defined.yres) {
 		printk(KERN_INFO "vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n",
 		       (ypan > 1) ? "ywrap" : "ypan",vesafb_defined.yres_virtual);
 	} else {
 		printk(KERN_INFO "vesafb: scrolling: redraw\n");
-		vesafb_defined.yres_virtual = video_height;
+		vesafb_defined.yres_virtual = vesafb_defined.yres;
 		ypan = 0;
 	}
-	video_height_virtual = vesafb_defined.yres_virtual;
-
+	
 	/* some dummy values for timing to make fbset happy */
-	vesafb_defined.pixclock     = 10000000 / video_width * 1000 / video_height;
-	vesafb_defined.left_margin  = (video_width / 8) & 0xf8;
+	vesafb_defined.pixclock     = 10000000 / vesafb_defined.xres * 1000 / vesafb_defined.yres;
+	vesafb_defined.left_margin  = (vesafb_defined.xres / 8) & 0xf8;
 	vesafb_defined.right_margin = 32;
 	vesafb_defined.upper_margin = 16;
 	vesafb_defined.lower_margin = 4;
-	vesafb_defined.hsync_len    = (video_width / 8) & 0xf8;
+	vesafb_defined.hsync_len    = (vesafb_defined.xres / 8) & 0xf8;
 	vesafb_defined.vsync_len    = 4;
 
-	if (video_bpp > 8) {
+	if (vesafb_defined.bits_per_pixel > 8) {
 		vesafb_defined.red.offset    = screen_info.red_pos;
 		vesafb_defined.red.length    = screen_info.red_size;
 		vesafb_defined.green.offset  = screen_info.green_pos;
@@ -585,48 +331,49 @@
 		vesafb_defined.red.length   = 6;
 		vesafb_defined.green.length = 6;
 		vesafb_defined.blue.length  = 6;
-		for(i = 0; i < 16; i++) {
-			j = color_table[i];
-			palette[i].red   = default_red[j];
-			palette[i].green = default_grn[j];
-			palette[i].blue  = default_blu[j];
-		}
 		video_cmap_len = 256;
 	}
 
+	vesafb_fix.ypanstep  = ypan     ? 1 : 0;
+	vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0;
+
 	/* request failure does not faze us, as vgacon probably has this
 	 * region already (FIXME) */
 	request_region(0x3c0, 32, "vesafb");
 
 	if (mtrr) {
-		int temp_size = video_size;
+		int temp_size = vesafb_fix.smem_len;
 		/* Find the largest power-of-two */
 		while (temp_size & (temp_size - 1))
                 	temp_size &= (temp_size - 1);
                         
                 /* Try and find a power of two to add */
-		while (temp_size && mtrr_add(video_base, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) {
+		while (temp_size && mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) {
 			temp_size >>= 1;
 		}
 	}
 	
-	strcpy(fb_info.modename, "VESA VGA");
+	strcpy(fb_info.modename, vesafb_fix.id);
 	fb_info.changevar = NULL;
 	fb_info.node = NODEV;
 	fb_info.fbops = &vesafb_ops;
-	fb_info.screen_base = video_vbase;
-	fb_info.disp=&disp;
+	fb_info.var = vesafb_defined;
+	fb_info.fix = vesafb_fix;
 	fb_info.currcon = -1;
-	fb_info.switch_con=&vesafb_switch;
-	fb_info.updatevar=&vesafb_update_var;
-	fb_info.flags=FBINFO_FLAG_DEFAULT;
-	vesafb_set_disp(-1);
+	fb_info.disp = &disp;
+	fb_info.switch_con = gen_switch;
+	fb_info.updatevar = gen_update_var;
+	fb_info.pseudo_palette = pseudo_palette;
+	fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+	fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0);
+	gen_set_disp(-1, &fb_info);
 
 	if (register_framebuffer(&fb_info)<0)
 		return -EINVAL;
 
 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
-	       GET_FB_IDX(fb_info.node), fb_info.modename);
+	       GET_FB_IDX(fb_info.node), fb_info.fix.id);
 	return 0;
 }
 
diff -Nru a/drivers/video/vfb.c b/drivers/video/vfb.c
--- a/drivers/video/vfb.c	Wed May 29 11:43:01 2002
+++ b/drivers/video/vfb.c	Wed May 29 11:43:01 2002
@@ -1,6 +1,8 @@
 /*
  *  linux/drivers/video/vfb.c -- Virtual frame buffer device
  *
+ *      Copyright (C) 2002 James Simmons
+ *
  *	Copyright (C) 1997 Geert Uytterhoeven
  *
  *  This file is subject to the terms and conditions of the GNU General Public
@@ -22,15 +24,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 
-#include <video/fbcon.h>
-#include <video/fbcon-mfb.h>
-#include <video/fbcon-cfb2.h>
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-
+#include <linux/fbcon.h>
 
     /*
      *  RAM we reserve for the frame buffer. This defines the maximum screen
@@ -41,525 +35,447 @@
 
 #define VIDEOMEMSIZE	(1*1024*1024)	/* 1 MB */
 
-static u_long videomemory, videomemorysize = VIDEOMEMSIZE;
+static void *videomemory;
+static u_long videomemorysize = VIDEOMEMSIZE;
 MODULE_PARM(videomemorysize, "l");
-static struct display disp;
+static const char *mode_option __initdata = NULL;
+
 static struct fb_info fb_info;
-static struct { u_char red, green, blue, pad; } palette[256];
-static union {
-#ifdef FBCON_HAS_CFB16
-    u16 cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB24
-    u32 cfb24[16];
-#endif
-#ifdef FBCON_HAS_CFB32
-    u32 cfb32[16];
-#endif
-} fbcon_cmap;
-static char vfb_name[16] = "Virtual FB";
-
-static struct fb_var_screeninfo vfb_default = {
-    /* 640x480, 8 bpp */
-    640, 480, 640, 480, 0, 0, 8, 0,
-    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-    0, 0, -1, -1, 0, 20000, 64, 64, 32, 32, 64, 2,
-    0, FB_VMODE_NONINTERLACED
+static u32 vfb_pseudo_palette[17];
+static struct display disp;
+
+static struct fb_var_screeninfo vfb_default __initdata = {
+	xres:		640,
+	yres:		480,
+	xres_virtual:	640,
+	yres_virtual:	480,
+	bits_per_pixel:	8,
+	red:		{ 0, 8, 0 },
+      	green:		{ 0, 8, 0 },
+      	blue:		{ 0, 8, 0 },
+      	activate:	FB_ACTIVATE_TEST,
+      	height:		-1,
+      	width:		-1,
+      	pixclock:	20000,
+      	left_margin:	64,
+      	right_margin:	64,
+      	upper_margin:	32,
+      	lower_margin:	32,
+      	hsync_len:	64,
+      	vsync_len:	2,
+      	vmode:		FB_VMODE_NONINTERLACED,
 };
 
-static int vfb_enable = 0;	/* disabled by default */
+static struct fb_fix_screeninfo vfb_fix __initdata = {
+	id:		"Virtual FB",
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_PSEUDOCOLOR,
+	xpanstep:	1,
+	ypanstep:	1,
+	ywrapstep:	1,
+	accel:		FB_ACCEL_NONE,
+};
 
+static int vfb_enable __initdata = 0;	/* disabled by default */
+MODULE_PARM(vfb_enable, "i");
 
     /*
      *  Interface used by the world
      */
+int vfb_init(void);
+int vfb_setup(char *);
 
-int vfb_setup(char*);
-
-static int vfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-		       struct fb_info *info);
-static int vfb_get_var(struct fb_var_screeninfo *var, int con,
-		       struct fb_info *info);
-static int vfb_set_var(struct fb_var_screeninfo *var, int con,
-		       struct fb_info *info);
+static int vfb_check_var(struct fb_var_screeninfo *var,
+			 struct fb_info *info);
+static int vfb_set_par(struct fb_info *info);
 static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp, struct fb_info *info);
-static int vfb_pan_display(struct fb_var_screeninfo *var, int con,
+			 u_int transp, struct fb_info *info);
+static int vfb_pan_display(struct fb_var_screeninfo *var,
 			   struct fb_info *info);
-static int vfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			struct fb_info *info);
-
-    /*
-     *  Interface to the low level console driver
-     */
-
-int vfb_init(void);
-static int vfbcon_switch(int con, struct fb_info *info);
-static int vfbcon_updatevar(int con, struct fb_info *info);
-
-    /*
-     *  Internal routines
-     */
-
-static u_long get_line_length(int xres_virtual, int bpp);
-static void vfb_encode_fix(struct fb_fix_screeninfo *fix,
-			   struct fb_var_screeninfo *var);
-static void set_color_bitfields(struct fb_var_screeninfo *var);
-static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp, struct fb_info *info);
+static int vfb_mmap(struct fb_info *info, struct file *file,
+		    struct vm_area_struct *vma);
 
 static struct fb_ops vfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	vfb_get_fix,
-	fb_get_var:	vfb_get_var,
-	fb_set_var:	vfb_set_var,
-	fb_get_cmap:	vfb_get_cmap,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_set_cmap,
 	fb_set_cmap:	gen_set_cmap,
+	fb_check_var:	vfb_check_var,
+	fb_set_par:	vfb_set_par,
 	fb_setcolreg:	vfb_setcolreg,
 	fb_pan_display:	vfb_pan_display,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
+	fb_mmap:	vfb_mmap,
 };
 
     /*
-     *  Get the Fixed Part of the Display
+     *  Internal routines
      */
 
-static int vfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-		       struct fb_info *info)
+static u_long get_line_length(int xres_virtual, int bpp)
 {
-    struct fb_var_screeninfo *var;
+	u_long length;
 
-    if (con == -1)
-	var = &vfb_default;
-    else
-	var = &fb_display[con].var;
-    vfb_encode_fix(fix, var);
-    return 0;
+	length = xres_virtual * bpp;
+	length = (length + 31) & ~31;
+	length >>= 3;
+	return (length);
 }
 
-
     /*
-     *  Get the User Defined Part of the Display
+     *  Setting the video mode has been split into two parts.
+     *  First part, xxxfb_check_var, must not write anything
+     *  to hardware, it should only verify and adjust var.
+     *  This means it doesn't alter par but it does use hardware
+     *  data from it to check this var. 
      */
 
-static int vfb_get_var(struct fb_var_screeninfo *var, int con,
-		       struct fb_info *info)
+static int vfb_check_var(struct fb_var_screeninfo *var,
+			 struct fb_info *info)
 {
-    if (con == -1)
-	*var = vfb_default;
-    else
-	*var = fb_display[con].var;
-    set_color_bitfields(var);
-    return 0;
-}
+	u_long line_length;
 
+	/*
+	 *  FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
+	 *  as FB_VMODE_SMOOTH_XPAN is only used internally
+	 */
 
-    /*
-     *  Set the User Defined Part of the Display
-     */
+	if (var->vmode & FB_VMODE_CONUPDATE) {
+		var->vmode |= FB_VMODE_YWRAP;
+		var->xoffset = info->var.xoffset;
+		var->yoffset = info->var.yoffset;
+	}
 
-static int vfb_set_var(struct fb_var_screeninfo *var, int con,
-		       struct fb_info *info)
-{
-    int err, activate = var->activate;
-    int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-    u_long line_length;
-
-    struct display *display;
-    if (con >= 0)
-	display = &fb_display[con];
-    else
-	display = &disp;	/* used during initialization */
+	/*
+	 *  Some very basic checks
+	 */
+	if (!var->xres)
+		var->xres = 1;
+	if (!var->yres)
+		var->yres = 1;
+	if (var->xres > var->xres_virtual)
+		var->xres_virtual = var->xres;
+	if (var->yres > var->yres_virtual)
+		var->yres_virtual = var->yres;
+	if (var->bits_per_pixel <= 1)
+		var->bits_per_pixel = 1;
+	else if (var->bits_per_pixel <= 8)
+		var->bits_per_pixel = 8;
+	else if (var->bits_per_pixel <= 16)
+		var->bits_per_pixel = 16;
+	else if (var->bits_per_pixel <= 24)
+		var->bits_per_pixel = 24;
+	else if (var->bits_per_pixel <= 32)
+		var->bits_per_pixel = 32;
+	else
+		return -EINVAL;
+
+	if (var->xres_virtual < var->xoffset + var->xres)
+		var->xres_virtual = var->xoffset + var->xres;
+	if (var->yres_virtual < var->yoffset + var->yres)
+		var->yres_virtual = var->yoffset + var->yres;
+
+	/*
+	 *  Memory limit
+	 */
+	line_length =
+	    get_line_length(var->xres_virtual, var->bits_per_pixel);
+	if (line_length * var->yres_virtual > videomemorysize)
+		return -ENOMEM;
+
+	/*
+	 * Now that we checked it we alter var. The reason being is that the video
+	 * mode passed in might not work but slight changes to it might make it 
+	 * work. This way we let the user know what is acceptable.
+	 */
+	switch (var->bits_per_pixel) {
+	case 1:
+	case 8:
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 0;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case 16:		/* RGBA 5551 */
+		if (var->transp.length) {
+			var->red.offset = 0;
+			var->red.length = 5;
+			var->green.offset = 5;
+			var->green.length = 5;
+			var->blue.offset = 10;
+			var->blue.length = 5;
+			var->transp.offset = 15;
+			var->transp.length = 1;
+		} else {	/* RGB 565 */
+			var->red.offset = 0;
+			var->red.length = 5;
+			var->green.offset = 5;
+			var->green.length = 6;
+			var->blue.offset = 11;
+			var->blue.length = 5;
+			var->transp.offset = 0;
+			var->transp.length = 0;
+		}
+		break;
+	case 24:		/* RGB 888 */
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 16;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case 32:		/* RGBA 8888 */
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 16;
+		var->blue.length = 8;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		break;
+	}
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
 
-    /*
-     *  FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
-     *  as FB_VMODE_SMOOTH_XPAN is only used internally
-     */
+	return 0;
+}
 
-    if (var->vmode & FB_VMODE_CONUPDATE) {
-	var->vmode |= FB_VMODE_YWRAP;
-	var->xoffset = display->var.xoffset;
-	var->yoffset = display->var.yoffset;
-    }
+/* This routine actually sets the video mode. It's in here where we
+ * the hardware state info->par and fix which can be affected by the 
+ * change in par. For this driver it doesn't do much. 
+ */
+static int vfb_set_par(struct fb_info *info)
+{
+	info->fix.line_length = get_line_length(info->var.xres_virtual,
+						info->var.bits_per_pixel);
+	return 0;
+}
 
     /*
-     *  Some very basic checks
+     *  Set a single color register. The values supplied are already
+     *  rounded down to the hardware's capabilities (according to the
+     *  entries in the var structure). Return != 0 for invalid regno.
      */
-    if (!var->xres)
-	var->xres = 1;
-    if (!var->yres)
-	var->yres = 1;
-    if (var->xres > var->xres_virtual)
-	var->xres_virtual = var->xres;
-    if (var->yres > var->yres_virtual)
-	var->yres_virtual = var->yres;
-    if (var->bits_per_pixel <= 1)
-	var->bits_per_pixel = 1;
-    else if (var->bits_per_pixel <= 8)
-	var->bits_per_pixel = 8;
-    else if (var->bits_per_pixel <= 16)
-	var->bits_per_pixel = 16;
-#if 0
-    /* fbcon doesn't support this (yet) */
-    else if (var->bits_per_pixel <= 24)
-	var->bits_per_pixel = 24;
-    else if (var->bits_per_pixel <= 32)
-	var->bits_per_pixel = 32;
-#endif
-    else
-	return -EINVAL;
 
-    /*
-     *  Memory limit
-     */
-    line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
-    if (line_length*var->yres_virtual > videomemorysize)
-	return -ENOMEM;
-
-    set_color_bitfields(var);
-
-    if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-	oldxres = display->var.xres;
-	oldyres = display->var.yres;
-	oldvxres = display->var.xres_virtual;
-	oldvyres = display->var.yres_virtual;
-	oldbpp = display->var.bits_per_pixel;
-	display->var = *var;
-	if (oldxres != var->xres || oldyres != var->yres ||
-	    oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
-	    oldbpp != var->bits_per_pixel) {
-	    struct fb_fix_screeninfo fix;
-
-	    vfb_encode_fix(&fix, var);
-	    display->visual = fix.visual;
-	    display->type = fix.type;
-	    display->type_aux = fix.type_aux;
-	    display->ypanstep = fix.ypanstep;
-	    display->ywrapstep = fix.ywrapstep;
-	    display->line_length = fix.line_length;
-	    display->can_soft_blank = 1;
-	    display->inverse = 0;
-	    switch (var->bits_per_pixel) {
-#ifdef FBCON_HAS_MFB
-		case 1:
-		    display->dispsw = &fbcon_mfb;
-		    break;
-#endif
-#ifdef FBCON_HAS_CFB2
-		case 2:
-		    display->dispsw = &fbcon_cfb2;
-		    break;
-#endif
-#ifdef FBCON_HAS_CFB4
-		case 4:
-		    display->dispsw = &fbcon_cfb4;
-		    break;
-#endif
-#ifdef FBCON_HAS_CFB8
+static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			 u_int transp, struct fb_info *info)
+{
+	if (regno >= 256)	/* no. of hw registers */
+		return 1;
+	/*
+	 * Program hardware... do anything you want with transp
+	 */
+
+	/* grayscale works only partially under directcolor */
+	if (info->var.grayscale) {
+		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue =
+		    (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	/* Directcolor:
+	 *   var->{color}.offset contains start of bitfield
+	 *   var->{color}.length contains length of bitfield
+	 *   {hardwarespecific} contains width of RAMDAC
+	 *   cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset)
+	 *   RAMDAC[X] is programmed to (red, green, blue)
+	 * 
+	 * Pseudocolor:
+	 *    uses offset = 0 && length = RAMDAC register width.
+	 *    var->{color}.offset is 0
+	 *    var->{color}.length contains widht of DAC
+	 *    cmap is not used
+	 *    RAMDAC[X] is programmed to (red, green, blue)
+	 * Truecolor:
+	 *    does not use DAC. Usually 3 are present.
+	 *    var->{color}.offset contains start of bitfield
+	 *    var->{color}.length contains length of bitfield
+	 *    cmap is programmed to (red << red.offset) | (green << green.offset) |
+	 *                      (blue << blue.offset) | (transp << transp.offset)
+	 *    RAMDAC does not exist
+	 */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+	switch (info->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		red = CNVT_TOHW(red, info->var.red.length);
+		green = CNVT_TOHW(green, info->var.green.length);
+		blue = CNVT_TOHW(blue, info->var.blue.length);
+		transp = CNVT_TOHW(transp, info->var.transp.length);
+		break;
+	case FB_VISUAL_DIRECTCOLOR:
+		red = CNVT_TOHW(red, 8);	/* expect 8 bit DAC */
+		green = CNVT_TOHW(green, 8);
+		blue = CNVT_TOHW(blue, 8);
+		/* hey, there is bug in transp handling... */
+		transp = CNVT_TOHW(transp, 8);
+		break;
+	}
+#undef CNVT_TOHW
+	/* Truecolor has hardware independent palette */
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 v;
+
+		if (regno >= 16)
+			return 1;
+
+		v = (red << info->var.red.offset) |
+		    (green << info->var.green.offset) |
+		    (blue << info->var.blue.offset) |
+		    (transp << info->var.transp.offset);
+		switch (info->var.bits_per_pixel) {
 		case 8:
-		    display->dispsw = &fbcon_cfb8;
-		    break;
-#endif
-#ifdef FBCON_HAS_CFB16
+			break;
 		case 16:
-		    display->dispsw = &fbcon_cfb16;
-		    display->dispsw_data = fbcon_cmap.cfb16;
-		    break;
-#endif
-#ifdef FBCON_HAS_CFB24
+			((u32 *) (info->pseudo_palette))[regno] = v;
+			break;
 		case 24:
-		    display->dispsw = &fbcon_cfb24;
-		    display->dispsw_data = fbcon_cmap.cfb24;
-		    break;
-#endif
-#ifdef FBCON_HAS_CFB32
 		case 32:
-		    display->dispsw = &fbcon_cfb32;
-		    display->dispsw_data = fbcon_cmap.cfb32;
-		    break;
-#endif
-		default:
-		    display->dispsw = &fbcon_dummy;
-		    break;
-	    }
-	    if (fb_info.changevar)
-		(*fb_info.changevar)(con);
-	}
-	if (oldbpp != var->bits_per_pixel) {
-	    if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-		return err;
-	    do_install_cmap(con, info);
+			((u32 *) (info->pseudo_palette))[regno] = v;
+			break;
+		}
+		return 0;
 	}
-    }
-    return 0;
+	return 0;
 }
 
-
     /*
      *  Pan or Wrap the Display
      *
      *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
      */
 
-static int vfb_pan_display(struct fb_var_screeninfo *var, int con,
+static int vfb_pan_display(struct fb_var_screeninfo *var,
 			   struct fb_info *info)
 {
-    if (var->vmode & FB_VMODE_YWRAP) {
-	if (var->yoffset < 0 ||
-	    var->yoffset >= fb_display[con].var.yres_virtual ||
-	    var->xoffset)
-	    return -EINVAL;
-    } else {
-	if (var->xoffset+fb_display[con].var.xres >
-	    fb_display[con].var.xres_virtual ||
-	    var->yoffset+fb_display[con].var.yres >
-	    fb_display[con].var.yres_virtual)
-	    return -EINVAL;
-    }
-    fb_display[con].var.xoffset = var->xoffset;
-    fb_display[con].var.yoffset = var->yoffset;
-    if (var->vmode & FB_VMODE_YWRAP)
-	fb_display[con].var.vmode |= FB_VMODE_YWRAP;
-    else
-	fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
-    return 0;
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset < 0
+		    || var->yoffset >= info->var.yres_virtual
+		    || var->xoffset)
+			return -EINVAL;
+	} else {
+		if (var->xoffset + var->xres > info->var.xres_virtual ||
+		    var->yoffset + var->yres > info->var.yres_virtual)
+			return -EINVAL;
+	}
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		info->var.vmode &= ~FB_VMODE_YWRAP;
+	return 0;
 }
 
     /*
-     *  Get the Colormap
+     *  Most drivers don't need their own mmap function 
      */
 
-static int vfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			struct fb_info *info)
+static int vfb_mmap(struct fb_info *info, struct file *file,
+		    struct vm_area_struct *vma)
 {
-    if (con == info->currcon) /* current console? */
-	return fb_get_cmap(cmap, kspc, vfb_getcolreg, info);
-    else if (fb_display[con].cmap.len) /* non default colormap? */
-	fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-    else
-	fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-		     cmap, kspc ? 0 : 2);
-    return 0;
+	return -EINVAL;
 }
 
 int __init vfb_setup(char *options)
 {
-    char *this_opt;
-
-    fb_info.fontname[0] = '\0';
+	char *this_opt;
 
-    vfb_enable = 1;
+	vfb_enable = 1;
 
-    if (!options || !*options)
-	return 0;
+	if (!options || !*options)
+		return 1;
 
-    while ((this_opt = strsep(&options, ",")) != NULL) {
-	if (!strncmp(this_opt, "font:", 5))
-	    strcpy(fb_info.fontname, this_opt+5);
-    }
-    return 0;
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+		if (!strncmp(this_opt, "disable", 7))
+			vfb_enable = 0;
+	}
+	return 1;
 }
 
-
     /*
      *  Initialisation
      */
 
 int __init vfb_init(void)
 {
-    if (!vfb_enable)
-	return -ENXIO;
-
-    if (!(videomemory = (u_long)vmalloc(videomemorysize)))
-	return -ENOMEM;
-
-    strcpy(fb_info.modename, vfb_name);
-    fb_info.changevar = NULL;
-    fb_info.node = NODEV;
-    fb_info.fbops = &vfb_ops;
-    fb_info.screen_base = (char *)videomemory;
-    fb_info.disp = &disp;
-    fb_info.currcon = -1;	
-    fb_info.switch_con = &vfbcon_switch;
-    fb_info.updatevar = &vfbcon_updatevar;
-    fb_info.flags = FBINFO_FLAG_DEFAULT;
-
-    vfb_set_var(&vfb_default, -1, &fb_info);
-
-    if (register_framebuffer(&fb_info) < 0) {
-	vfree((void *)videomemory);
-	return -EINVAL;
-    }
-
-    printk(KERN_INFO "fb%d: Virtual frame buffer device, using %ldK of video memory\n",
-	   GET_FB_IDX(fb_info.node), videomemorysize>>10);
-    return 0;
-}
-
-
-static int vfbcon_switch(int con, struct fb_info *info)
-{
-    /* Do we have to save the colormap? */
-    if (fb_display[info->currcon].cmap.len)
-	fb_get_cmap(&fb_display[info->currcon].cmap, 1, vfb_getcolreg, info);
-
-    info->currcon = con;
-    /* Install new colormap */
-    do_install_cmap(con, info);
-    return 0;
-}
-
-    /*
-     *  Update the `var' structure (called by fbcon.c)
-     */
-
-static int vfbcon_updatevar(int con, struct fb_info *info)
-{
-    /* Nothing */
-    return 0;
-}
-
-static u_long get_line_length(int xres_virtual, int bpp)
-{
-    u_long length;
-    
-    length = xres_virtual*bpp;
-    length = (length+31)&-32;
-    length >>= 3;
-    return(length);
-}
-
-static void vfb_encode_fix(struct fb_fix_screeninfo *fix,
-			   struct fb_var_screeninfo *var)
-{
-    memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-    strcpy(fix->id, vfb_name);
-    fix->smem_start = videomemory;
-    fix->smem_len = videomemorysize;
-    fix->type = FB_TYPE_PACKED_PIXELS;
-    fix->type_aux = 0;
-    switch (var->bits_per_pixel) {
-	case 1:
-	    fix->visual = FB_VISUAL_MONO01;
-	    break;
-	case 2:
-	case 4:
-	case 8:
-	    fix->visual = FB_VISUAL_PSEUDOCOLOR;
-	    break;
-	case 16:
-	case 24:
-	case 32:
-	    fix->visual = FB_VISUAL_TRUECOLOR;
-	    break;
-    }
-    fix->ywrapstep = 1;
-    fix->xpanstep = 1;
-    fix->ypanstep = 1;
-    fix->line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
-}
-
-static void set_color_bitfields(struct fb_var_screeninfo *var)
-{
-    switch (var->bits_per_pixel) {
-	case 1:
-	case 8:
-	    var->red.offset = 0;
-	    var->red.length = 8;
-	    var->green.offset = 0;
-	    var->green.length = 8;
-	    var->blue.offset = 0;
-	    var->blue.length = 8;
-	    var->transp.offset = 0;
-	    var->transp.length = 0;
-	    break;
-	case 16:	/* RGB 565 */
-	    var->red.offset = 0;
-	    var->red.length = 5;
-	    var->green.offset = 5;
-	    var->green.length = 6;
-	    var->blue.offset = 11;
-	    var->blue.length = 5;
-	    var->transp.offset = 0;
-	    var->transp.length = 0;
-	    break;
-	case 24:	/* RGB 888 */
-	    var->red.offset = 0;
-	    var->red.length = 8;
-	    var->green.offset = 8;
-	    var->green.length = 8;
-	    var->blue.offset = 16;
-	    var->blue.length = 8;
-	    var->transp.offset = 0;
-	    var->transp.length = 0;
-	    break;
-	case 32:	/* RGBA 8888 */
-	    var->red.offset = 0;
-	    var->red.length = 8;
-	    var->green.offset = 8;
-	    var->green.length = 8;
-	    var->blue.offset = 16;
-	    var->blue.length = 8;
-	    var->transp.offset = 24;
-	    var->transp.length = 8;
-	    break;
-    }
-    var->red.msb_right = 0;
-    var->green.msb_right = 0;
-    var->blue.msb_right = 0;
-    var->transp.msb_right = 0;
-}
-
-
-    /*
-     *  Read a single color register and split it into
-     *  colors/transparent. Return != 0 for invalid regno.
-     */
-
-static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp, struct fb_info *info)
-{
-    if (regno > 255)
-	return 1;
-    *red = (palette[regno].red<<8) | palette[regno].red;
-    *green = (palette[regno].green<<8) | palette[regno].green;
-    *blue = (palette[regno].blue<<8) | palette[regno].blue;
-    *transp = 0;
-    return 0;
-}
+	int retval;
 
+	if (!vfb_enable)
+		return -ENXIO;
 
-    /*
-     *  Set a single color register. The values supplied are already
-     *  rounded down to the hardware's capabilities (according to the
-     *  entries in the var structure). Return != 0 for invalid regno.
-     */
+	/*
+	 * For real video cards we use ioremap.
+	 */
+	if (!(videomemory = vmalloc(videomemorysize)))
+		return -ENOMEM;
+
+	/*
+	 * VFB must clear memory to prevent kernel info
+	 * leakage into userspace
+	 * VGA-based drivers MUST NOT clear memory if
+	 * they want to be able to take over vgacon
+	 */
+	memset(videomemory, 0, videomemorysize);
+
+	fb_info.screen_base = videomemory;
+	fb_info.node = NODEV;
+	fb_info.fbops = &vfb_ops;
+
+	retval = fb_find_mode(&fb_info.var, &fb_info, mode_option,
+			      NULL, 0, NULL, 8);
+
+	if (!retval || (retval == 4))
+		fb_info.var = vfb_default;
+	fb_info.fix = vfb_fix;
+	fb_info.pseudo_palette = &vfb_pseudo_palette;
+	fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+	strcpy(fb_info.modename, vesafb_fix.id);
+	fb_info.changevar = NULL;
+	fb_info.currcon = -1;
+	fb_info.disp = &disp;
+	fb_info.switch_con = gen_switch;
+	fb_info.updatevar = gen_update_var;
+
+	fb_alloc_cmap(&fb_info.cmap, 256, 0);
+
+	if (register_framebuffer(&fb_info) < 0) {
+		vfree(videomemory);
+		return -EINVAL;
+	}
 
-static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp, struct fb_info *info)
-{
-    if (regno > 255)
-	return 1;
-    red >>= 8;
-    green >>= 8;
-    blue >>= 8;
-    palette[regno].red = red;
-    palette[regno].green = green;
-    palette[regno].blue = blue;
-    return 0;
+	printk(KERN_INFO
+	       "fb%d: Virtual frame buffer device, using %ldK of video memory\n",
+	       GET_FB_IDX(fb_info.node), videomemorysize >> 10);
+	return 0;
 }
 
 #ifdef MODULE
-MODULE_LICENSE("GPL");
 
-int init_module(void)
+static void __exit vfb_cleanup(void)
 {
-    return vfb_init();
+	unregister_framebuffer(&fb_info);
+	vfree(videomemory);
 }
 
-void cleanup_module(void)
-{
-    unregister_framebuffer(&fb_info);
-    vfree((void *)videomemory);
-}
+module_init(vfb_init);
+module_exit(vfb_cleanup);
 
-#endif /* MODULE */
+MODULE_LICENSE("GPL");
+#endif				/* MODULE */
diff -Nru a/drivers/zorro/Makefile b/drivers/zorro/Makefile
--- a/drivers/zorro/Makefile	Wed May 29 11:43:02 2002
+++ b/drivers/zorro/Makefile	Wed May 29 11:43:02 2002
@@ -1,15 +1,6 @@
 #
 # Makefile for the Zorro bus specific drivers.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now inherited from the
-# parent makefile.
-#
-
-O_TARGET := driver.o
 
 export-objs		:= zorro.o
 
diff -Nru a/fs/Config.help b/fs/Config.help
--- a/fs/Config.help	Wed May 29 11:43:03 2002
+++ b/fs/Config.help	Wed May 29 11:43:03 2002
@@ -18,21 +18,6 @@
   need this functionality say Y here. Note that you will need latest
   quota utilities for new quota format with this kernel.
 
-CONFIG_QIFACE_COMPAT
-  This option will enable old quota interface in kernel.
-  If you have old quota tools (version <= 3.04) and you don't want to
-  upgrade them say Y here.
-
-CONFIG_QIFACE_V1
-  This is the oldest quota interface. It was used for old quota format.
-  If you have old quota tools and you use old quota format choose this
-  interface (if unsure, this interface is the best one to choose).
-
-CONFIG_QIFACE_V2
-  This quota interface was used by VFS v0 quota format. If you need
-  support for VFS v0 quota format (eg. you're using quota on ReiserFS)
-  and you don't want to upgrade quota tools, choose this interface.
-
 CONFIG_MINIX_FS
   Minix is a simple operating system used in many classes about OS's.
   The minix file system (method to organize files on a hard disk
diff -Nru a/fs/Config.in b/fs/Config.in
--- a/fs/Config.in	Wed May 29 11:43:01 2002
+++ b/fs/Config.in	Wed May 29 11:43:01 2002
@@ -7,11 +7,8 @@
 bool 'Quota support' CONFIG_QUOTA
 dep_tristate '  Old quota format support' CONFIG_QFMT_V1 $CONFIG_QUOTA
 dep_tristate '  VFS v0 quota format support' CONFIG_QFMT_V2 $CONFIG_QUOTA
-dep_mbool '  Compatible quota interfaces' CONFIG_QIFACE_COMPAT $CONFIG_QUOTA
-if [ "$CONFIG_QUOTA" = "y" -a "$CONFIG_QIFACE_COMPAT" = "y" ]; then
-   choice '    Compatible quota interfaces' \
-	"Original	CONFIG_QIFACE_V1 \
-	 VFSv0		CONFIG_QIFACE_V2" Original
+if [ "$CONFIG_QUOTA" = "y" ]; then
+   define_bool CONFIG_QUOTACTL y
 fi
 tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
 tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS
diff -Nru a/fs/Makefile b/fs/Makefile
--- a/fs/Makefile	Wed May 29 11:43:01 2002
+++ b/fs/Makefile	Wed May 29 11:43:01 2002
@@ -7,7 +7,8 @@
 
 O_TARGET := fs.o
 
-export-objs :=	filesystems.o open.o dcache.o buffer.o bio.o inode.o dquot.o
+export-objs :=	filesystems.o open.o dcache.o buffer.o bio.o inode.o dquot.o \
+		mpage.o
 mod-subdirs :=	nls
 
 obj-y :=	open.o read_write.o devices.o file_table.o buffer.o \
@@ -15,7 +16,7 @@
 		namei.o fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
 		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
 		filesystems.o namespace.o seq_file.o xattr.o libfs.o \
-		fs-writeback.o quota.o
+		fs-writeback.o mpage.o
 
 ifneq ($(CONFIG_NFSD),n)
 ifneq ($(CONFIG_NFSD),)
@@ -35,6 +36,7 @@
 obj-$(CONFIG_QUOTA)		+= dquot.o
 obj-$(CONFIG_QFMT_V1)		+= quota_v1.o
 obj-$(CONFIG_QFMT_V2)		+= quota_v2.o
+obj-$(CONFIG_QUOTACTL)		+= quota.o
 
 obj-$(CONFIG_PROC_FS)		+= proc/
 obj-y				+= partitions/
diff -Nru a/fs/binfmt_em86.c b/fs/binfmt_em86.c
--- a/fs/binfmt_em86.c	Wed May 29 11:43:03 2002
+++ b/fs/binfmt_em86.c	Wed May 29 11:43:03 2002
@@ -16,7 +16,9 @@
 #include <linux/binfmts.h>
 #include <linux/elf.h>
 #include <linux/init.h>
+#include <linux/fs.h>
 #include <linux/file.h>
+#include <linux/errno.h>
 
 
 #define EM86_INTERP	"/usr/bin/em86"
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Wed May 29 11:43:03 2002
+++ b/fs/block_dev.c	Wed May 29 11:43:03 2002
@@ -748,7 +748,7 @@
 	sync_page: block_sync_page,
 	prepare_write: blkdev_prepare_write,
 	commit_write: blkdev_commit_write,
-	writeback_mapping: generic_writeback_mapping,
+	writepages: generic_writepages,
 	vm_writeback: generic_vm_writeback,
 	direct_IO: blkdev_direct_IO,
 };
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Wed May 29 11:43:01 2002
+++ b/fs/buffer.c	Wed May 29 11:43:01 2002
@@ -122,8 +122,6 @@
 	wake_up_buffer(bh);
 }
 
-DECLARE_TASK_QUEUE(tq_bdflush);
-
 /*
  * Block until a buffer comes unlocked.  This doesn't stop it
  * from becoming locked again - you have to lock it yourself
@@ -138,7 +136,7 @@
 	get_bh(bh);
 	add_wait_queue(wq, &wait);
 	do {
-		run_task_queue(&tq_disk);
+		blk_run_queues();
 		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 		if (!buffer_locked(bh))
 			break;
@@ -167,8 +165,9 @@
 
 static void buffer_io_error(struct buffer_head *bh)
 {
-	printk(KERN_ERR "Buffer I/O error on device %s, logical block %Ld\n",
-			bdevname(bh->b_bdev), (u64)bh->b_blocknr);
+	printk(KERN_ERR "Buffer I/O error on device %s, logical block %Lu\n",
+			bdevname(bh->b_bdev),
+			(unsigned long long)bh->b_blocknr);
 }
 
 /*
@@ -487,7 +486,7 @@
 
 	wakeup_bdflush();
 	try_to_free_pages(zone, GFP_NOFS, 0);
-	run_task_queue(&tq_disk);
+	blk_run_queues();
 	__set_current_state(TASK_RUNNING);
 	yield();
 }
@@ -543,6 +542,14 @@
 	 */
 	if (page_uptodate && !PageError(page))
 		SetPageUptodate(page);
+
+	/*
+	 * swap page handling is a bit hacky.  A standalone completion handler
+	 * for swapout pages would fix that up.  swapin can use this function.
+	 */
+	if (PageSwapCache(page) && PageWriteback(page))
+		end_page_writeback(page);
+
 	unlock_page(page);
 	return;
 
@@ -771,11 +778,11 @@
  *
  * The private_list buffers generally contain filesystem indirect blocks.
  * The idea is that the filesystem can start I/O against the indirects at
- * the same time as running generic_writeback_mapping(), so the indirect's
+ * the same time as running generic_writepages(), so the indirect's
  * I/O will be merged with the data.
  *
  * We sneakliy write the buffers in probable tail-to-head order.  This is
- * because generic_writeback_mapping writes in probable head-to-tail
+ * because generic_writepages() writes in probable head-to-tail
  * order.  If the file is so huge that the data or the indirects overflow
  * the request queue we will at least get some merging this way.
  *
@@ -835,6 +842,7 @@
 out:
 	return ret;
 }
+EXPORT_SYMBOL(write_mapping_buffers);
 
 void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode)
 {
@@ -1004,7 +1012,7 @@
 	 * the reserve list is empty, we're sure there are 
 	 * async buffer heads in use.
 	 */
-	run_task_queue(&tq_disk);
+	blk_run_queues();
 
 	free_more_memory();
 	goto try_again;
@@ -1400,7 +1408,6 @@
 	head = create_buffers(page, blocksize, 1);
 	bh = head;
 	do {
-		bh->b_end_io = NULL;
 		bh->b_state |= b_state;
 		tail = bh;
 		bh = bh->b_this_page;
@@ -1439,11 +1446,11 @@
  * wait on that I/O in bforget() - it's more efficient to wait on the I/O
  * only if we really need to.  That happens here.
  */
-static void unmap_underlying_metadata(struct buffer_head *bh)
+void unmap_underlying_metadata(struct block_device *bdev, sector_t block)
 {
 	struct buffer_head *old_bh;
 
-	old_bh = __get_hash_table(bh->b_bdev, bh->b_blocknr, 0);
+	old_bh = __get_hash_table(bdev, block, 0);
 	if (old_bh) {
 #if 0	/* This happens.  Later. */
 		if (buffer_dirty(old_bh))
@@ -1539,7 +1546,8 @@
 			if (buffer_new(bh)) {
 				/* blockdev mappings never come here */
 				clear_buffer_new(bh);
-				unmap_underlying_metadata(bh);
+				unmap_underlying_metadata(bh->b_bdev,
+							bh->b_blocknr);
 			}
 		}
 		bh = bh->b_this_page;
@@ -1666,18 +1674,22 @@
 	    block++, block_start=block_end, bh = bh->b_this_page) {
 		block_end = block_start + blocksize;
 		if (block_end <= from || block_start >= to) {
-			if (PageUptodate(page))
-				set_buffer_uptodate(bh);
+			if (PageUptodate(page)) {
+				if (!buffer_uptodate(bh))
+					set_buffer_uptodate(bh);
+			}
 			continue;
 		}
-		clear_buffer_new(bh);
+		if (buffer_new(bh))
+			clear_buffer_new(bh);
 		if (!buffer_mapped(bh)) {
 			err = get_block(inode, block, bh, 1);
 			if (err)
 				goto out;
 			if (buffer_new(bh)) {
 				clear_buffer_new(bh);
-				unmap_underlying_metadata(bh);
+				unmap_underlying_metadata(bh->b_bdev,
+							bh->b_blocknr);
 				if (PageUptodate(page)) {
 					if (!buffer_mapped(bh))
 						buffer_error();
@@ -1695,7 +1707,8 @@
 			}
 		}
 		if (PageUptodate(page)) {
-			set_buffer_uptodate(bh);
+			if (!buffer_uptodate(bh))
+				set_buffer_uptodate(bh);
 			continue; 
 		}
 		if (!buffer_uptodate(bh) &&
@@ -2074,11 +2087,10 @@
 
 	err = 0;
 	if (!buffer_mapped(bh)) {
-		/* Hole? Nothing to do */
-		if (buffer_uptodate(bh))
+		err = get_block(inode, iblock, bh, 0);
+		if (err)
 			goto unlock;
-		get_block(inode, iblock, bh, 0);
-		/* Still unmapped? Nothing to do */
+		/* unmapped? It's a hole - nothing to do */
 		if (!buffer_mapped(bh))
 			goto unlock;
 	}
@@ -2179,7 +2191,8 @@
 			}
 		} else {
 			if (buffer_new(&bh))
-				unmap_underlying_metadata(&bh);
+				unmap_underlying_metadata(bh.b_bdev,
+							bh.b_blocknr);
 			if (!buffer_mapped(&bh))
 				BUG();
 		}
@@ -2267,6 +2280,9 @@
  * calls block_flushpage() under spinlock and hits a locked buffer, and
  * schedules under spinlock.   Another approach would be to teach
  * find_trylock_page() to also trylock the page's writeback flags.
+ *
+ * Swap pages are also marked PageWriteback when they are being written
+ * so that memory allocators will throttle on them.
  */
 int brw_page(int rw, struct page *page,
 		struct block_device *bdev, sector_t b[], int size)
@@ -2297,6 +2313,11 @@
 		bh = bh->b_this_page;
 	} while (bh != head);
 
+	if (rw == WRITE) {
+		BUG_ON(PageWriteback(page));
+		SetPageWriteback(page);
+	}
+
 	/* Stage 2: start the IO */
 	do {
 		struct buffer_head *next = bh->b_this_page;
@@ -2452,7 +2473,7 @@
 
 int block_sync_page(struct page *page)
 {
-	run_task_queue(&tq_disk);
+	blk_run_queues();
 	return 0;
 }
 
diff -Nru a/fs/dcache.c b/fs/dcache.c
--- a/fs/dcache.c	Wed May 29 11:43:01 2002
+++ b/fs/dcache.c	Wed May 29 11:43:01 2002
@@ -65,7 +65,7 @@
 }
 
 /*
- * Release the dentry's inode, using the fileystem
+ * Release the dentry's inode, using the filesystem
  * d_iput() operation if defined.
  * Called with dcache_lock held, drops it.
  */
diff -Nru a/fs/dquot.c b/fs/dquot.c
--- a/fs/dquot.c	Wed May 29 11:43:01 2002
+++ b/fs/dquot.c	Wed May 29 11:43:01 2002
@@ -45,6 +45,10 @@
  *		Added dynamic quota structure allocation
  *		Jan Kara <jack@suse.cz> 12/2000
  *
+ *		Rewritten quota interface. Implemented new quota format and
+ *		formats registering.
+ *		Jan Kara, <jack@suse.cz>, 2001,2002
+ *
  * (C) Copyright 1994 - 1997 Marco van Wieringen 
  */
 
@@ -121,7 +125,7 @@
  * Unused dquots (dq_count == 0) are added to the free_dquots list when freed,
  * and this list is searched whenever we need an available dquot.  Dquots are
  * removed from the list as soon as they are used again, and
- * dqstats_array[DQSTATS_FREE] gives the number of dquots on the list. When
+ * dqstats.free_dquots gives the number of dquots on the list. When
  * dquot is invalidated it's completely released from memory.
  *
  * Dquots with a specific identity (device, type and id) are placed on
@@ -148,7 +152,7 @@
 static LIST_HEAD(free_dquots);
 static struct list_head dquot_hash[NR_DQHASH];
 
-__u32 dqstats_array[DQSTATS_SIZE];
+struct dqstats dqstats;
 
 static void dqput(struct dquot *);
 static struct dquot *dqduplicate(struct dquot *);
@@ -207,14 +211,14 @@
 static inline void put_dquot_head(struct dquot *dquot)
 {
 	list_add(&dquot->dq_free, &free_dquots);
-	++dqstats_array[DQSTATS_FREE];
+	dqstats.free_dquots++;
 }
 
 /* Add a dquot to the tail of the free list */
 static inline void put_dquot_last(struct dquot *dquot)
 {
 	list_add(&dquot->dq_free, free_dquots.prev);
-	++dqstats_array[DQSTATS_FREE];
+	dqstats.free_dquots++;
 }
 
 /* Move dquot to the head of free list (it must be already on it) */
@@ -230,7 +234,7 @@
 		return;
 	list_del(&dquot->dq_free);
 	INIT_LIST_HEAD(&dquot->dq_free);
-	--dqstats_array[DQSTATS_FREE];
+	dqstats.free_dquots--;
 }
 
 static inline void put_inuse(struct dquot *dquot)
@@ -238,12 +242,12 @@
 	/* We add to the back of inuse list so we don't have to restart
 	 * when traversing this list and we block */
 	list_add(&dquot->dq_inuse, inuse_list.prev);
-	++dqstats_array[DQSTATS_ALLOCATED];
+	dqstats.allocated_dquots++;
 }
 
 static inline void remove_inuse(struct dquot *dquot)
 {
-	--dqstats_array[DQSTATS_ALLOCATED];
+	dqstats.allocated_dquots--;
 	list_del(&dquot->dq_inuse);
 }
 
@@ -403,7 +407,7 @@
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt]))
 			dqopt->ops[cnt]->write_file_info(sb, cnt);
-	++dqstats_array[DQSTATS_SYNCS];
+	dqstats.syncs++;
 
 	return 0;
 }
@@ -491,7 +495,7 @@
 	int count = 0;
 
 	lock_kernel();
-	count = dqstats_array[DQSTATS_FREE] / priority;
+	count = dqstats.free_dquots / priority;
 	prune_dqcache(count);
 	unlock_kernel();
 	kmem_cache_shrink(dquot_cachep);
@@ -517,7 +521,7 @@
 	}
 #endif
 
-	++dqstats_array[DQSTATS_DROPS];
+	dqstats.drops++;
 we_slept:
 	if (dquot->dq_dup_ref && dquot->dq_count - dquot->dq_dup_ref <= 1) {	/* Last unduplicated reference? */
 		__wait_dup_drop(dquot);
@@ -597,7 +601,7 @@
 		if (!dquot->dq_count)
 			remove_free_dquot(dquot);
 		get_dquot_ref(dquot);
-		++dqstats_array[DQSTATS_CACHE_HITS];
+		dqstats.cache_hits++;
 		wait_on_dquot(dquot);
 		if (empty)
 			dqput(empty);
@@ -609,7 +613,7 @@
 		return NODQUOT;
 	}
 	++dquot->dq_referenced;
-	++dqstats_array[DQSTATS_LOOKUPS];
+	dqstats.lookups++;
 
 	return dquot;
 }
@@ -629,7 +633,7 @@
 		printk(KERN_ERR "VFS: dqduplicate(): Locked quota to be duplicated!\n");
 	get_dquot_dup_ref(dquot);
 	dquot->dq_referenced++;
-	++dqstats_array[DQSTATS_LOOKUPS];
+	dqstats.lookups++;
 
 	return dquot;
 }
@@ -645,7 +649,7 @@
 	if (!dquot->dq_dup_ref)
 		wake_up(&dquot->dq_wait_free);
 	put_dquot_ref(dquot);
-	++dqstats_array[DQSTATS_DROPS];
+	dqstats.drops++;
 }
 
 static int dqinit_needed(struct inode *inode, int type)
@@ -1295,7 +1299,7 @@
 	int error;
 
 	if (!fmt)
-		return -EINVAL;
+		return -ESRCH;
 	if (is_enabled(dqopt, type)) {
 		error = -EBUSY;
 		goto out_fmt;
@@ -1437,7 +1441,7 @@
 }
 
 /* Generic routine for getting common part of quota file information */
-int vfs_get_info(struct super_block *sb, int type, struct if_dqinfo *ii)
+int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
 {
 	struct mem_dqinfo *mi = sb_dqopt(sb)->info + type;
 
@@ -1449,7 +1453,7 @@
 }
 
 /* Generic routine for setting common part of quota file information */
-int vfs_set_info(struct super_block *sb, int type, struct if_dqinfo *ii)
+int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
 {
 	struct mem_dqinfo *mi = sb_dqopt(sb)->info + type;
 
@@ -1467,18 +1471,30 @@
 	quota_on:	vfs_quota_on,
 	quota_off:	vfs_quota_off,
 	quota_sync:	vfs_quota_sync,
-	get_info:	vfs_get_info,
-	set_info:	vfs_set_info,
+	get_info:	vfs_get_dqinfo,
+	set_info:	vfs_set_dqinfo,
 	get_dqblk:	vfs_get_dqblk,
 	set_dqblk:	vfs_set_dqblk
 };
 
+static ctl_table fs_dqstats_table[] = {
+	{FS_DQ_LOOKUPS, "lookups", &dqstats.lookups, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_DROPS, "drops", &dqstats.drops, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_READS, "reads", &dqstats.reads, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_WRITES, "writes", &dqstats.writes, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_CACHE_HITS, "cache_hits", &dqstats.cache_hits, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_ALLOCATED, "allocated_dquots", &dqstats.allocated_dquots, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_FREE, "free_dquots", &dqstats.free_dquots, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_SYNCS, "syncs", &dqstats.syncs, sizeof(int), 0444, NULL, &proc_dointvec},
+	{},
+};
+
 static ctl_table fs_table[] = {
-	{FS_DQSTATS, "dqstats", dqstats_array, sizeof(dqstats_array), 0444, NULL, &proc_dointvec},
+	{FS_DQSTATS, "quota", NULL, 0, 0555, fs_dqstats_table},
 	{},
 };
 
-static ctl_table dquot_table[] = {
+static ctl_table sys_table[] = {
 	{CTL_FS, "fs", NULL, 0, 0555, fs_table},
 	{},
 };
@@ -1487,7 +1503,7 @@
 {
 	int i;
 
-	register_sysctl_table(dquot_table, 0);
+	register_sysctl_table(sys_table, 0);
 	for (i = 0; i < NR_DQHASH; i++)
 		INIT_LIST_HEAD(dquot_hash + i);
 	printk(KERN_NOTICE "VFS: Disk quotas v%s\n", __DQUOT_VERSION__);
@@ -1498,4 +1514,4 @@
 
 EXPORT_SYMBOL(register_quota_format);
 EXPORT_SYMBOL(unregister_quota_format);
-EXPORT_SYMBOL(dqstats_array);
+EXPORT_SYMBOL(dqstats);
diff -Nru a/fs/driverfs/inode.c b/fs/driverfs/inode.c
--- a/fs/driverfs/inode.c	Wed May 29 11:43:01 2002
+++ b/fs/driverfs/inode.c	Wed May 29 11:43:01 2002
@@ -53,11 +53,49 @@
 static struct inode_operations driverfs_dir_inode_operations;
 static struct dentry_operations driverfs_dentry_dir_ops;
 static struct dentry_operations driverfs_dentry_file_ops;
+static struct address_space_operations driverfs_aops;
 
 static struct vfsmount *driverfs_mount;
 static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED;
 static int mount_count = 0;
 
+
+static int driverfs_readpage(struct file *file, struct page * page)
+{
+	if (!PageUptodate(page)) {
+		memset(kmap(page), 0, PAGE_CACHE_SIZE);
+		kunmap(page);
+		flush_dcache_page(page);
+		SetPageUptodate(page);
+	}
+	unlock_page(page);
+	return 0;
+}
+
+static int driverfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+{
+	void *addr = kmap(page);
+	if (!PageUptodate(page)) {
+		memset(addr, 0, PAGE_CACHE_SIZE);
+		flush_dcache_page(page);
+		SetPageUptodate(page);
+	}
+	SetPageDirty(page);
+	return 0;
+}
+
+static int driverfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+{
+	struct inode *inode = page->mapping->host;
+	loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+
+	kunmap(page);
+	if (pos > inode->i_size)
+		inode->i_size = pos;
+	return 0;
+}
+
+
 struct inode *driverfs_get_inode(struct super_block *sb, int mode, int dev)
 {
 	struct inode *inode = new_inode(sb);
@@ -70,6 +108,7 @@
 		inode->i_blocks = 0;
 		inode->i_rdev = NODEV;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+		inode->i_mapping->a_ops = &driverfs_aops;
 		switch (mode & S_IFMT) {
 		default:
 			init_special_inode(inode, mode, dev);
@@ -81,6 +120,9 @@
 			inode->i_op = &driverfs_dir_inode_operations;
 			inode->i_fop = &simple_dir_operations;
 			break;
+		case S_IFLNK:
+			inode->i_op = &page_symlink_inode_operations;
+			break;
 		}
 	}
 	return inode;
@@ -121,6 +163,24 @@
 	return res;
 }
 
+static int driverfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
+{
+	struct inode *inode;
+	int error = -ENOSPC;
+
+	inode = driverfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
+	if (inode) {
+		int l = strlen(symname)+1;
+		error = block_symlink(inode, symname, l);
+		if (!error) {
+			d_instantiate(dentry, inode);
+			dget(dentry);
+		} else
+			iput(inode);
+	}
+	return error;
+}
+
 static inline int driverfs_positive(struct dentry *dentry)
 {
 	return (dentry->d_inode && !d_unhashed(dentry));
@@ -364,10 +424,18 @@
 	create:		driverfs_create,
 	lookup:		simple_lookup,
 	unlink:		driverfs_unlink,
+	symlink:	driverfs_symlink,
 	mkdir:		driverfs_mkdir,
 	rmdir:		driverfs_rmdir,
 };
 
+static struct address_space_operations driverfs_aops = {
+	readpage:	driverfs_readpage,
+	writepage:	fail_writepage,
+	prepare_write:	driverfs_prepare_write,
+	commit_write:	driverfs_commit_write
+};
+
 static struct dentry_operations driverfs_dentry_file_ops = {
 	d_delete:	driverfs_d_delete_file,
 };
@@ -569,6 +637,52 @@
 }
 
 /**
+ * driverfs_create_symlink - make a symlink
+ * @parent:	directory we're creating in 
+ * @entry:	entry describing link
+ * @target:	place we're symlinking to
+ * 
+ */
+int driverfs_create_symlink(struct driver_dir_entry * parent, 
+			    struct driver_file_entry * entry,
+			    char * target)
+{
+	struct dentry * dentry;
+	struct qstr qstr;
+	int error = 0;
+
+	if (!entry || !parent)
+		return -EINVAL;
+
+	get_mount();
+
+	if (!parent->dentry) {
+		put_mount();
+		return -EINVAL;
+	}
+	down(&parent->dentry->d_inode->i_sem);
+	qstr.name = entry->name;
+	qstr.len = strlen(entry->name);
+	qstr.hash = full_name_hash(entry->name,qstr.len);
+	dentry = lookup_hash(&qstr,parent->dentry);
+	if (!IS_ERR(dentry)) {
+		dentry->d_fsdata = (void *)entry;
+		error = vfs_symlink(parent->dentry->d_inode,dentry,target);
+		if (!error) {
+			dentry->d_inode->u.generic_ip = (void *)entry;
+			entry->dentry = dentry;
+			entry->parent = parent;
+			list_add_tail(&entry->node,&parent->files);
+		}
+	} else
+		error = PTR_ERR(dentry);
+	up(&parent->dentry->d_inode->i_sem);
+	if (error)
+		put_mount();
+	return error;
+}
+
+/**
  * driverfs_remove_file - exported file removal
  * @dir:	directory the file supposedly resides in
  * @name:	name of the file
@@ -641,6 +755,7 @@
 }
 
 EXPORT_SYMBOL(driverfs_create_file);
+EXPORT_SYMBOL(driverfs_create_symlink);
 EXPORT_SYMBOL(driverfs_create_dir);
 EXPORT_SYMBOL(driverfs_remove_file);
 EXPORT_SYMBOL(driverfs_remove_dir);
diff -Nru a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c	Wed May 29 11:43:02 2002
+++ b/fs/exec.c	Wed May 29 11:43:02 2002
@@ -391,48 +391,31 @@
 	return result;
 }
 
-static int exec_mmap(void)
+static int exec_mmap(struct mm_struct *mm)
 {
-	struct mm_struct * mm, * old_mm;
+	struct mm_struct * old_mm, *active_mm;
 
-	old_mm = current->mm;
-	if (old_mm && atomic_read(&old_mm->mm_users) == 1) {
-		mm_release();
-		exit_mmap(old_mm);
-		return 0;
-	}
-
-	mm = mm_alloc();
-	if (mm) {
-		struct mm_struct *active_mm;
-
-		if (init_new_context(current, mm)) {
-			mmdrop(mm);
-			return -ENOMEM;
-		}
+	/* Add it to the list of mm's */
+	spin_lock(&mmlist_lock);
+	list_add(&mm->mmlist, &init_mm.mmlist);
+	mmlist_nr++;
+	spin_unlock(&mmlist_lock);
 
-		/* Add it to the list of mm's */
-		spin_lock(&mmlist_lock);
-		list_add(&mm->mmlist, &init_mm.mmlist);
-		mmlist_nr++;
-		spin_unlock(&mmlist_lock);
-
-		task_lock(current);
-		active_mm = current->active_mm;
-		current->mm = mm;
-		current->active_mm = mm;
-		activate_mm(active_mm, mm);
-		task_unlock(current);
-		mm_release();
-		if (old_mm) {
-			if (active_mm != old_mm) BUG();
-			mmput(old_mm);
-			return 0;
-		}
-		mmdrop(active_mm);
+	task_lock(current);
+	old_mm = current->mm;
+	active_mm = current->active_mm;
+	current->mm = mm;
+	current->active_mm = mm;
+	activate_mm(active_mm, mm);
+	task_unlock(current);
+	mm_release();
+	if (old_mm) {
+		if (active_mm != old_mm) BUG();
+		mmput(old_mm);
 		return 0;
 	}
-	return -ENOMEM;
+	mmdrop(active_mm);
+	return 0;
 }
 
 /*
@@ -571,7 +554,7 @@
 	/* 
 	 * Release all of the old mmap stuff
 	 */
-	retval = exec_mmap();
+	retval = exec_mmap(bprm->mm);
 	if (retval) goto mmap_failed;
 
 	/* This is the point of no return */
@@ -902,17 +885,23 @@
 	bprm.sh_bang = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
-	if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
-		allow_write_access(file);
-		fput(file);
-		return bprm.argc;
-	}
 
-	if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) {
-		allow_write_access(file);
-		fput(file);
-		return bprm.envc;
-	}
+	bprm.mm = mm_alloc();
+	retval = -ENOMEM;
+	if (!bprm.mm)
+		goto out_file;
+
+	retval = init_new_context(current, bprm.mm);
+	if (retval < 0)
+		goto out_mm;
+
+	bprm.argc = count(argv, bprm.p / sizeof(void *));
+	if ((retval = bprm.argc) < 0)
+		goto out_mm;
+
+	bprm.envc = count(envp, bprm.p / sizeof(void *));
+	if ((retval = bprm.envc) < 0)
+		goto out_mm;
 
 	retval = prepare_binprm(&bprm);
 	if (retval < 0) 
@@ -938,16 +927,20 @@
 
 out:
 	/* Something went wrong, return the inode and free the argument pages*/
-	allow_write_access(bprm.file);
-	if (bprm.file)
-		fput(bprm.file);
-
 	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
 		struct page * page = bprm.page[i];
 		if (page)
 			__free_page(page);
 	}
 
+out_mm:
+	mmdrop(bprm.mm);
+
+out_file:
+	if (bprm.file) {
+		allow_write_access(bprm.file);
+		fput(bprm.file);
+	}
 	return retval;
 }
 
diff -Nru a/fs/ext2/dir.c b/fs/ext2/dir.c
--- a/fs/ext2/dir.c	Wed May 29 11:43:01 2002
+++ b/fs/ext2/dir.c	Wed May 29 11:43:01 2002
@@ -68,7 +68,7 @@
 	int err = 0;
 	dir->i_version = ++event;
 	page->mapping->a_ops->commit_write(NULL, page, from, to);
-	if (IS_SYNC(dir))
+	if (IS_DIRSYNC(dir))
 		err = write_one_page(page, 1);
 	else
 		unlock_page(page);
diff -Nru a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
--- a/fs/ext2/ialloc.c	Wed May 29 11:43:03 2002
+++ b/fs/ext2/ialloc.c	Wed May 29 11:43:03 2002
@@ -429,6 +429,9 @@
 	ei->i_flags = EXT2_I(dir)->i_flags;
 	if (S_ISLNK(mode))
 		ei->i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL);
+	/* dirsync is only applied to directories */
+	if (!S_ISDIR(mode))
+		ei->i_flags &= ~EXT2_DIRSYNC_FL;
 	ei->i_faddr = 0;
 	ei->i_frag_no = 0;
 	ei->i_frag_size = 0;
@@ -443,6 +446,8 @@
 	ei->i_dir_start_lookup = 0;
 	if (ei->i_flags & EXT2_SYNC_FL)
 		inode->i_flags |= S_SYNC;
+	if (ei->i_flags & EXT2_DIRSYNC_FL)
+		inode->i_flags |= S_DIRSYNC;
 	inode->i_generation = EXT2_SB(sb)->s_next_generation++;
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c
--- a/fs/ext2/inode.c	Wed May 29 11:43:01 2002
+++ b/fs/ext2/inode.c	Wed May 29 11:43:01 2002
@@ -30,6 +30,7 @@
 #include <linux/quotaops.h>
 #include <linux/module.h>
 #include <linux/buffer_head.h>
+#include <linux/mpage.h>
 
 MODULE_AUTHOR("Remy Card and others");
 MODULE_DESCRIPTION("Second Extended Filesystem");
@@ -57,7 +58,7 @@
 		goto no_delete;
 	EXT2_I(inode)->i_dtime	= CURRENT_TIME;
 	mark_inode_dirty(inode);
-	ext2_update_inode(inode, IS_SYNC(inode));
+	ext2_update_inode(inode, inode_needs_sync(inode));
 
 	inode->i_size = 0;
 	if (inode->i_blocks)
@@ -148,7 +149,8 @@
  *	@inode: inode in question (we are only interested in its superblock)
  *	@i_block: block number to be parsed
  *	@offsets: array to store the offsets in
- *
+ *      @boundary: set this non-zero if the referred-to block is likely to be
+ *             followed (on disk) by an indirect block.
  *	To store the locations of file's data ext2 uses a data structure common
  *	for UNIX filesystems - tree of pointers anchored in the inode, with
  *	data blocks at leaves and indirect blocks in intermediate nodes.
@@ -172,7 +174,8 @@
  * get there at all.
  */
 
-static int ext2_block_to_path(struct inode *inode, long i_block, int offsets[4])
+static int ext2_block_to_path(struct inode *inode,
+			long i_block, int offsets[4], int *boundary)
 {
 	int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
 	int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
@@ -180,26 +183,33 @@
 		indirect_blocks = ptrs,
 		double_blocks = (1 << (ptrs_bits * 2));
 	int n = 0;
+	int final = 0;
 
 	if (i_block < 0) {
 		ext2_warning (inode->i_sb, "ext2_block_to_path", "block < 0");
 	} else if (i_block < direct_blocks) {
 		offsets[n++] = i_block;
+		final = direct_blocks;
 	} else if ( (i_block -= direct_blocks) < indirect_blocks) {
 		offsets[n++] = EXT2_IND_BLOCK;
 		offsets[n++] = i_block;
+		final = ptrs;
 	} else if ((i_block -= indirect_blocks) < double_blocks) {
 		offsets[n++] = EXT2_DIND_BLOCK;
 		offsets[n++] = i_block >> ptrs_bits;
 		offsets[n++] = i_block & (ptrs - 1);
+		final = ptrs;
 	} else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) {
 		offsets[n++] = EXT2_TIND_BLOCK;
 		offsets[n++] = i_block >> (ptrs_bits * 2);
 		offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1);
 		offsets[n++] = i_block & (ptrs - 1);
+		final = ptrs;
 	} else {
 		ext2_warning (inode->i_sb, "ext2_block_to_path", "block > big");
 	}
+	if (boundary)
+		*boundary = (i_block & (ptrs - 1)) == (final - 1);
 	return n;
 }
 
@@ -506,7 +516,8 @@
 	Indirect *partial;
 	unsigned long goal;
 	int left;
-	int depth = ext2_block_to_path(inode, iblock, offsets);
+	int boundary = 0;
+	int depth = ext2_block_to_path(inode, iblock, offsets, &boundary);
 
 	if (depth == 0)
 		goto out;
@@ -518,6 +529,8 @@
 	if (!partial) {
 got_it:
 		map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
+		if (boundary)
+			set_buffer_boundary(bh_result);
 		/* Clean up and exit */
 		partial = chain+depth-1; /* the whole chain */
 		goto cleanup;
@@ -569,46 +582,63 @@
 {
 	return block_write_full_page(page,ext2_get_block);
 }
+
 static int ext2_readpage(struct file *file, struct page *page)
 {
-	return block_read_full_page(page,ext2_get_block);
+	return mpage_readpage(page, ext2_get_block);
+}
+
+static int
+ext2_readpages(struct address_space *mapping,
+		struct list_head *pages, unsigned nr_pages)
+{
+	return mpage_readpages(mapping, pages, nr_pages, ext2_get_block);
 }
-static int ext2_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+
+static int
+ext2_prepare_write(struct file *file, struct page *page,
+			unsigned from, unsigned to)
 {
 	return block_prepare_write(page,from,to,ext2_get_block);
 }
+
 static int ext2_bmap(struct address_space *mapping, long block)
 {
 	return generic_block_bmap(mapping,block,ext2_get_block);
 }
-static int ext2_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsigned long blocknr, int blocksize)
+
+static int
+ext2_direct_IO(int rw, struct inode *inode, struct kiobuf *iobuf,
+			unsigned long blocknr, int blocksize)
 {
-	return generic_direct_IO(rw, inode, iobuf, blocknr, blocksize, ext2_get_block);
+	return generic_direct_IO(rw, inode, iobuf, blocknr,
+				blocksize, ext2_get_block);
 }
 
 static int
-ext2_writeback_mapping(struct address_space *mapping, int *nr_to_write)
+ext2_writepages(struct address_space *mapping, int *nr_to_write)
 {
 	int ret;
 	int err;
 
 	ret = write_mapping_buffers(mapping);
-	err = generic_writeback_mapping(mapping, nr_to_write);
+	err = mpage_writepages(mapping, nr_to_write, ext2_get_block);
 	if (!ret)
 		ret = err;
 	return ret;
 }
 
 struct address_space_operations ext2_aops = {
-	readpage: ext2_readpage,
-	writepage: ext2_writepage,
-	sync_page: block_sync_page,
-	prepare_write: ext2_prepare_write,
-	commit_write: generic_commit_write,
-	bmap: ext2_bmap,
-	direct_IO: ext2_direct_IO,
-	writeback_mapping: ext2_writeback_mapping,
-	vm_writeback: generic_vm_writeback,
+	readpage:		ext2_readpage,
+	readpages:		ext2_readpages,
+	writepage:		ext2_writepage,
+	sync_page:		block_sync_page,
+	prepare_write:		ext2_prepare_write,
+	commit_write:		generic_commit_write,
+	bmap:			ext2_bmap,
+	direct_IO:		ext2_direct_IO,
+	writepages:		ext2_writepages,
+	vm_writeback:		generic_vm_writeback,
 };
 
 /*
@@ -818,7 +848,7 @@
 
 	block_truncate_page(inode->i_mapping, inode->i_size, ext2_get_block);
 
-	n = ext2_block_to_path(inode, iblock, offsets);
+	n = ext2_block_to_path(inode, iblock, offsets, NULL);
 	if (n == 0)
 		return;
 
@@ -875,7 +905,7 @@
 			;
 	}
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	if (IS_SYNC(inode)) {
+	if (inode_needs_sync(inode)) {
 		sync_mapping_buffers(inode->i_mapping);
 		ext2_sync_inode (inode);
 	} else {
@@ -1009,23 +1039,14 @@
 		init_special_inode(inode, inode->i_mode,
 				   le32_to_cpu(raw_inode->i_block[0]));
 	brelse (bh);
-	inode->i_attr_flags = 0;
-	if (ei->i_flags & EXT2_SYNC_FL) {
-		inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS;
+	if (ei->i_flags & EXT2_SYNC_FL)
 		inode->i_flags |= S_SYNC;
-	}
-	if (ei->i_flags & EXT2_APPEND_FL) {
-		inode->i_attr_flags |= ATTR_FLAG_APPEND;
+	if (ei->i_flags & EXT2_APPEND_FL)
 		inode->i_flags |= S_APPEND;
-	}
-	if (ei->i_flags & EXT2_IMMUTABLE_FL) {
-		inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;
+	if (ei->i_flags & EXT2_IMMUTABLE_FL)
 		inode->i_flags |= S_IMMUTABLE;
-	}
-	if (ei->i_flags & EXT2_NOATIME_FL) {
-		inode->i_attr_flags |= ATTR_FLAG_NOATIME;
+	if (ei->i_flags & EXT2_NOATIME_FL)
 		inode->i_flags |= S_NOATIME;
-	}
 	return;
 	
 bad_inode:
diff -Nru a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
--- a/fs/ext2/ioctl.c	Wed May 29 11:43:03 2002
+++ b/fs/ext2/ioctl.c	Wed May 29 11:43:03 2002
@@ -36,6 +36,9 @@
 		if (get_user(flags, (int *) arg))
 			return -EFAULT;
 
+		if (!S_ISDIR(inode->i_mode))
+			flags &= ~EXT2_DIRSYNC_FL;
+
 		oldflags = ei->i_flags;
 
 		/*
diff -Nru a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
--- a/fs/ext3/ialloc.c	Wed May 29 11:43:03 2002
+++ b/fs/ext3/ialloc.c	Wed May 29 11:43:03 2002
@@ -490,6 +490,9 @@
 	ei->i_flags = EXT3_I(dir)->i_flags & ~EXT3_INDEX_FL;
 	if (S_ISLNK(mode))
 		ei->i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL);
+	/* dirsync only applies to directories */
+	if (!S_ISDIR(mode))
+		ei->i_flags &= ~EXT3_DIRSYNC_FL;
 #ifdef EXT3_FRAGMENTS
 	ei->i_faddr = 0;
 	ei->i_frag_no = 0;
@@ -506,7 +509,9 @@
 	
 	if (ei->i_flags & EXT3_SYNC_FL)
 		inode->i_flags |= S_SYNC;
-	if (IS_SYNC(inode))
+	if (ei->i_flags & EXT3_DIRSYNC_FL)
+		inode->i_flags |= S_DIRSYNC;
+	if (IS_DIRSYNC(inode))
 		handle->h_sync = 1;
 	insert_inode_hash(inode);
 	inode->i_generation = sb->u.ext3_sb.s_next_generation++;
diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c
--- a/fs/ext3/inode.c	Wed May 29 11:43:03 2002
+++ b/fs/ext3/inode.c	Wed May 29 11:43:03 2002
@@ -33,6 +33,7 @@
 #include <linux/quotaops.h>
 #include <linux/string.h>
 #include <linux/buffer_head.h>
+#include <linux/mpage.h>
 
 /*
  * SEARCH_FROM_ZERO forces each block allocation to search from the start
@@ -1327,16 +1328,28 @@
 out_fail:
 	
 	unlock_kernel();
-	set_page_dirty(page);
+
+	/*
+	 * We have to fail this writepage to avoid cross-fs transactions.
+	 * Put the page back on mapping->dirty_pages, but leave its buffer's
+	 * dirty state as-is.
+	 */
+	__set_page_dirty_nobuffers(page);
 	unlock_page(page);
 	return ret;
 }
 
 static int ext3_readpage(struct file *file, struct page *page)
 {
-	return block_read_full_page(page,ext3_get_block);
+	return mpage_readpage(page, ext3_get_block);
 }
 
+static int
+ext3_readpages(struct address_space *mapping,
+		struct list_head *pages, unsigned nr_pages)
+{
+	return mpage_readpages(mapping, pages, nr_pages, ext3_get_block);
+}
 
 static int ext3_flushpage(struct page *page, unsigned long offset)
 {
@@ -1353,6 +1366,7 @@
 
 struct address_space_operations ext3_aops = {
 	readpage:	ext3_readpage,		/* BKL not held.  Don't need */
+	readpages:	ext3_readpages,		/* BKL not held.  Don't need */
 	writepage:	ext3_writepage,		/* BKL not held.  We take it */
 	sync_page:	block_sync_page,
 	prepare_write:	ext3_prepare_write,	/* BKL not held.  We take it */
@@ -1408,11 +1422,8 @@
 
 	err = 0;
 	if (!buffer_mapped(bh)) {
-		/* Hole? Nothing to do */
-		if (buffer_uptodate(bh))
-			goto unlock;
 		ext3_get_block(inode, iblock, bh, 0);
-		/* Still unmapped? Nothing to do */
+		/* unmapped? It's a hole - nothing to do */
 		if (!buffer_mapped(bh))
 			goto unlock;
 	}
@@ -2149,23 +2160,14 @@
 	} else 
 		init_special_inode(inode, inode->i_mode,
 				   le32_to_cpu(iloc.raw_inode->i_block[0]));
-	/* inode->i_attr_flags = 0;				unused */
-	if (ei->i_flags & EXT3_SYNC_FL) {
-		/* inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS; unused */
+	if (ei->i_flags & EXT3_SYNC_FL)
 		inode->i_flags |= S_SYNC;
-	}
-	if (ei->i_flags & EXT3_APPEND_FL) {
-		/* inode->i_attr_flags |= ATTR_FLAG_APPEND;	unused */
+	if (ei->i_flags & EXT3_APPEND_FL)
 		inode->i_flags |= S_APPEND;
-	}
-	if (ei->i_flags & EXT3_IMMUTABLE_FL) {
-		/* inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;	unused */
+	if (ei->i_flags & EXT3_IMMUTABLE_FL)
 		inode->i_flags |= S_IMMUTABLE;
-	}
-	if (ei->i_flags & EXT3_NOATIME_FL) {
-		/* inode->i_attr_flags |= ATTR_FLAG_NOATIME;	unused */
+	if (ei->i_flags & EXT3_NOATIME_FL)
 		inode->i_flags |= S_NOATIME;
-	}
 	return;
 	
 bad_inode:
@@ -2474,7 +2476,7 @@
 		/* ext3_do_update_inode() does journal_dirty_metadata */
 		brelse(iloc->bh);
 	} else {
-		printk(KERN_EMERG __FUNCTION__ ": called with no handle!\n");
+		printk(KERN_EMERG "%s: called with no handle!\n", __FUNCTION__);
 	}
 	return err;
 }
@@ -2562,7 +2564,8 @@
 	if (current_handle &&
 		current_handle->h_transaction != handle->h_transaction) {
 		/* This task has a transaction open against a different fs */
-		printk(KERN_EMERG __FUNCTION__": transactions do not match!\n");
+		printk(KERN_EMERG "%s: transactions do not match!\n",
+		       __FUNCTION__);
 	} else {
 		jbd_debug(5, "marking dirty.  outer handle=%p\n",
 				current_handle);
diff -Nru a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
--- a/fs/ext3/ioctl.c	Wed May 29 11:43:02 2002
+++ b/fs/ext3/ioctl.c	Wed May 29 11:43:02 2002
@@ -43,6 +43,9 @@
 		if (get_user(flags, (int *) arg))
 			return -EFAULT;
 
+		if (!S_ISDIR(inode->i_mode))
+			flags &= ~EXT3_DIRSYNC_FL;
+
 		oldflags = ei->i_flags;
 
 		/* The JOURNAL_DATA flag is modifiable only by root */
diff -Nru a/fs/ext3/namei.c b/fs/ext3/namei.c
--- a/fs/ext3/namei.c	Wed May 29 11:43:03 2002
+++ b/fs/ext3/namei.c	Wed May 29 11:43:03 2002
@@ -502,7 +502,7 @@
 		return PTR_ERR(handle);
 	}
 
-	if (IS_SYNC(dir))
+	if (IS_DIRSYNC(dir))
 		handle->h_sync = 1;
 
 	inode = ext3_new_inode (handle, dir, mode);
@@ -533,7 +533,7 @@
 		return PTR_ERR(handle);
 	}
 
-	if (IS_SYNC(dir))
+	if (IS_DIRSYNC(dir))
 		handle->h_sync = 1;
 
 	inode = ext3_new_inode (handle, dir, mode);
@@ -566,7 +566,7 @@
 		return PTR_ERR(handle);
 	}
 
-	if (IS_SYNC(dir))
+	if (IS_DIRSYNC(dir))
 		handle->h_sync = 1;
 
 	inode = ext3_new_inode (handle, dir, S_IFDIR);
@@ -860,7 +860,7 @@
 	if (!bh)
 		goto end_rmdir;
 
-	if (IS_SYNC(dir))
+	if (IS_DIRSYNC(dir))
 		handle->h_sync = 1;
 
 	inode = dentry->d_inode;
@@ -916,7 +916,7 @@
 		return PTR_ERR(handle);
 	}
 
-	if (IS_SYNC(dir))
+	if (IS_DIRSYNC(dir))
 		handle->h_sync = 1;
 
 	retval = -ENOENT;
@@ -975,7 +975,7 @@
 		return PTR_ERR(handle);
 	}
 
-	if (IS_SYNC(dir))
+	if (IS_DIRSYNC(dir))
 		handle->h_sync = 1;
 
 	inode = ext3_new_inode (handle, dir, S_IFLNK|S_IRWXUGO);
@@ -1033,7 +1033,7 @@
 		return PTR_ERR(handle);
 	}
 
-	if (IS_SYNC(dir))
+	if (IS_DIRSYNC(dir))
 		handle->h_sync = 1;
 
 	inode->i_ctime = CURRENT_TIME;
@@ -1073,7 +1073,7 @@
 		return PTR_ERR(handle);
 	}
 
-	if (IS_SYNC(old_dir) || IS_SYNC(new_dir))
+	if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
 		handle->h_sync = 1;
 
 	old_bh = ext3_find_entry (old_dentry, &old_de);
diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c
--- a/fs/ext3/super.c	Wed May 29 11:43:03 2002
+++ b/fs/ext3/super.c	Wed May 29 11:43:03 2002
@@ -892,17 +892,17 @@
 
 		list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan);
 		if (inode->i_nlink) {
-			printk(KERN_DEBUG __FUNCTION__
-				": truncating inode %ld to %Ld bytes\n",
-				inode->i_ino, inode->i_size);
+			printk(KERN_DEBUG
+				"%s: truncating inode %ld to %Ld bytes\n",
+				__FUNCTION__, inode->i_ino, inode->i_size);
 			jbd_debug(2, "truncating inode %ld to %Ld bytes\n",
 				  inode->i_ino, inode->i_size);
 			ext3_truncate(inode);
 			nr_truncates++;
 		} else {
-			printk(KERN_DEBUG __FUNCTION__
-				": deleting unreferenced inode %ld\n",
-				inode->i_ino);
+			printk(KERN_DEBUG
+				"%s: deleting unreferenced inode %ld\n",
+				__FUNCTION__, inode->i_ino);
 			jbd_debug(2, "deleting unreferenced inode %ld\n",
 				  inode->i_ino);
 			nr_orphans++;
diff -Nru a/fs/fat/inode.c b/fs/fat/inode.c
--- a/fs/fat/inode.c	Wed May 29 11:43:02 2002
+++ b/fs/fat/inode.c	Wed May 29 11:43:02 2002
@@ -872,7 +872,8 @@
 	if (!silent)
 		printk("FAT: Using codepage %s\n", sbi->nls_disk->charset);
 
-	if (sbi->options.isvfat && !sbi->options.utf8) {
+	/* FIXME: utf8 is using iocharset for upper/lower conversion */
+	if (sbi->options.isvfat) {
 		if (sbi->options.iocharset != NULL) {
 			sbi->nls_io = load_nls(sbi->options.iocharset);
 			if (!sbi->nls_io) {
diff -Nru a/fs/fs-writeback.c b/fs/fs-writeback.c
--- a/fs/fs-writeback.c	Wed May 29 11:43:03 2002
+++ b/fs/fs-writeback.c	Wed May 29 11:43:03 2002
@@ -114,13 +114,13 @@
  * from *nr_to_write.
  *
  * Normally it is not legal for a single process to lock more than one
- * page at a time, due to ab/ba deadlock problems.  But writeback_mapping()
+ * page at a time, due to ab/ba deadlock problems.  But writepages()
  * does want to lock a large number of pages, without immediately submitting
  * I/O against them (starting I/O is a "deferred unlock_page").
  *
  * However it *is* legal to lock multiple pages, if this is only ever performed
  * by a single process.  We provide that exclusion via locking in the
- * filesystem's ->writeback_mapping a_op. This ensures that only a single
+ * filesystem's ->writepages a_op. This ensures that only a single
  * process is locking multiple pages against this inode.  And as I/O is
  * submitted against all those locked pages, there is no deadlock.
  *
@@ -146,7 +146,7 @@
 	mapping->dirtied_when = 0;	/* assume it's whole-file writeback */
 	spin_unlock(&inode_lock);
 
-	writeback_mapping(mapping, nr_to_write);
+	do_writepages(mapping, nr_to_write);
 
 	/* Don't write the inode if only I_DIRTY_PAGES was set */
 	if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC))
@@ -257,7 +257,7 @@
 		if (current_is_pdflush())
 			writeback_release(bdi);
 
-		if (nr_to_write && *nr_to_write == 0)
+		if (nr_to_write && *nr_to_write <= 0)
 			break;
 	}
 out:
@@ -301,7 +301,7 @@
 					older_than_this);
 			spin_lock(&sb_lock);
 		}
-		if (nr_to_write && *nr_to_write == 0)
+		if (nr_to_write && *nr_to_write <= 0)
 			break;
 	}
 	spin_unlock(&sb_lock);
@@ -325,11 +325,21 @@
  * writeback and wait upon the filesystem's dirty inodes.  The caller will
  * do this in two passes - one to write, and one to wait.  WB_SYNC_HOLD is
  * used to park the written inodes on sb->s_dirty for the wait pass.
+ *
+ * A finite limit is set on the number of pages which will be written.
+ * To prevent infinite livelock of sys_sync().
  */
 void sync_inodes_sb(struct super_block *sb, int wait)
 {
+	struct page_state ps;
+	int nr_to_write;
+
+	get_page_state(&ps);
+	nr_to_write = ps.nr_dirty + ps.nr_dirty / 4;
+
 	spin_lock(&inode_lock);
-	sync_sb_inodes(sb, wait ? WB_SYNC_ALL : WB_SYNC_HOLD, NULL, NULL);
+	sync_sb_inodes(sb, wait ? WB_SYNC_ALL : WB_SYNC_HOLD,
+				&nr_to_write, NULL);
 	if (wait)
 		__wait_on_locked(&sb->s_locked_inodes);
 	spin_unlock(&inode_lock);
diff -Nru a/fs/inode.c b/fs/inode.c
--- a/fs/inode.c	Wed May 29 11:43:03 2002
+++ b/fs/inode.c	Wed May 29 11:43:03 2002
@@ -981,6 +981,15 @@
 	do_atime_update(inode);
 }   /*  End Function update_atime  */
 
+int inode_needs_sync(struct inode *inode)
+{
+	if (IS_SYNC(inode))
+		return 1;
+	if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode))
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(inode_needs_sync);
 
 /*
  *	Quota functions that want to walk the inode lists..
diff -Nru a/fs/iobuf.c b/fs/iobuf.c
--- a/fs/iobuf.c	Wed May 29 11:43:03 2002
+++ b/fs/iobuf.c	Wed May 29 11:43:03 2002
@@ -112,7 +112,7 @@
 repeat:
 	set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 	if (atomic_read(&kiobuf->io_count) != 0) {
-		run_task_queue(&tq_disk);
+		blk_run_queues();
 		schedule();
 		if (atomic_read(&kiobuf->io_count) != 0)
 			goto repeat;
diff -Nru a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c
--- a/fs/jbd/checkpoint.c	Wed May 29 11:43:02 2002
+++ b/fs/jbd/checkpoint.c	Wed May 29 11:43:02 2002
@@ -179,7 +179,7 @@
 
 	spin_unlock(&journal_datalist_lock);
 	ll_rw_block(WRITE, *batch_count, bhs);
-	run_task_queue(&tq_disk);
+	blk_run_queues();
 	spin_lock(&journal_datalist_lock);
 	for (i = 0; i < *batch_count; i++) {
 		struct buffer_head *bh = bhs[i];
diff -Nru a/fs/jbd/journal.c b/fs/jbd/journal.c
--- a/fs/jbd/journal.c	Wed May 29 11:43:02 2002
+++ b/fs/jbd/journal.c	Wed May 29 11:43:02 2002
@@ -226,7 +226,6 @@
 			journal->j_commit_interval / HZ);
 	list_add(&journal->j_all_journals, &all_journals);
 
-	current->flags |= PF_KERNTHREAD;
 	/* And now, wait forever for commit wakeup events. */
 	while (1) {
 		if (journal->j_flags & JFS_UNMOUNT)
@@ -466,9 +465,8 @@
 	do {
 		new_bh = alloc_buffer_head(0);
 		if (!new_bh) {
-			printk (KERN_NOTICE __FUNCTION__
-				": ENOMEM at alloc_buffer_head, "
-				"trying again.\n");
+			printk (KERN_NOTICE "%s: ENOMEM at alloc_buffer_head, "
+				"trying again.\n", __FUNCTION__);
 			yield();
 		}
 	} while (!new_bh);
@@ -593,9 +591,9 @@
 #ifdef CONFIG_JBD_DEBUG
 	lock_journal(journal);
 	if (!tid_geq(journal->j_commit_request, tid)) {
-		printk(KERN_EMERG __FUNCTION__
-			": error: j_commit_request=%d, tid=%d\n",
-			journal->j_commit_request, tid);
+		printk(KERN_EMERG
+		       "%s: error: j_commit_request=%d, tid=%d\n",
+		       __FUNCTION__, journal->j_commit_request, tid);
 	}
 	unlock_journal(journal);
 #endif
@@ -644,9 +642,9 @@
 		if (ret)
 			*retp = ret;
 		else {
-			printk (KERN_ALERT __FUNCTION__ 
-				": journal block not found "
-				"at offset %lu on %s\n",
+			printk(KERN_ALERT "%s: journal block not found "
+					"at offset %lu on %s\n",
+				__FUNCTION__,
 				blocknr,
 				bdevname(journal->j_dev));
 			err = -EIO;
@@ -792,8 +790,8 @@
 	err = journal_bmap(journal, 0, &blocknr);
 	/* If that failed, give up */
 	if (err) {
-		printk(KERN_ERR __FUNCTION__ ": Cannnot locate journal "
-		       "superblock\n");
+		printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
+		       __FUNCTION__);
 		kfree(journal);
 		return NULL;
 	}
@@ -879,8 +877,9 @@
 		/*
 		 * We don't know what block to start at!
 		 */
-		printk(KERN_EMERG __FUNCTION__
-			": creation of journal on external device!\n");
+		printk(KERN_EMERG
+		       "%s: creation of journal on external device!\n",
+		       __FUNCTION__);
 		BUG();
 	}
 
@@ -1601,8 +1600,8 @@
 	if (ret == 0) {
 		jbd_debug(1, "out of memory for journal_head\n");
 		if (time_after(jiffies, last_warning + 5*HZ)) {
-			printk(KERN_NOTICE "ENOMEM in " __FUNCTION__
-			       ", retrying.\n");
+			printk(KERN_NOTICE "ENOMEM in %s, retrying.\n",
+			       __FUNCTION__);
 			last_warning = jiffies;
 		}
 		while (ret == 0) {
diff -Nru a/fs/jbd/transaction.c b/fs/jbd/transaction.c
--- a/fs/jbd/transaction.c	Wed May 29 11:43:02 2002
+++ b/fs/jbd/transaction.c	Wed May 29 11:43:02 2002
@@ -709,8 +709,9 @@
 							    GFP_NOFS);
 				lock_journal(journal);
 				if (!frozen_buffer) {
-					printk(KERN_EMERG __FUNCTION__
-						"OOM for frozen_buffer\n");
+					printk(KERN_EMERG
+					       "%s: OOM for frozen_buffer\n",
+					       __FUNCTION__);
 					JBUFFER_TRACE(jh, "oom!");
 					error = -ENOMEM;
 					spin_lock(&journal_datalist_lock);
@@ -906,8 +907,9 @@
 		jh->b_committed_data = jbd_kmalloc(jh2bh(jh)->b_size, 
 						   GFP_NOFS);
 		if (!jh->b_committed_data) {
-			printk(KERN_EMERG __FUNCTION__
-				": No memory for committed data!\n");
+			printk(KERN_EMERG
+			       "%s: No memory for committed data!\n",
+			       __FUNCTION__);
 			err = -ENOMEM;
 			goto out;
 		}
diff -Nru a/fs/mpage.c b/fs/mpage.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/mpage.c	Wed May 29 11:43:03 2002
@@ -0,0 +1,547 @@
+/*
+ * fs/mpage.c
+ *
+ * Copyright (C) 2002, Linus Torvalds.
+ *
+ * Contains functions related to preparing and submitting BIOs which contain
+ * multiple pagecache pages.
+ *
+ * 15May2002	akpm@zip.com.au
+ *		Initial version
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bio.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/blkdev.h>
+#include <linux/highmem.h>
+#include <linux/prefetch.h>
+#include <linux/mpage.h>
+
+/*
+ * The largest-sized BIO which this code will assemble, in bytes.  Set this
+ * to PAGE_CACHE_SIZE if your drivers are broken.
+ */
+#define MPAGE_BIO_MAX_SIZE BIO_MAX_SIZE
+
+/*
+ * I/O completion handler for multipage BIOs.
+ *
+ * The mpage code never puts partial pages into a BIO (except for end-of-file).
+ * If a page does not map to a contiguous run of blocks then it simply falls
+ * back to block_read_full_page().
+ *
+ * Why is this?  If a page's completion depends on a number of different BIOs
+ * which can complete in any order (or at the same time) then determining the
+ * status of that page is hard.  See end_buffer_async_read() for the details.
+ * There is no point in duplicating all that complexity.
+ */
+static void mpage_end_io_read(struct bio *bio)
+{
+	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+	struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+
+	do {
+		struct page *page = bvec->bv_page;
+
+		if (--bvec >= bio->bi_io_vec)
+			prefetchw(&bvec->bv_page->flags);
+
+		if (uptodate) {
+			SetPageUptodate(page);
+		} else {
+			ClearPageUptodate(page);
+			SetPageError(page);
+		}
+		unlock_page(page);
+	} while (bvec >= bio->bi_io_vec);
+	bio_put(bio);
+}
+
+static void mpage_end_io_write(struct bio *bio)
+{
+	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+	struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+
+	do {
+		struct page *page = bvec->bv_page;
+
+		if (--bvec >= bio->bi_io_vec)
+			prefetchw(&bvec->bv_page->flags);
+
+		if (!uptodate)
+			SetPageError(page);
+		end_page_writeback(page);
+	} while (bvec >= bio->bi_io_vec);
+	bio_put(bio);
+}
+
+struct bio *mpage_bio_submit(int rw, struct bio *bio)
+{
+	bio->bi_vcnt = bio->bi_idx;
+	bio->bi_idx = 0;
+	bio->bi_end_io = mpage_end_io_read;
+	if (rw == WRITE)
+		bio->bi_end_io = mpage_end_io_write;
+	submit_bio(rw, bio);
+	return NULL;
+}
+
+static struct bio *
+mpage_alloc(struct block_device *bdev,
+		sector_t first_sector, int nr_vecs, int gfp_flags)
+{
+	struct bio *bio;
+
+	bio = bio_alloc(gfp_flags, nr_vecs);
+	if (bio) {
+		bio->bi_bdev = bdev;
+		bio->bi_vcnt = nr_vecs;
+		bio->bi_idx = 0;
+		bio->bi_size = 0;
+		bio->bi_sector = first_sector;
+		bio->bi_io_vec[0].bv_page = NULL;
+	}
+	return bio;
+}
+
+/**
+ * mpage_readpages - populate an address space with some pages, and
+ *                       start reads against them.
+ *
+ * @mapping: the address_space
+ * @pages: The address of a list_head which contains the target pages.  These
+ *   pages have their ->index populated and are otherwise uninitialised.
+ *
+ *   The page at @pages->prev has the lowest file offset, and reads should be
+ *   issued in @pages->prev to @pages->next order.
+ *
+ * @nr_pages: The number of pages at *@pages
+ * @get_block: The filesystem's block mapper function.
+ *
+ * This function walks the pages and the blocks within each page, building and
+ * emitting large BIOs.
+ *
+ * If anything unusual happens, such as:
+ *
+ * - encountering a page which has buffers
+ * - encountering a page which has a non-hole after a hole
+ * - encountering a page with non-contiguous blocks
+ *
+ * then this code just gives up and calls the buffer_head-based read function.
+ * It does handle a page which has holes at the end - that is a common case:
+ * the end-of-file on blocksize < PAGE_CACHE_SIZE setups.
+ *
+ * BH_Boundary explanation:
+ *
+ * There is a problem.  The mpage read code assembles several pages, gets all
+ * their disk mappings, and then submits them all.  That's fine, but obtaining
+ * the disk mappings may require I/O.  Reads of indirect blocks, for example.
+ *
+ * So an mpage read of the first 16 blocks of an ext2 file will cause I/O to be
+ * submitted in the following order:
+ * 	12 0 1 2 3 4 5 6 7 8 9 10 11 13 14 15 16
+ * because the indirect block has to be read to get the mappings of blocks
+ * 13,14,15,16.  Obviously, this impacts performance.
+ * 
+ * So what we do it to allow the filesystem's get_block() function to set
+ * BH_Boundary when it maps block 11.  BH_Boundary says: mapping of the block
+ * after this one will require I/O against a block which is probably close to
+ * this one.  So you should push what I/O you have currently accumulated.
+ *
+ * This all causes the disk requests to be issued in the correct order.
+ */
+static struct bio *
+do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,
+			sector_t *last_block_in_bio, get_block_t get_block)
+{
+	struct inode *inode = page->mapping->host;
+	const unsigned blkbits = inode->i_blkbits;
+	const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits;
+	const unsigned blocksize = 1 << blkbits;
+	struct bio_vec *bvec;
+	sector_t block_in_file;
+	sector_t last_block;
+	sector_t blocks[MAX_BUF_PER_PAGE];
+	unsigned page_block;
+	unsigned first_hole = blocks_per_page;
+	struct block_device *bdev = NULL;
+	struct buffer_head bh;
+
+	if (page_has_buffers(page))
+		goto confused;
+
+	block_in_file = page->index << (PAGE_CACHE_SHIFT - blkbits);
+	last_block = (inode->i_size + blocksize - 1) >> blkbits;
+
+	for (page_block = 0; page_block < blocks_per_page;
+				page_block++, block_in_file++) {
+		bh.b_state = 0;
+		if (block_in_file < last_block) {
+			if (get_block(inode, block_in_file, &bh, 0))
+				goto confused;
+		}
+
+		if (!buffer_mapped(&bh)) {
+			if (first_hole == blocks_per_page)
+				first_hole = page_block;
+			continue;
+		}
+	
+		if (first_hole != blocks_per_page)
+			goto confused;		/* hole -> non-hole */
+
+		/* Contiguous blocks? */
+		if (page_block && blocks[page_block-1] != bh.b_blocknr-1)
+			goto confused;
+		blocks[page_block] = bh.b_blocknr;
+		bdev = bh.b_bdev;
+	}
+
+	if (first_hole != blocks_per_page) {
+		memset(kmap(page) + (first_hole << blkbits), 0,
+				PAGE_CACHE_SIZE - (first_hole << blkbits));
+		flush_dcache_page(page);
+		kunmap(page);
+		if (first_hole == 0) {
+			SetPageUptodate(page);
+			unlock_page(page);
+			goto out;
+		}
+	}
+
+	/*
+	 * This page will go to BIO.  Do we need to send this BIO off first?
+	 */
+	if (bio && (bio->bi_idx == bio->bi_vcnt ||
+			*last_block_in_bio != blocks[0] - 1))
+		bio = mpage_bio_submit(READ, bio);
+
+	if (bio == NULL) {
+		unsigned nr_bvecs = MPAGE_BIO_MAX_SIZE / PAGE_CACHE_SIZE;
+
+		if (nr_bvecs > nr_pages)
+			nr_bvecs = nr_pages;
+		bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9),
+					nr_bvecs, GFP_KERNEL);
+		if (bio == NULL)
+			goto confused;
+	}
+
+	bvec = &bio->bi_io_vec[bio->bi_idx++];
+	bvec->bv_page = page;
+	bvec->bv_len = (first_hole << blkbits);
+	bvec->bv_offset = 0;
+	bio->bi_size += bvec->bv_len;
+	if (buffer_boundary(&bh) || (first_hole != blocks_per_page))
+		bio = mpage_bio_submit(READ, bio);
+	else
+		*last_block_in_bio = blocks[blocks_per_page - 1];
+out:
+	return bio;
+
+confused:
+	if (bio)
+		bio = mpage_bio_submit(READ, bio);
+	block_read_full_page(page, get_block);
+	goto out;
+}
+
+int
+mpage_readpages(struct address_space *mapping, struct list_head *pages,
+				unsigned nr_pages, get_block_t get_block)
+{
+	struct bio *bio = NULL;
+	unsigned page_idx;
+	sector_t last_block_in_bio = 0;
+
+	for (page_idx = 0; page_idx < nr_pages; page_idx++) {
+		struct page *page = list_entry(pages->prev, struct page, list);
+
+		prefetchw(&page->flags);
+		list_del(&page->list);
+		if (!add_to_page_cache_unique(page, mapping, page->index))
+			bio = do_mpage_readpage(bio, page,
+					nr_pages - page_idx,
+					&last_block_in_bio, get_block);
+		page_cache_release(page);
+	}
+	BUG_ON(!list_empty(pages));
+	if (bio)
+		mpage_bio_submit(READ, bio);
+	return 0;
+}
+EXPORT_SYMBOL(mpage_readpages);
+
+/*
+ * This isn't called much at all
+ */
+int mpage_readpage(struct page *page, get_block_t get_block)
+{
+	struct bio *bio = NULL;
+	sector_t last_block_in_bio = 0;
+
+	bio = do_mpage_readpage(bio, page, 1,
+			&last_block_in_bio, get_block);
+	if (bio)
+		mpage_bio_submit(READ, bio);
+	return 0;
+}
+EXPORT_SYMBOL(mpage_readpage);
+
+/*
+ * Writing is not so simple.
+ *
+ * If the page has buffers then they will be used for obtaining the disk
+ * mapping.  We only support pages which are fully mapped-and-dirty, with a
+ * special case for pages which are unmapped at the end: end-of-file.
+ *
+ * If the page has no buffers (preferred) then the page is mapped here.
+ *
+ * If all blocks are found to be contiguous then the page can go into the
+ * BIO.  Otherwise fall back to block_write_full_page().
+ * 
+ * FIXME: This code wants an estimate of how many pages are still to be
+ * written, so it can intelligently allocate a suitably-sized BIO.  For now,
+ * just allocate full-size (16-page) BIOs.
+ */
+static /* inline */ struct bio *
+mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
+			sector_t *last_block_in_bio, int *ret)
+{
+	struct inode *inode = page->mapping->host;
+	const unsigned blkbits = inode->i_blkbits;
+	unsigned long end_index;
+	const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits;
+	struct bio_vec *bvec;
+	sector_t last_block;
+	sector_t block_in_file;
+	sector_t blocks[MAX_BUF_PER_PAGE];
+	unsigned page_block;
+	unsigned first_unmapped = blocks_per_page;
+	struct block_device *bdev = NULL;
+	int boundary = 0;
+
+	if (page_has_buffers(page)) {
+		struct buffer_head *head = page_buffers(page);
+		struct buffer_head *bh = head;
+
+		/* If they're all mapped and dirty, do it */
+		page_block = 0;
+		do {
+			BUG_ON(buffer_locked(bh));
+			if (!buffer_mapped(bh)) {
+				/*
+				 * unmapped dirty buffers are created by
+				 * __set_page_dirty_buffers -> mmapped data
+				 */
+				if (buffer_dirty(bh))
+					goto confused;
+				if (first_unmapped == blocks_per_page)
+					first_unmapped = page_block;
+				continue;
+			}
+
+			if (first_unmapped != blocks_per_page)
+				goto confused;	/* hole -> non-hole */
+
+			if (!buffer_dirty(bh) || !buffer_uptodate(bh))
+				goto confused;
+			if (page_block) {
+				if (bh->b_blocknr != blocks[page_block-1] + 1)
+					goto confused;
+			}
+			blocks[page_block++] = bh->b_blocknr;
+			boundary = buffer_boundary(bh);
+			bdev = bh->b_bdev;
+		} while ((bh = bh->b_this_page) != head);
+
+		if (first_unmapped)
+			goto page_is_mapped;
+
+		/*
+		 * Page has buffers, but they are all unmapped. The page was
+		 * created by pagein or read over a hole which was handled by
+		 * block_read_full_page().  If this address_space is also
+		 * using mpage_readpages then this can rarely happen.
+		 */
+		goto confused;
+	}
+
+	/*
+	 * The page has no buffers: map it to disk
+	 */
+	BUG_ON(!PageUptodate(page));
+	block_in_file = page->index << (PAGE_CACHE_SHIFT - blkbits);
+	last_block = (inode->i_size - 1) >> blkbits;
+	for (page_block = 0; page_block < blocks_per_page; ) {
+		struct buffer_head map_bh;
+
+		map_bh.b_state = 0;
+		if (get_block(inode, block_in_file, &map_bh, 1))
+			goto confused;
+		if (buffer_new(&map_bh))
+			unmap_underlying_metadata(map_bh.b_bdev,
+						map_bh.b_blocknr);
+		if (page_block) {
+			if (map_bh.b_blocknr != blocks[page_block-1] + 1)
+				goto confused;
+		}
+		blocks[page_block++] = map_bh.b_blocknr;
+		boundary = buffer_boundary(&map_bh);
+		bdev = map_bh.b_bdev;
+		if (block_in_file == last_block)
+			break;
+		block_in_file++;
+	}
+	if (page_block == 0)
+		buffer_error();
+
+	first_unmapped = page_block;
+
+	end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+	if (page->index >= end_index) {
+		unsigned offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
+
+		if (page->index > end_index || !offset)
+			goto confused;
+		memset(kmap(page) + offset, 0, PAGE_CACHE_SIZE - offset);
+		flush_dcache_page(page);
+		kunmap(page);
+	}
+
+page_is_mapped:
+
+	/*
+	 * This page will go to BIO.  Do we need to send this BIO off first?
+	 */
+	if (bio && (bio->bi_idx == bio->bi_vcnt ||
+				*last_block_in_bio != blocks[0] - 1))
+		bio = mpage_bio_submit(WRITE, bio);
+
+	if (bio == NULL) {
+		unsigned nr_bvecs = MPAGE_BIO_MAX_SIZE / PAGE_CACHE_SIZE;
+
+		bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9),
+					nr_bvecs, GFP_NOFS);
+		if (bio == NULL)
+			goto confused;
+	}
+
+	/*
+	 * OK, we have our BIO, so we can now mark the buffers clean.  Make
+	 * sure to only clean buffers which we know we'll be writing.
+	 */
+	if (page_has_buffers(page)) {
+		struct buffer_head *head = page_buffers(page);
+		struct buffer_head *bh = head;
+		unsigned buffer_counter = 0;
+
+		do {
+			if (buffer_counter++ == first_unmapped)
+				break;
+			clear_buffer_dirty(bh);
+			bh = bh->b_this_page;
+		} while (bh != head);
+	}
+
+	bvec = &bio->bi_io_vec[bio->bi_idx++];
+	bvec->bv_page = page;
+	bvec->bv_len = (first_unmapped << blkbits);
+	bvec->bv_offset = 0;
+	bio->bi_size += bvec->bv_len;
+	BUG_ON(PageWriteback(page));
+	SetPageWriteback(page);
+	unlock_page(page);
+	if (boundary || (first_unmapped != blocks_per_page))
+		bio = mpage_bio_submit(WRITE, bio);
+	else
+		*last_block_in_bio = blocks[blocks_per_page - 1];
+	goto out;
+
+confused:
+	if (bio)
+		bio = mpage_bio_submit(WRITE, bio);
+	*ret = block_write_full_page(page, get_block);
+out:
+	return bio;
+}
+
+/*
+ * This is a cut-n-paste of generic_writepages().  We _could_
+ * generalise that function.  It'd get a bit messy.  We'll see.
+ */
+int
+mpage_writepages(struct address_space *mapping,
+			int *nr_to_write, get_block_t get_block)
+{
+	struct bio *bio = NULL;
+	sector_t last_block_in_bio = 0;
+	int ret = 0;
+	int done = 0;
+
+	write_lock(&mapping->page_lock);
+
+	list_splice(&mapping->dirty_pages, &mapping->io_pages);
+	INIT_LIST_HEAD(&mapping->dirty_pages);
+
+        while (!list_empty(&mapping->io_pages) && !done) {
+		struct page *page = list_entry(mapping->io_pages.prev,
+					struct page, list);
+		list_del(&page->list);
+		if (PageWriteback(page)) {
+			if (PageDirty(page)) {
+				list_add(&page->list, &mapping->dirty_pages);
+				continue;
+			}
+			list_add(&page->list, &mapping->locked_pages);
+			continue;
+		}
+		if (!PageDirty(page)) {
+			list_add(&page->list, &mapping->clean_pages);
+			continue;
+		}
+		list_add(&page->list, &mapping->locked_pages);
+
+		page_cache_get(page);
+		write_unlock(&mapping->page_lock);
+
+		lock_page(page);
+
+		if (page->mapping && TestClearPageDirty(page) &&
+					!PageWriteback(page)) {
+			/* FIXME: batch this up */
+			if (!PageActive(page) && PageLRU(page)) {
+				spin_lock(&pagemap_lru_lock);
+				if (!PageActive(page) && PageLRU(page)) {
+					list_del(&page->lru);
+					list_add(&page->lru, &inactive_list);
+				}
+				spin_unlock(&pagemap_lru_lock);
+			}
+			bio = mpage_writepage(bio, page, get_block,
+					&last_block_in_bio, &ret);
+			if (ret || (nr_to_write && --(*nr_to_write) <= 0))
+				done = 1;
+		} else {
+			unlock_page(page);
+		}
+
+		page_cache_release(page);
+		write_lock(&mapping->page_lock);
+	}
+	if (!list_empty(&mapping->io_pages)) {
+		/*
+		 * Put the rest back, in the correct order.
+		 */
+		list_splice(&mapping->io_pages, mapping->dirty_pages.prev);
+		INIT_LIST_HEAD(&mapping->io_pages);
+	}
+	write_unlock(&mapping->page_lock);
+	if (bio)
+		mpage_bio_submit(WRITE, bio);
+	return ret;
+}
+EXPORT_SYMBOL(mpage_writepages);
diff -Nru a/fs/msdos/namei.c b/fs/msdos/namei.c
--- a/fs/msdos/namei.c	Wed May 29 11:43:03 2002
+++ b/fs/msdos/namei.c	Wed May 29 11:43:03 2002
@@ -222,22 +222,17 @@
 	if (res)
 		goto out;
 add:
-	if (inode) {
-		dentry = d_splice_alias(inode, dentry);
-		dentry->d_op = &msdos_dentry_operations;
-	} else {
-		d_add(dentry, inode);
-		dentry = NULL;
-	}
 	res = 0;
+	dentry = d_splice_alias(inode, dentry);
+	if (dentry)
+		dentry->d_op = &msdos_dentry_operations;
 out:
 	if (bh)
 		fat_brelse(sb, bh);
 	unlock_kernel();
-	if (res)
-		return ERR_PTR(res);
-	else
+	if (!res)
 		return dentry;
+	return ERR_PTR(res);
 }
 
 /***** Creates a directory entry (name is already formatted). */
diff -Nru a/fs/namespace.c b/fs/namespace.c
--- a/fs/namespace.c	Wed May 29 11:43:03 2002
+++ b/fs/namespace.c	Wed May 29 11:43:03 2002
@@ -197,6 +197,7 @@
 		char *str;
 	} fs_info[] = {
 		{ MS_SYNCHRONOUS, ",sync" },
+		{ MS_DIRSYNC, ",dirsync" },
 		{ MS_MANDLOCK, ",mand" },
 		{ MS_NOATIME, ",noatime" },
 		{ MS_NODIRATIME, ",nodiratime" },
diff -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c
--- a/fs/nfs/dir.c	Wed May 29 11:43:03 2002
+++ b/fs/nfs/dir.c	Wed May 29 11:43:03 2002
@@ -100,13 +100,12 @@
 	struct file	*file = desc->file;
 	struct inode	*inode = file->f_dentry->d_inode;
 	struct rpc_cred	*cred = nfs_file_cred(file);
-	void		*buffer = kmap(page);
 	int		error;
 
 	dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
 
  again:
-	error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, buffer,
+	error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, page,
 					  NFS_SERVER(inode)->dtsize, desc->plus);
 	/* We requested READDIRPLUS, but the server doesn't grok it */
 	if (desc->plus && error == -ENOTSUPP) {
@@ -117,7 +116,6 @@
 	if (error < 0)
 		goto error;
 	SetPageUptodate(page);
-	kunmap(page);
 	/* Ensure consistent page alignment of the data.
 	 * Note: assumes we have exclusive access to this mapping either
 	 *	 throught inode->i_sem or some other mechanism.
@@ -316,12 +314,12 @@
 		status = -ENOMEM;
 		goto out;
 	}
-	desc->page = page;
-	desc->ptr = kmap(page);
 	desc->error = NFS_PROTO(inode)->readdir(inode, cred, desc->target,
-						desc->ptr,
+						page,
 						NFS_SERVER(inode)->dtsize,
 						desc->plus);
+	desc->page = page;
+	desc->ptr = kmap(page);
 	if (desc->error >= 0) {
 		if ((status = dir_decode(desc)) == 0)
 			desc->entry->prev_cookie = desc->target;
diff -Nru a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
--- a/fs/nfs/nfs2xdr.c	Wed May 29 11:43:02 2002
+++ b/fs/nfs/nfs2xdr.c	Wed May 29 11:43:02 2002
@@ -24,9 +24,6 @@
 #include <linux/nfs2.h>
 #include <linux/nfs_fs.h>
 
-/* Uncomment this to support servers requiring longword lengths */
-#define NFS_PAD_WRITES 1
-
 #define NFSDBG_FACILITY		NFSDBG_XDR
 /* #define NFS_PARANOIA 1 */
 
@@ -90,17 +87,6 @@
 	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
-static inline u32 *
-xdr_decode_string2(u32 *p, char **string, unsigned int *len,
-			unsigned int maxlen)
-{
-	*len = ntohl(*p++);
-	if (*len > maxlen)
-		return NULL;
-	*string = (char *) p;
-	return p + XDR_QUADLEN(*len);
-}
-
 static inline u32*
 xdr_decode_time(u32 *p, u64 *timep)
 {
@@ -109,7 +95,7 @@
 	return p;
 }
 
-static inline u32 *
+static u32 *
 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
 {
 	fattr->type = (enum nfs_ftype) ntohl(*p++);
@@ -223,35 +209,20 @@
 nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		buflen, replen;
-	unsigned int	nr;
+	unsigned int replen;
+	u32 offset = (u32)args->offset;
+	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->offset);
-	*p++ = htonl(args->count);
-	*p++ = htonl(args->count);
+	*p++ = htonl(offset);
+	*p++ = htonl(count);
+	*p++ = htonl(count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	/* Get the number of buffers in the receive iovec */
-        nr = args->nriov;
-
-        if (nr+2 > MAX_IOVEC) {
-                printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
-                return -EINVAL;
-        }
-
-	/* set up reply iovec */
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-        /* Copy the iovec */
-        memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
-
-	req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[nr+1].iov_len  = buflen - replen;
-	req->rq_rlen = args->count + buflen;
-	req->rq_rnr += nr+1;
-
+	xdr_inline_pages(&req->rq_rcv_buf, replen,
+			 args->pages, args->pgbase, count);
 	return 0;
 }
 
@@ -272,7 +243,7 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 	}
 
 	recvd = req->rq_rlen - hdrlen;
@@ -284,7 +255,6 @@
 
 	dprintk("RPC:      readres OK count %d\n", count);
 	if (count < res->count) {
-		xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
 		res->count = count;
 		res->eof = 1;  /* Silly NFSv3ism which can't be helped */
 	} else
@@ -300,46 +270,19 @@
 static int
 nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
 {
-	unsigned int nr;
+	struct xdr_buf *sndbuf = &req->rq_snd_buf;
+	u32 offset = (u32)args->offset;
 	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->offset);
-	*p++ = htonl(args->offset);
+	*p++ = htonl(offset);
+	*p++ = htonl(offset);
 	*p++ = htonl(count);
 	*p++ = htonl(count);
-	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
-
-	/* Get the number of buffers in the send iovec */
-	nr = args->nriov;
-
-	if (nr+2 > MAX_IOVEC) {
-                printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs "
-                        "(nr %d max %d)\n", nr, MAX_IOVEC);
-                return -EINVAL;
-        }
-
-	/* Copy the iovec */
-        memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
-
-#ifdef NFS_PAD_WRITES
-	/*
-	 * Some old servers require that the message length
-	 * be a multiple of 4, so we pad it here if needed.
-	 */
-	if (count & 3) {
-		struct iovec	*iov = req->rq_svec + nr + 1;
-		int		pad = 4 - (count & 3);
-
-		iov->iov_base = (void *) "\0\0\0";
-		iov->iov_len  = pad;
-		count += pad;
-		nr++;
-	}
-#endif
-	req->rq_slen += count;
-	req->rq_snr += nr;
+	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
 
+	/* Copy the page array */
+	xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
 	return 0;
 }
 
@@ -406,32 +349,24 @@
 {
 	struct rpc_task	*task = req->rq_task;
 	struct rpc_auth	*auth = task->tk_auth;
-	u32		bufsiz = args->bufsiz;
-	int		buflen, replen;
+	unsigned int replen;
+	u32 count = args->count;
 
 	/*
 	 * Some servers (e.g. HP OS 9.5) seem to expect the buffer size
 	 * to be in longwords ... check whether to convert the size.
 	 */
 	if (task->tk_client->cl_flags & NFS_CLNTF_BUFSIZE)
-		bufsiz = bufsiz >> 2;
+		count = count >> 2;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	*p++ = htonl(args->cookie);
-	*p++ = htonl(bufsiz); /* see above */
+	*p++ = htonl(count); /* see above */
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	/* set up reply iovec */
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
-	req->rq_rlen = buflen + args->bufsiz;
-	req->rq_rnr += 2;
-
+	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 	return 0;
 }
 
@@ -443,12 +378,15 @@
  * from nfs_readdir for each entry.
  */
 static int
-nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
+nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
 {
-	struct iovec		*iov = req->rq_rvec;
-	int			 hdrlen;
-	int			 status, nr;
-	u32			*end, *entry, len;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	struct iovec *iov = rcvbuf->head;
+	struct page **page;
+	int hdrlen;
+	int status, nr;
+	unsigned int len, pglen;
+	u32 *end, *entry;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
@@ -456,13 +394,13 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
-
-	/* Get start and end address of XDR data */
-	p   = (u32 *) iov[1].iov_base;
-	end = (u32 *) ((u8 *) p + iov[1].iov_len);
+	pglen = rcvbuf->page_len;
+	page = rcvbuf->pages;
+	p = kmap(*page);
+	end = (u32 *)((char *)p + pglen);
 	for (nr = 0; *p++; nr++) {
 		entry = p - 1;
 		if (p + 2 > end)
@@ -473,16 +411,21 @@
 		if (len > NFS2_MAXNAMLEN) {
 			printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
 						len);
-			return -errno_NFSERR_IO;
+			goto err_unmap;
 		}
 		if (p + 2 > end)
 			goto short_pkt;
 	}
+	kunmap(*page);
 	return nr;
  short_pkt:
+	kunmap(*page);
 	printk(KERN_NOTICE "NFS: short packet in readdir reply!\n");
 	entry[0] = entry[1] = 0;
 	return nr;
+err_unmap:
+	kunmap(*page);
+	return -errno_NFSERR_IO;
 }
 
 u32 *
@@ -568,21 +511,16 @@
 static int
 nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
 {
-	struct rpc_task *task = req->rq_task;
-	struct rpc_auth *auth = task->tk_auth;
-	int		buflen, replen;
+	struct rpc_auth *auth = req->rq_task->tk_auth;
+	unsigned int replen;
+	u32 count = args->count - 4;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
-	req->rq_rlen = buflen + args->bufsiz;
-	req->rq_rnr += 2;
+	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 	return 0;
 }
 
@@ -590,32 +528,33 @@
  * Decode READLINK reply
  */
 static int
-nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
+nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
 {
-	struct iovec *iov = req->rq_rvec;
-	u32	*strlen;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	struct iovec *iov = rcvbuf->head;
+	unsigned int hdrlen;
+	u32	*strlen, len;
 	char	*string;
-	int	hdrlen;
 	int	status;
-	unsigned int len;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
-	strlen = (u32*)res->buffer;
+	strlen = (u32*)kmap(rcvbuf->pages[0]);
 	/* Convert length of symlink */
 	len = ntohl(*strlen);
-	if (len > res->bufsiz - 5)
-		len = res->bufsiz - 5;
+	if (len > rcvbuf->page_len)
+		len = rcvbuf->page_len;
 	*strlen = len;
 	/* NULL terminate the string we got */
 	string = (char *)(strlen + 1);
 	string[len] = 0;
+	kunmap(rcvbuf->pages[0]);
 	return 0;
 }
 
diff -Nru a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
--- a/fs/nfs/nfs3proc.c	Wed May 29 11:43:03 2002
+++ b/fs/nfs/nfs3proc.c	Wed May 29 11:43:03 2002
@@ -171,25 +171,20 @@
 }
 
 static int
-nfs3_proc_readlink(struct inode *inode, void *buffer, unsigned int buflen)
+nfs3_proc_readlink(struct inode *inode, struct page *page)
 {
 	struct nfs_fattr	fattr;
 	struct nfs3_readlinkargs args = {
 		fh:		NFS_FH(inode),
-		buffer:		buffer,
-		bufsiz:		buflen
-	};
-	struct nfs3_readlinkres	res = {
-		fattr:		&fattr,
-		buffer:		buffer,
-		bufsiz:		buflen
+		count:		PAGE_CACHE_SIZE,
+		pages:		&page
 	};
 	int			status;
 
 	dprintk("NFS call  readlink\n");
 	fattr.valid = 0;
 	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK,
-			  &args, &res, 0);
+			  &args, &fattr, 0);
 	nfs_refresh_inode(inode, &fattr);
 	dprintk("NFS reply readlink: %d\n", status);
 	return status;
@@ -198,14 +193,16 @@
 static int
 nfs3_proc_read(struct inode *inode, struct rpc_cred *cred,
 	       struct nfs_fattr *fattr, int flags,
-	       loff_t offset, unsigned int count, void *buffer, int *eofp)
+	       unsigned int base, unsigned int count, struct page *page,
+	       int *eofp)
 {
+	u64			offset = page_offset(page) + base;
 	struct nfs_readargs	arg = {
 		fh:		NFS_FH(inode),
 		offset:		offset,
 		count:		count,
-		nriov:		1,
-		iov:		{{buffer, count}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}
+		pgbase:		base,
+		pages:		&page
 	};
 	struct nfs_readres	res = {
 		fattr:		fattr,
@@ -230,16 +227,17 @@
 static int
 nfs3_proc_write(struct inode *inode, struct rpc_cred *cred,
 		struct nfs_fattr *fattr, int flags,
-		loff_t offset, unsigned int count,
-		void *buffer, struct nfs_writeverf *verf)
+		unsigned int base, unsigned int count,
+		struct page *page, struct nfs_writeverf *verf)
 {
+	u64			offset = page_offset(page) + base;
 	struct nfs_writeargs	arg = {
 		fh:		NFS_FH(inode),
 		offset:		offset,
 		count:		count,
 		stable:		NFS_FILE_SYNC,
-		nriov:		1,
-		iov:		{{buffer, count}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}
+		pgbase:		base,
+		pages:		&page
 	};
 	struct nfs_writeres	res = {
 		fattr:		fattr,
@@ -541,16 +539,22 @@
  */
 static int
 nfs3_proc_readdir(struct inode *dir, struct rpc_cred *cred,
-		  u64 cookie, void *entry,
-		  unsigned int size, int plus)
+		  u64 cookie, struct page *page, unsigned int count, int plus)
 {
 	struct nfs_fattr	dir_attr;
+	u32			*verf = NFS_COOKIEVERF(dir);
 	struct nfs3_readdirargs	arg = {
 		fh:		NFS_FH(dir),
 		cookie:		cookie,
+		verf:		{verf[0], verf[1]},
+		plus:		plus,
+		count:		count,
+		pages:		&page
 	};
 	struct nfs3_readdirres	res = {
 		dir_attr:	&dir_attr,
+		verf:		verf,
+		plus:		plus
 	};
 	struct rpc_message	msg = {
 		rpc_proc:	NFS3PROC_READDIR,
@@ -558,20 +562,9 @@
 		rpc_resp:	&res,
 		rpc_cred:	cred
 	};
-	u32			*verf = NFS_COOKIEVERF(dir);
 	int			status;
 
 	lock_kernel();
-
-	arg.buffer  = entry;
-	arg.bufsiz  = size;
-	arg.verf[0] = verf[0];
-	arg.verf[1] = verf[1];
-	arg.plus    = plus;
-	res.buffer  = entry;
-	res.bufsiz  = size;
-	res.verf    = verf;
-	res.plus    = plus;
 
 	if (plus)
 		msg.rpc_proc = NFS3PROC_READDIRPLUS;
diff -Nru a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
--- a/fs/nfs/nfs3xdr.c	Wed May 29 11:43:03 2002
+++ b/fs/nfs/nfs3xdr.c	Wed May 29 11:43:03 2002
@@ -22,9 +22,6 @@
 #include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
 
-/* Uncomment this to support servers requiring longword lengths */
-#define NFS_PAD_WRITES		1
-
 #define NFSDBG_FACILITY		NFSDBG_XDR
 
 /* Mapping from NFS error code to "errno" error code. */
@@ -156,18 +153,7 @@
 	return p;
 }
 
-static inline u32 *
-xdr_decode_string2(u32 *p, char **string, unsigned int *len,
-			unsigned int maxlen)
-{
-	*len = ntohl(*p++);
-	if (*len > maxlen)
-		return NULL;
-	*string = (char *) p;
-	return p + XDR_QUADLEN(*len);
-}
-
-static inline u32 *
+static u32 *
 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
 {
 	unsigned int	type;
@@ -350,35 +336,18 @@
 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		buflen, replen;
-	unsigned int	nr;
+	unsigned int replen;
+	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_hyper(p, args->offset);
-	*p++ = htonl(args->count);
+	*p++ = htonl(count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	/* Get the number of buffers in the receive iovec */
-	nr = args->nriov;
-
-	if (nr+2 > MAX_IOVEC) {
-		printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
-		return -EINVAL;
-	}
-
-	/* set up reply iovec */
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-
-	/* Copy the iovec */
-	memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
-
-	req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[nr+1].iov_len  = buflen - replen;
-	req->rq_rlen = args->count + buflen;
-	req->rq_rnr += nr+1;
-
+	xdr_inline_pages(&req->rq_rcv_buf, replen,
+			 args->pages, args->pgbase, count);
 	return 0;
 }
 
@@ -388,7 +357,7 @@
 static int
 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
 {
-	unsigned int	nr;
+	struct xdr_buf *sndbuf = &req->rq_snd_buf;
 	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
@@ -396,37 +365,10 @@
 	*p++ = htonl(count);
 	*p++ = htonl(args->stable);
 	*p++ = htonl(count);
-	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
-
-	/* Get the number of buffers in the send iovec */
-	nr = args->nriov;
-
-	if (nr+2 > MAX_IOVEC) {
-		printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs\n");
-		return -EINVAL;
-	}
-
-	/* Copy the iovec */
-	memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
-
-#ifdef NFS_PAD_WRITES
-	/*
-	 * Some old servers require that the message length
-	 * be a multiple of 4, so we pad it here if needed.
-	 */
-	if (count & 3) {
-		struct iovec	*iov = req->rq_svec + nr + 1;
-		int		pad = 4 - (count & 3);
-
-		iov->iov_base = (void *) "\0\0\0";
-		iov->iov_len  = pad;
-		count += pad;
-		nr++;
-	}
-#endif
-	req->rq_slen += count;
-	req->rq_snr  += nr;
+	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
 
+	/* Copy the page array */
+	xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
 	return 0;
 }
 
@@ -530,7 +472,8 @@
 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		buflen, replen;
+	unsigned int replen;
+	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_hyper(p, args->cookie);
@@ -539,22 +482,14 @@
 	if (args->plus) {
 		/* readdirplus: need dircount + buffer size.
 		 * We just make sure we make dircount big enough */
-		*p++ = htonl(args->bufsiz >> 3);
+		*p++ = htonl(count >> 3);
 	}
-	*p++ = htonl(args->bufsiz);
+	*p++ = htonl(count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	/* set up reply iovec */
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
-	req->rq_rlen = buflen + args->bufsiz;
-	req->rq_rnr += 2;
-
+	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 	return 0;
 }
 
@@ -565,11 +500,13 @@
 static int
 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
 {
-	struct iovec	*iov = req->rq_rvec;
-	int		hdrlen;
-	int		status, nr;
-	unsigned int	len;
-	u32		*entry, *end;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	struct iovec *iov = rcvbuf->head;
+	struct page **page;
+	int hdrlen;
+	int status, nr;
+	unsigned int len, pglen;
+	u32 *entry, *end;
 
 	status = ntohl(*p++);
 	/* Decode post_op_attrs */
@@ -587,11 +524,13 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
-	p   = (u32 *) iov[1].iov_base;
-	end = (u32 *) ((u8 *) p + iov[1].iov_len);
+	pglen = rcvbuf->page_len;
+	page = rcvbuf->pages;
+	p = kmap(*page);
+	end = (u32 *)((char *)p + pglen);
 	for (nr = 0; *p++; nr++) {
 		entry = p - 1;
 		if (p + 3 > end)
@@ -602,7 +541,7 @@
 		if (len > NFS3_MAXNAMLEN) {
 			printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
 						len);
-			return -errno_NFSERR_IO;
+			goto err_unmap;
 		}
 
 		if (res->plus) {
@@ -622,7 +561,7 @@
 				if (len > NFS3_FHSIZE) {
 					printk(KERN_WARNING "NFS: giant filehandle in "
 						"readdir (len %x)!\n", len);
-					return -errno_NFSERR_IO;
+					goto err_unmap;
 				}
 				p += XDR_QUADLEN(len);
 			}
@@ -631,13 +570,17 @@
 		if (p + 2 > end)
 			goto short_pkt;
 	}
-
+	kunmap(*page);
 	return nr;
  short_pkt:
+	kunmap(*page);
 	printk(KERN_NOTICE "NFS: short packet in readdir reply!\n");
 	/* truncate listing */
 	entry[0] = entry[1] = 0;
 	return nr;
+err_unmap:
+	kunmap(*page);
+	return -errno_NFSERR_IO;
 }
 
 u32 *
@@ -772,21 +715,16 @@
 static int
 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
 {
-	struct rpc_task *task = req->rq_task;
-	struct rpc_auth *auth = task->tk_auth;
-	int		buflen, replen;
+	struct rpc_auth *auth = req->rq_task->tk_auth;
+	unsigned int replen;
+	u32 count = args->count - 4;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+	/* Inline the page array */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
-	buflen = req->rq_rvec[0].iov_len;
-	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
-	req->rq_rlen = buflen + args->bufsiz;
-	req->rq_rnr += 2;
+	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 	return 0;
 }
 
@@ -794,17 +732,17 @@
  * Decode READLINK reply
  */
 static int
-nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkres *res)
+nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
 {
-	struct iovec	*iov = req->rq_rvec;
-	int		hdrlen;
-	u32	*strlen;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	struct iovec *iov = rcvbuf->head;
+	unsigned int hdrlen;
+	u32	*strlen, len;
 	char	*string;
 	int	status;
-	unsigned int len;
 
 	status = ntohl(*p++);
-	p = xdr_decode_post_op_attr(p, res->fattr);
+	p = xdr_decode_post_op_attr(p, fattr);
 
 	if (status != 0)
 		return -nfs_stat_to_errno(status);
@@ -812,18 +750,19 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 	}
 
-	strlen = (u32*)res->buffer;
+	strlen = (u32*)kmap(rcvbuf->pages[0]);
 	/* Convert length of symlink */
 	len = ntohl(*strlen);
-	if (len > res->bufsiz - 5)
-		len = res->bufsiz - 5;
+	if (len > rcvbuf->page_len)
+		len = rcvbuf->page_len;
 	*strlen = len;
 	/* NULL terminate the string we got */
 	string = (char *)(strlen + 1);
 	string[len] = 0;
+	kunmap(rcvbuf->pages[0]);
 	return 0;
 }
 
@@ -857,7 +796,7 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len > hdrlen) {
 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
-		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 	}
 
 	recvd = req->rq_rlen - hdrlen;
@@ -867,10 +806,8 @@
 		count = recvd;
 	}
 
-	if (count < res->count) {
-		xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
+	if (count < res->count)
 		res->count = count;
-	}
 
 	return count;
 }
diff -Nru a/fs/nfs/proc.c b/fs/nfs/proc.c
--- a/fs/nfs/proc.c	Wed May 29 11:43:02 2002
+++ b/fs/nfs/proc.c	Wed May 29 11:43:02 2002
@@ -117,22 +117,17 @@
 }
 
 static int
-nfs_proc_readlink(struct inode *inode, void *buffer, unsigned int bufsiz)
+nfs_proc_readlink(struct inode *inode, struct page *page)
 {
 	struct nfs_readlinkargs	args = {
 		fh:		NFS_FH(inode),
-		buffer:		buffer,
-		bufsiz:		bufsiz
-	};
-	struct nfs_readlinkres	res = {
-		buffer:		buffer,
-		bufsiz:		bufsiz
+		count:		PAGE_CACHE_SIZE,
+		pages:		&page
 	};
 	int			status;
 
 	dprintk("NFS call  readlink\n");
-	status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK,
-					&args, &res, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK, &args, NULL, 0);
 	dprintk("NFS reply readlink: %d\n", status);
 	return status;
 }
@@ -140,14 +135,16 @@
 static int
 nfs_proc_read(struct inode *inode, struct rpc_cred *cred,
 	      struct nfs_fattr *fattr, int flags,
-	      loff_t offset, unsigned int count, void *buffer, int *eofp)
+	      unsigned int base, unsigned int count, struct page *page,
+	      int *eofp)
 {
+	u64			offset = page_offset(page) + base;
 	struct nfs_readargs	arg = {
 		fh:		NFS_FH(inode),
 		offset:		offset,
 		count:		count,
-		nriov:		1,
-		iov:		{{ buffer, count }, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}
+		pgbase:		base,
+		pages:		&page
 	};
 	struct nfs_readres	res = {
 		fattr:		fattr,
@@ -173,16 +170,17 @@
 static int
 nfs_proc_write(struct inode *inode, struct rpc_cred *cred,
 	       struct nfs_fattr *fattr, int how,
-	       loff_t offset, unsigned int count,
-	       void *buffer, struct nfs_writeverf *verf)
+	       unsigned int base, unsigned int count,
+	       struct page *page, struct nfs_writeverf *verf)
 {
+	u64			offset = page_offset(page) + base;
 	struct nfs_writeargs	arg = {
 		fh:		NFS_FH(inode),
 		offset:		offset,
 		count:		count,
 		stable:		NFS_FILE_SYNC,
-		nriov:		1,
-		iov:		{{buffer, count}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}
+		pgbase:		base,
+		pages:		&page
 	};
 	struct nfs_writeres     res = {
 		fattr:		fattr,
@@ -428,27 +426,23 @@
  */
 static int
 nfs_proc_readdir(struct inode *dir, struct rpc_cred *cred,
-		 __u64 cookie, void *entry, 
-		 unsigned int size, int plus)
+		 u64 cookie, struct page *page, unsigned int count, int plus)
 {
-	struct nfs_readdirargs	arg;
-	struct nfs_readdirres	res;
+	struct nfs_readdirargs	arg = {
+		fh:		NFS_FH(dir),
+		cookie:		cookie,
+		count:		count,
+		pages:		&page
+	};
 	struct rpc_message	msg = {
 		rpc_proc:	NFSPROC_READDIR,
 		rpc_argp:	&arg,
-		rpc_resp:	&res,
+		rpc_resp:	NULL,
 		rpc_cred:	cred
 	};
 	int			status;
 
 	lock_kernel();
-
-	arg.fh = NFS_FH(dir);
-	arg.cookie = cookie;
-	arg.buffer = entry;
-	arg.bufsiz = size;
-	res.buffer = entry;
-	res.bufsiz = size;
 
 	dprintk("NFS call  readdir %d\n", (unsigned int)cookie);
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
diff -Nru a/fs/nfs/read.c b/fs/nfs/read.c
--- a/fs/nfs/read.c	Wed May 29 11:43:01 2002
+++ b/fs/nfs/read.c	Wed May 29 11:43:01 2002
@@ -42,6 +42,7 @@
 	struct nfs_readres	res;	/* ... and result struct */
 	struct nfs_fattr	fattr;	/* fattr storage */
 	struct list_head	pages;	/* Coalesced read requests */
+	struct page		*pagevec[NFS_READ_MAXIOV];
 };
 
 /*
@@ -63,6 +64,7 @@
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
+		p->args.pages = p->pagevec;
 	}
 	return p;
 }
@@ -86,11 +88,10 @@
 {
 	struct rpc_cred	*cred = NULL;
 	struct nfs_fattr fattr;
-	loff_t		offset = page_offset(page);
-	char		*buffer;
-	int		rsize = NFS_SERVER(inode)->rsize;
+	unsigned int	offset = 0;
+	unsigned int	rsize = NFS_SERVER(inode)->rsize;
+	unsigned int	count = PAGE_CACHE_SIZE;
 	int		result;
-	int		count = PAGE_CACHE_SIZE;
 	int		flags = IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0;
 	int		eof;
 
@@ -103,20 +104,19 @@
 	 * This works now because the socket layer never tries to DMA
 	 * into this buffer directly.
 	 */
-	buffer = kmap(page);
 	do {
 		if (count < rsize)
 			rsize = count;
 
-		dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Ld, %d, %p)\n",
+		dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n",
 			NFS_SERVER(inode)->hostname,
 			inode->i_sb->s_id,
 			(long long)NFS_FILEID(inode),
-			(long long)offset, rsize, buffer);
+			(unsigned long long)offset, rsize);
 
 		lock_kernel();
 		result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags,
-						offset, rsize, buffer, &eof);
+						offset, rsize, page, &eof);
 		nfs_refresh_inode(inode, &fattr);
 		unlock_kernel();
 
@@ -131,12 +131,15 @@
 		}
 		count  -= result;
 		offset += result;
-		buffer += result;
 		if (result < rsize)	/* NFSv2ism */
 			break;
 	} while (count);
 
-	memset(buffer, 0, count);
+	if (count) {
+		char *kaddr = kmap(page);
+		memset(kaddr + offset, 0, count);
+		kunmap(page);
+	}
 	flush_dcache_page(page);
 	SetPageUptodate(page);
 	if (PageError(page))
@@ -144,7 +147,6 @@
 	result = 0;
 
 io_error:
-	kunmap(page);
 	unlock_page(page);
 	return result;
 }
@@ -189,26 +191,24 @@
 nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data)
 {
 	struct nfs_page		*req;
-	struct iovec		*iov;
+	struct page		**pages;
 	unsigned int		count;
 
-	iov = data->args.iov;
+	pages = data->args.pages;
 	count = 0;
 	while (!list_empty(head)) {
 		struct nfs_page *req = nfs_list_entry(head->next);
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, &data->pages);
-		iov->iov_base = kmap(req->wb_page) + req->wb_offset;
-		iov->iov_len = req->wb_bytes;
+		*pages++ = req->wb_page;
 		count += req->wb_bytes;
-		iov++;
-		data->args.nriov++;
 	}
 	req = nfs_list_entry(data->pages.next);
 	data->inode	  = req->wb_inode;
 	data->cred	  = req->wb_cred;
 	data->args.fh     = NFS_FH(req->wb_inode);
 	data->args.offset = page_offset(req->wb_page) + req->wb_offset;
+	data->args.pgbase = req->wb_offset;
 	data->args.count  = count;
 	data->res.fattr   = &data->fattr;
 	data->res.count   = count;
@@ -269,11 +269,12 @@
 	msg.rpc_cred = data->cred;
 
 	/* Start the async call */
-	dprintk("NFS: %4d initiated read call (req %s/%Ld count %d nriov %d.\n",
+	dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu.\n",
 		task->tk_pid,
 		inode->i_sb->s_id,
 		(long long)NFS_FILEID(inode),
-		data->args.count, data->args.nriov);
+		(unsigned int)data->args.count,
+		(unsigned long long)data->args.offset);
 
 	rpc_clnt_sigmask(clnt, &oldset);
 	rpc_call_setup(task, &msg, 0);
@@ -429,7 +430,6 @@
 		} else
 			SetPageError(page);
 		flush_dcache_page(page);
-		kunmap(page);
 		unlock_page(page);
 
 		dprintk("NFS: read (%s/%Ld %d@%Ld)\n",
diff -Nru a/fs/nfs/symlink.c b/fs/nfs/symlink.c
--- a/fs/nfs/symlink.c	Wed May 29 11:43:01 2002
+++ b/fs/nfs/symlink.c	Wed May 29 11:43:01 2002
@@ -29,7 +29,6 @@
  */
 static int nfs_symlink_filler(struct inode *inode, struct page *page)
 {
-	void *buffer = kmap(page);
 	int error;
 
 	/* We place the length at the beginning of the page,
@@ -37,19 +36,16 @@
 	 * XDR response verification will NULL terminate it.
 	 */
 	lock_kernel();
-	error = NFS_PROTO(inode)->readlink(inode, buffer,
-					   PAGE_CACHE_SIZE - sizeof(u32)-4);
+	error = NFS_PROTO(inode)->readlink(inode, page);
 	unlock_kernel();
 	if (error < 0)
 		goto error;
 	SetPageUptodate(page);
-	kunmap(page);
 	unlock_page(page);
 	return 0;
 
 error:
 	SetPageError(page);
-	kunmap(page);
 	unlock_page(page);
 	return -EIO;
 }
diff -Nru a/fs/nfs/write.c b/fs/nfs/write.c
--- a/fs/nfs/write.c	Wed May 29 11:43:02 2002
+++ b/fs/nfs/write.c	Wed May 29 11:43:02 2002
@@ -77,6 +77,7 @@
 	struct nfs_fattr	fattr;
 	struct nfs_writeverf	verf;
 	struct list_head	pages;		/* Coalesced requests we wish to flush */
+	struct page		*pagevec[NFS_WRITE_MAXIOV];
 };
 
 /*
@@ -105,6 +106,7 @@
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
+		p->args.pages = p->pagevec;
 	}
 	return p;
 }
@@ -164,7 +166,6 @@
 		(long long)NFS_FILEID(inode),
 		count, (long long)(page_offset(page) + offset));
 
-	buffer = kmap(page) + offset;
 	base = page_offset(page) + offset;
 
 	flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC;
@@ -174,7 +175,7 @@
 			wsize = count;
 
 		result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags,
-						 base, wsize, buffer, &verf);
+						 offset, wsize, page, &verf);
 		nfs_write_attributes(inode, &fattr);
 
 		if (result < 0) {
@@ -187,7 +188,8 @@
 			wsize, result);
 		refresh = 1;
 		buffer  += wsize;
-	        base    += wsize;
+		base    += wsize;
+	        offset  += wsize;
 		written += wsize;
 		count   -= wsize;
 		/*
@@ -202,7 +204,6 @@
 		ClearPageError(page);
 
 io_error:
-	kunmap(page);
 	if (cred)
 		put_rpccred(cred);
 
@@ -857,29 +858,27 @@
 nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
 {
 	struct nfs_page		*req;
-	struct iovec		*iov;
+	struct page		**pages;
 	unsigned int		count;
 
 	/* Set up the RPC argument and reply structs
 	 * NB: take care not to mess about with data->commit et al. */
 
-	iov = data->args.iov;
+	pages = data->args.pages;
 	count = 0;
 	while (!list_empty(head)) {
 		struct nfs_page *req = nfs_list_entry(head->next);
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, &data->pages);
-		iov->iov_base = kmap(req->wb_page) + req->wb_offset;
-		iov->iov_len = req->wb_bytes;
+		*pages++ = req->wb_page;
 		count += req->wb_bytes;
-		iov++;
-		data->args.nriov++;
 	}
 	req = nfs_list_entry(data->pages.next);
 	data->inode = req->wb_inode;
 	data->cred = req->wb_cred;
 	data->args.fh     = NFS_FH(req->wb_inode);
 	data->args.offset = page_offset(req->wb_page) + req->wb_offset;
+	data->args.pgbase = req->wb_offset;
 	data->args.count  = count;
 	data->res.fattr   = &data->fattr;
 	data->res.count   = count;
@@ -945,11 +944,12 @@
 	msg.rpc_resp = &data->res;
 	msg.rpc_cred = data->cred;
 
-	dprintk("NFS: %4d initiated write call (req %s/%Ld count %d nriov %d)\n",
-		task->tk_pid, 
+	dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
+		task->tk_pid,
 		inode->i_sb->s_id,
 		(long long)NFS_FILEID(inode),
-		data->args.count, data->args.nriov);
+		(unsigned int)data->args.count,
+		(unsigned long long)data->args.offset);
 
 	rpc_clnt_sigmask(clnt, &oldset);
 	rpc_call_setup(task, &msg, 0);
@@ -1060,8 +1060,6 @@
 		req = nfs_list_entry(data->pages.next);
 		nfs_list_remove_request(req);
 		page = req->wb_page;
-
-		kunmap(page);
 
 		dprintk("NFS: write (%s/%Ld %d@%Ld)",
 			req->wb_inode->i_sb->s_id,
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Wed May 29 11:43:02 2002
+++ b/fs/partitions/check.c	Wed May 29 11:43:02 2002
@@ -224,15 +224,11 @@
 static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor)
 {
 	devfs_handle_t de = NULL;
-	static int first_time = 1;
 	unsigned long first_sector;
 	struct block_device *bdev;
 	char buf[64];
 	int i;
 
-	if (first_time)
-		printk(KERN_INFO "Partition check:\n");
-	first_time = 0;
 	first_sector = hd->part[minor(dev)].start_sect;
 
 	/*
diff -Nru a/fs/proc/array.c b/fs/proc/array.c
--- a/fs/proc/array.c	Wed May 29 11:43:01 2002
+++ b/fs/proc/array.c	Wed May 29 11:43:01 2002
@@ -346,7 +346,7 @@
 	read_unlock(&tasklist_lock);
 	res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n",
 		task->pid,
 		task->comm,
 		state,
@@ -389,7 +389,9 @@
 		task->nswap,
 		task->cnswap,
 		task->exit_signal,
-		task->thread_info->cpu);
+		task->thread_info->cpu,
+		task->rt_priority,
+		task->policy);
 	if(mm)
 		mmput(mm);
 	return res;
diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Wed May 29 11:43:01 2002
+++ b/fs/proc/proc_misc.c	Wed May 29 11:43:01 2002
@@ -149,8 +149,8 @@
 		"MemShared:    %8lu kB\n"
 		"Cached:       %8lu kB\n"
 		"SwapCached:   %8lu kB\n"
-		"Active:       %8u kB\n"
-		"Inactive:     %8u kB\n"
+		"Active:       %8lu kB\n"
+		"Inactive:     %8lu kB\n"
 		"HighTotal:    %8lu kB\n"
 		"HighFree:     %8lu kB\n"
 		"LowTotal:     %8lu kB\n"
@@ -164,8 +164,8 @@
 		K(i.sharedram),
 		K(ps.nr_pagecache-swapper_space.nrpages),
 		K(swapper_space.nrpages),
-		K(nr_active_pages),
-		K(nr_inactive_pages),
+		K(ps.nr_active),
+		K(ps.nr_inactive),
 		K(i.totalhigh),
 		K(i.freehigh),
 		K(i.totalram-i.totalhigh),
diff -Nru a/fs/quota.c b/fs/quota.c
--- a/fs/quota.c	Wed May 29 11:43:03 2002
+++ b/fs/quota.c	Wed May 29 11:43:03 2002
@@ -6,16 +6,12 @@
  */
 
 #include <linux/fs.h>
+#include <linux/namei.h>
 #include <linux/slab.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include <linux/kernel.h>
 #include <linux/smp_lock.h>
-#include <linux/namei.h>
-#ifdef CONFIG_QIFACE_COMPAT
-#include <linux/quotacompat.h>
-#endif
-
 
 /* Check validity of quotactl */
 static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
@@ -234,381 +230,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_QIFACE_COMPAT
-static int check_compat_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
-{
-	if (type >= MAXQUOTAS)
-		return -EINVAL;
-	/* Is operation supported? */
-	/* sb==NULL for GETSTATS calls */
-	if (sb && !sb->s_qcop)
-		return -ENOSYS;
-
-	switch (cmd) {
-		case Q_COMP_QUOTAON:
-			if (!sb->s_qcop->quota_on)
-				return -ENOSYS;
-			break;
-		case Q_COMP_QUOTAOFF:
-			if (!sb->s_qcop->quota_off)
-				return -ENOSYS;
-			break;
-		case Q_COMP_SYNC:
-			if (!sb->s_qcop->quota_sync)
-				return -ENOSYS;
-		break;
-#ifdef CONFIG_QIFACE_V2
-		case Q_V2_SETFLAGS:
-		case Q_V2_SETGRACE:
-		case Q_V2_SETINFO:
-			if (!sb->s_qcop->set_info)
-				return -ENOSYS;
-			break;
-		case Q_V2_GETINFO:
-			if (!sb->s_qcop->get_info)
-				return -ENOSYS;
-			break;
-		case Q_V2_SETQLIM:
-		case Q_V2_SETUSE:
-		case Q_V2_SETQUOTA:
-			if (!sb->s_qcop->set_dqblk)
-				return -ENOSYS;
-			break;
-		case Q_V2_GETQUOTA:
-			if (!sb->s_qcop->get_dqblk)
-				return -ENOSYS;
-			break;
-		case Q_V2_GETSTATS:
-			return 0;	/* GETSTATS need no other checks */
-#endif
-#ifdef CONFIG_QIFACE_V1
-		case Q_V1_SETQLIM:
-		case Q_V1_SETUSE:
-		case Q_V1_SETQUOTA:
-			if (!sb->s_qcop->set_dqblk)
-				return -ENOSYS;
-			break;
-		case Q_V1_GETQUOTA:
-			if (!sb->s_qcop->get_dqblk)
-				return -ENOSYS;
-			break;
-		case Q_V1_RSQUASH:
-			if (!sb->s_qcop->set_info)
-				return -ENOSYS;
-			break;
-		case Q_V1_GETSTATS:
-			return 0;	/* GETSTATS need no other checks */
-#endif
-		default:
-			return -EINVAL;
-	}
-
-	/* Is quota turned on for commands which need it? */
-	switch (cmd) {
-		case Q_V2_SETFLAGS:
-		case Q_V2_SETGRACE:
-		case Q_V2_SETINFO:
-		case Q_V2_GETINFO:
-		case Q_COMP_QUOTAOFF:
-		case Q_V1_RSQUASH:
-		case Q_V1_SETQUOTA:
-		case Q_V1_SETQLIM:
-		case Q_V1_SETUSE:
-		case Q_V2_SETQUOTA:
-		/* Q_V2_SETQLIM: collision with Q_V1_SETQLIM */
-		case Q_V2_SETUSE:
-		case Q_V1_GETQUOTA:
-		case Q_V2_GETQUOTA:
-			if (!sb_has_quota_enabled(sb, type))
-				return -ESRCH;
-	}
-#ifdef CONFIG_QIFACE_V1
-	if (cmd != Q_COMP_QUOTAON && cmd != Q_COMP_QUOTAOFF && cmd != Q_COMP_SYNC && sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id != QFMT_VFS_OLD)
-#else
-	if (cmd != Q_COMP_QUOTAON && cmd != Q_COMP_QUOTAOFF && cmd != Q_COMP_SYNC && sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id != QFMT_VFS_V0)
-#endif
-		return -ESRCH;
-
-	/* Check privileges */
-	if (cmd == Q_V1_GETQUOTA || cmd == Q_V2_GETQUOTA) {
-		if (((type == USRQUOTA && current->euid != id) ||
-		     (type == GRPQUOTA && !in_egroup_p(id))) &&
-		    !capable(CAP_SYS_ADMIN))
-			return -EPERM;
-	}
-	else if (cmd != Q_V1_GETSTATS && cmd != Q_V2_GETSTATS && cmd != Q_V2_GETINFO && cmd != Q_COMP_SYNC)
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
-	return 0;
-}
-
-#ifdef CONFIG_QIFACE_V1
-static int v1_set_rsquash(struct super_block *sb, int type, int flag)
-{
-	struct if_dqinfo info;
-
-	info.dqi_valid = IIF_FLAGS;
-	info.dqi_flags = flag ? V1_DQF_RSQUASH : 0;
-	return sb->s_qcop->set_info(sb, type, &info);
-}
-
-static int v1_get_dqblk(struct super_block *sb, int type, qid_t id, struct v1c_mem_dqblk *mdq)
-{
-	struct if_dqblk idq;
-	int ret;
-
-	if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)) < 0)
-		return ret;
-	mdq->dqb_ihardlimit = idq.dqb_ihardlimit;
-	mdq->dqb_isoftlimit = idq.dqb_isoftlimit;
-	mdq->dqb_curinodes = idq.dqb_curinodes;
-	mdq->dqb_bhardlimit = idq.dqb_bhardlimit;
-	mdq->dqb_bsoftlimit = idq.dqb_bsoftlimit;
-	mdq->dqb_curblocks = toqb(idq.dqb_curspace);
-	mdq->dqb_itime = idq.dqb_itime;
-	mdq->dqb_btime = idq.dqb_btime;
-	if (id == 0) {	/* Times for id 0 are in fact grace times */
-		struct if_dqinfo info;
-
-		if ((ret = sb->s_qcop->get_info(sb, type, &info)) < 0)
-			return ret;
-		mdq->dqb_btime = info.dqi_bgrace;
-		mdq->dqb_itime = info.dqi_igrace;
-	}
-	return 0;
-}
-
-static int v1_set_dqblk(struct super_block *sb, int type, int cmd, qid_t id, struct v1c_mem_dqblk *mdq)
-{
-	struct if_dqblk idq;
-	int ret;
-
-	idq.dqb_valid = 0;
-	if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETQLIM) {
-		idq.dqb_ihardlimit = mdq->dqb_ihardlimit;
-		idq.dqb_isoftlimit = mdq->dqb_isoftlimit;
-		idq.dqb_bhardlimit = mdq->dqb_bhardlimit;
-		idq.dqb_bsoftlimit = mdq->dqb_bsoftlimit;
-		idq.dqb_valid |= QIF_LIMITS;
-	}
-	if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETUSE) {
-		idq.dqb_curinodes = mdq->dqb_curinodes;
-		idq.dqb_curspace = ((qsize_t)mdq->dqb_curblocks) << QUOTABLOCK_BITS;
-		idq.dqb_valid |= QIF_USAGE;
-	}
-	ret = sb->s_qcop->set_dqblk(sb, type, id, &idq);
-	if (!ret && id == 0 && cmd == Q_V1_SETQUOTA) {	/* Times for id 0 are in fact grace times */
-		struct if_dqinfo info;
-
-		info.dqi_bgrace = mdq->dqb_btime;
-		info.dqi_igrace = mdq->dqb_itime;
-		info.dqi_valid = IIF_BGRACE | IIF_IGRACE;
-		ret = sb->s_qcop->set_info(sb, type, &info);
-	}
-	return ret;
-}
-
-static void v1_get_stats(struct v1c_dqstats *dst)
-{
-	memcpy(dst, &dqstats_array, sizeof(dqstats_array));
-}
-#endif
-
-#ifdef CONFIG_QIFACE_V2
-static int v2_get_info(struct super_block *sb, int type, struct v2c_mem_dqinfo *oinfo)
-{
-	struct if_dqinfo info;
-	int ret;
-
-	if ((ret = sb->s_qcop->get_info(sb, type, &info)) < 0)
-		return ret;
-	oinfo->dqi_bgrace = info.dqi_bgrace;
-	oinfo->dqi_igrace = info.dqi_igrace;
-	oinfo->dqi_flags = info.dqi_flags;
-	oinfo->dqi_blocks = sb_dqopt(sb)->info[type].u.v2_i.dqi_blocks;
-	oinfo->dqi_free_blk = sb_dqopt(sb)->info[type].u.v2_i.dqi_free_blk;
-	oinfo->dqi_free_entry = sb_dqopt(sb)->info[type].u.v2_i.dqi_free_entry;
-	return 0;
-}
-
-static int v2_set_info(struct super_block *sb, int type, int cmd, struct v2c_mem_dqinfo *oinfo)
-{
-	struct if_dqinfo info;
-
-	info.dqi_valid = 0;
-	if (cmd == Q_V2_SETGRACE || cmd == Q_V2_SETINFO) {
-		info.dqi_bgrace = oinfo->dqi_bgrace;
-		info.dqi_igrace = oinfo->dqi_igrace;
-		info.dqi_valid |= IIF_BGRACE | IIF_IGRACE;
-	}
-	if (cmd == Q_V2_SETFLAGS || cmd == Q_V2_SETINFO) {
-		info.dqi_flags = oinfo->dqi_flags;
-		info.dqi_valid |= IIF_FLAGS;
-	}
-	/* We don't simulate deadly effects of setting other parameters ;-) */
-	return sb->s_qcop->set_info(sb, type, &info);
-}
-
-static int v2_get_dqblk(struct super_block *sb, int type, qid_t id, struct v2c_mem_dqblk *mdq)
-{
-	struct if_dqblk idq;
-	int ret;
-
-	if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)) < 0)
-		return ret;
-	mdq->dqb_ihardlimit = idq.dqb_ihardlimit;
-	mdq->dqb_isoftlimit = idq.dqb_isoftlimit;
-	mdq->dqb_curinodes = idq.dqb_curinodes;
-	mdq->dqb_bhardlimit = idq.dqb_bhardlimit;
-	mdq->dqb_bsoftlimit = idq.dqb_bsoftlimit;
-	mdq->dqb_curspace = idq.dqb_curspace;
-	mdq->dqb_itime = idq.dqb_itime;
-	mdq->dqb_btime = idq.dqb_btime;
-	return 0;
-}
-
-static int v2_set_dqblk(struct super_block *sb, int type, int cmd, qid_t id, struct v2c_mem_dqblk *mdq)
-{
-	struct if_dqblk idq;
-
-	idq.dqb_valid = 0;
-	if (cmd == Q_V2_SETQUOTA || cmd == Q_V2_SETQLIM) {
-		idq.dqb_ihardlimit = mdq->dqb_ihardlimit;
-		idq.dqb_isoftlimit = mdq->dqb_isoftlimit;
-		idq.dqb_bhardlimit = mdq->dqb_bhardlimit;
-		idq.dqb_bsoftlimit = mdq->dqb_bsoftlimit;
-		idq.dqb_valid |= QIF_LIMITS;
-	}
-	if (cmd == Q_V2_SETQUOTA || cmd == Q_V2_SETUSE) {
-		idq.dqb_curinodes = mdq->dqb_curinodes;
-		idq.dqb_curspace = mdq->dqb_curspace;
-		idq.dqb_valid |= QIF_USAGE;
-	}
-	return sb->s_qcop->set_dqblk(sb, type, id, &idq);
-}
-
-static void v2_get_stats(struct v2c_dqstats *dst)
-{
-	memcpy(dst, &dqstats_array, sizeof(dqstats_array));
-	dst->version = __DQUOT_NUM_VERSION__;
-}
-#endif
-
-/* Handle requests to old interface */
-static int do_compat_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr)
-{
-	int ret;
-
-	switch (cmd) {
-		case Q_COMP_QUOTAON: {
-			char *pathname;
-
-			if (IS_ERR(pathname = getname(addr)))
-				return PTR_ERR(pathname);
-#ifdef CONFIG_QIFACE_V1
-			ret = sb->s_qcop->quota_on(sb, type, QFMT_VFS_OLD, pathname);
-#else
-			ret = sb->s_qcop->quota_on(sb, type, QFMT_VFS_V0, pathname);
-#endif
-			putname(pathname);
-			return ret;
-		}
-		case Q_COMP_QUOTAOFF:
-			return sb->s_qcop->quota_off(sb, type);
-		case Q_COMP_SYNC:
-			return sb->s_qcop->quota_sync(sb, type);
-#ifdef CONFIG_QIFACE_V1
-		case Q_V1_RSQUASH: {
-			int flag;
-
-			if (copy_from_user(&flag, addr, sizeof(flag)))
-				return -EFAULT;
-			return v1_set_rsquash(sb, type, flag);
-		}
-		case Q_V1_GETQUOTA: {
-			struct v1c_mem_dqblk mdq;
-
-			if ((ret = v1_get_dqblk(sb, type, id, &mdq)))
-				return ret;
-			if (copy_to_user(addr, &mdq, sizeof(mdq)))
-				return -EFAULT;
-			return 0;
-		}
-		case Q_V1_SETQLIM:
-		case Q_V1_SETUSE:
-		case Q_V1_SETQUOTA: {
-			struct v1c_mem_dqblk mdq;
-
-			if (copy_from_user(&mdq, addr, sizeof(mdq)))
-				return -EFAULT;
-			return v1_set_dqblk(sb, type, cmd, id, &mdq);
-		}
-		case Q_V1_GETSTATS: {
-			struct v1c_dqstats dst;
-
-			v1_get_stats(&dst);
-			if (copy_to_user(addr, &dst, sizeof(dst)))
-				return -EFAULT;
-			return 0;
-		}
-#endif
-#ifdef CONFIG_QIFACE_V2
-		case Q_V2_GETINFO: {
-			struct v2c_mem_dqinfo info;
-
-			if ((ret = v2_get_info(sb, type, &info)))
-				return ret;
-			if (copy_to_user(addr, &info, sizeof(info)))
-				return -EFAULT;
-			return 0;
-		}
-		case Q_V2_SETFLAGS:
-		case Q_V2_SETGRACE:
-		case Q_V2_SETINFO: {
-			struct v2c_mem_dqinfo info;
-
-			if (copy_from_user(&info, addr, sizeof(info)))
-				return -EFAULT;
-			
-			return v2_set_info(sb, type, cmd, &info);
-		}
-		case Q_V2_GETQUOTA: {
-			struct v2c_mem_dqblk mdq;
-
-			if ((ret = v2_get_dqblk(sb, type, id, &mdq)))
-				return ret;
-			if (copy_to_user(addr, &mdq, sizeof(mdq)))
-				return -EFAULT;
-			return 0;
-		}
-		case Q_V2_SETUSE:
-		case Q_V2_SETQLIM:
-		case Q_V2_SETQUOTA: {
-			struct v2c_mem_dqblk mdq;
-
-			if (copy_from_user(&mdq, addr, sizeof(mdq)))
-				return -EFAULT;
-			return v2_set_dqblk(sb, type, cmd, id, &mdq);
-		}
-		case Q_V2_GETSTATS: {
-			struct v2c_dqstats dst;
-
-			v2_get_stats(&dst);
-			if (copy_to_user(addr, &dst, sizeof(dst)))
-				return -EFAULT;
-			return 0;
-		}
-#endif
-	}
-	BUG();
-	return 0;
-}
-#endif
-
-/* Macros for short-circuiting the compatibility tests */
-#define NEW_COMMAND(c) ((c) & (0x80 << 16))
-#define XQM_COMMAND(c) (((c) & ('X' << 8)) == ('X' << 8))
-
 /*
  * This is the system call interface. This communicates with
  * the user-level programs. Currently this only supports diskquota
@@ -625,25 +246,11 @@
 	cmds = cmd >> SUBCMDSHIFT;
 	type = cmd & SUBCMDMASK;
 
-#ifdef CONFIG_QIFACE_COMPAT
-	if (cmds != Q_V1_GETSTATS && cmds != Q_V2_GETSTATS && IS_ERR(sb = resolve_dev(special))) {
-		ret = PTR_ERR(sb);
-		sb = NULL;
-		goto out;
-	}
-	if (!NEW_COMMAND(cmds) && !XQM_COMMAND(cmds)) {
-		if ((ret = check_compat_quotactl_valid(sb, type, cmds, id)) < 0)
-			goto out;
-		ret = do_compat_quotactl(sb, type, cmds, id, addr);
-		goto out;
-	}
-#else
 	if (IS_ERR(sb = resolve_dev(special))) {
 		ret = PTR_ERR(sb);
 		sb = NULL;
 		goto out;
 	}
-#endif
 	if ((ret = check_quotactl_valid(sb, type, cmds, id)) < 0)
 		goto out;
 	ret = do_quotactl(sb, type, cmds, id, addr);
diff -Nru a/fs/quota_v1.c b/fs/quota_v1.c
--- a/fs/quota_v1.c	Wed May 29 11:43:03 2002
+++ b/fs/quota_v1.c	Wed May 29 11:43:03 2002
@@ -57,7 +57,7 @@
 	if (dquot->dq_dqb.dqb_bhardlimit == 0 && dquot->dq_dqb.dqb_bsoftlimit == 0 &&
 	    dquot->dq_dqb.dqb_ihardlimit == 0 && dquot->dq_dqb.dqb_isoftlimit == 0)
 		dquot->dq_flags |= DQ_FAKE;
-	++dqstats_array[DQSTATS_READS];
+	dqstats.reads++;
 
 	return 0;
 }
@@ -101,7 +101,7 @@
 
 out:
 	set_fs(fs);
-	++dqstats_array[DQSTATS_WRITES];
+	dqstats.writes++;
 
 	return ret;
 }
@@ -233,6 +233,8 @@
 {
         unregister_quota_format(&v1_quota_format);
 }
+
+EXPORT_NO_SYMBOLS;
 
 module_init(init_v1_quota_format);
 module_exit(exit_v1_quota_format);
diff -Nru a/fs/quota_v2.c b/fs/quota_v2.c
--- a/fs/quota_v2.c	Wed May 29 11:43:02 2002
+++ b/fs/quota_v2.c	Wed May 29 11:43:02 2002
@@ -430,7 +430,7 @@
 	}
 	else
 		ret = 0;
-	++dqstats_array[DQSTATS_WRITES];
+	dqstats.writes++;
 
 	return ret;
 }
@@ -645,7 +645,7 @@
 		set_fs(fs);
 		disk2memdqb(&dquot->dq_dqb, &ddquot);
 	}
-	++dqstats_array[DQSTATS_READS];
+	dqstats.reads++;
 
 	return ret;
 }
@@ -685,6 +685,8 @@
 {
 	unregister_quota_format(&v2_quota_format);
 }
+
+EXPORT_NO_SYMBOLS;
 
 module_init(init_v2_quota_format);
 module_exit(exit_v2_quota_format);
diff -Nru a/fs/reiserfs/buffer2.c b/fs/reiserfs/buffer2.c
--- a/fs/reiserfs/buffer2.c	Wed May 29 11:43:03 2002
+++ b/fs/reiserfs/buffer2.c	Wed May 29 11:43:03 2002
@@ -32,7 +32,7 @@
 			bh, repeat_counter, buffer_journaled(bh) ? ' ' : '!',
 			buffer_journal_dirty(bh) ? ' ' : '!');
     }
-    run_task_queue(&tq_disk);
+    blk_run_queues();
     yield();
   }
   if (repeat_counter > 30000000) {
diff -Nru a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
--- a/fs/reiserfs/journal.c	Wed May 29 11:43:01 2002
+++ b/fs/reiserfs/journal.c	Wed May 29 11:43:01 2002
@@ -1888,7 +1888,6 @@
   spin_unlock_irq(&current->sigmask_lock);
 
   sprintf(current->comm, "kreiserfsd") ;
-  current->flags |= PF_KERNTHREAD;
   lock_kernel() ;
   while(1) {
 
diff -Nru a/fs/vfat/namei.c b/fs/vfat/namei.c
--- a/fs/vfat/namei.c	Wed May 29 11:43:03 2002
+++ b/fs/vfat/namei.c	Wed May 29 11:43:03 2002
@@ -1021,16 +1021,12 @@
 	unlock_kernel();
 	dentry->d_op = &vfat_dentry_ops[table];
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
-	if (inode) {
-		dentry = d_splice_alias(inode, dentry);
-		if (dentry) {
-			dentry->d_op = &vfat_dentry_ops[table];
-			dentry->d_time = dentry->d_parent->d_inode->i_version;
-		}
-		return dentry;
+	dentry = d_splice_alias(inode, dentry);
+	if (dentry) {
+		dentry->d_op = &vfat_dentry_ops[table];
+		dentry->d_time = dentry->d_parent->d_inode->i_version;
 	}
-	d_add(dentry,inode);
-	return NULL;
+	return dentry;
 }
 
 int vfat_create(struct inode *dir,struct dentry* dentry,int mode)
diff -Nru a/include/asm-alpha/errno.h b/include/asm-alpha/errno.h
--- a/include/asm-alpha/errno.h	Wed May 29 11:43:02 2002
+++ b/include/asm-alpha/errno.h	Wed May 29 11:43:02 2002
@@ -1,40 +1,12 @@
 #ifndef _ALPHA_ERRNO_H
 #define _ALPHA_ERRNO_H
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
+#include <asm-generic/errno-base.h>
+
+#undef	EAGAIN			/* 11 in errno-base.h */
+
 #define	EDEADLK		11	/* Resource deadlock would occur */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
+
 #define	EAGAIN		35	/* Try again */
 #define	EWOULDBLOCK	EAGAIN	/* Operation would block */
 #define	EINPROGRESS	36	/* Operation now in progress */
diff -Nru a/include/asm-alpha/ide.h b/include/asm-alpha/ide.h
--- a/include/asm-alpha/ide.h	Wed May 29 11:43:02 2002
+++ b/include/asm-alpha/ide.h	Wed May 29 11:43:02 2002
@@ -77,7 +77,7 @@
 	for (index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 #endif
 }
diff -Nru a/include/asm-alpha/siginfo.h b/include/asm-alpha/siginfo.h
--- a/include/asm-alpha/siginfo.h	Wed May 29 11:43:02 2002
+++ b/include/asm-alpha/siginfo.h	Wed May 29 11:43:02 2002
@@ -1,219 +1,13 @@
 #ifndef _ALPHA_SIGINFO_H
 #define _ALPHA_SIGINFO_H
 
-#include <linux/types.h>
-
-/* This structure matches OSF/1 for binary compatibility. */
-
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
 #define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 4)
 
-typedef struct siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE];
-
-		/* kill() */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
-			int _status;		/* exit code */
-			clock_t _utime;
-			clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-		struct {
-			void *_addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} siginfo_t;
-
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
-
-/*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
-#define SI_TKILL	-6		/* sent by tkill system call */
-#define SI_DETHREAD	-7		/* sent by execve() killing subsidiary threads */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
-
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
 #define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
 
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
+#define HAVE_ARCH_COPY_SIGINFO
 
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
+#include <asm-generic/siginfo.h>
 
 #ifdef __KERNEL__
 #include <linux/string.h>
@@ -226,8 +20,6 @@
 		/* _sigchld is currently the largest know union member */
 		memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigchld));
 }
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/asm-alpha/signal.h b/include/asm-alpha/signal.h
--- a/include/asm-alpha/signal.h	Wed May 29 11:43:03 2002
+++ b/include/asm-alpha/signal.h	Wed May 29 11:43:03 2002
@@ -185,6 +185,9 @@
 
 #ifdef __KERNEL__
 #include <asm/sigcontext.h>
+
+#define HAVE_ARCH_GET_SIGNAL_TO_DELIVER
+
 #endif
 
 #endif
diff -Nru a/include/asm-arm/arch-anakin/ide.h b/include/asm-arm/arch-anakin/ide.h
--- a/include/asm-arm/arch-anakin/ide.h	Wed May 29 11:43:01 2002
+++ b/include/asm-arm/arch-anakin/ide.h	Wed May 29 11:43:01 2002
@@ -29,9 +29,9 @@
 		hw->io_ports[i] = reg;
 		reg += regincr;
 	}
-	
+
 	hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
-	
+
 	if (irq)
 		*irq = 0;
 }
@@ -46,10 +46,10 @@
 {
     hw_regs_t hw;
 
-    ide_init_hwif_ports(&hw, IO_BASE + COMPACTFLASH, 
-    			IO_BASE + COMPACTFLASH + IDE_CONTROL_OFFSET, NULL);
+    ide_init_hwif_ports(&hw, IO_BASE + COMPACTFLASH,
+			IO_BASE + COMPACTFLASH + IDE_CONTROL_OFFSET, NULL);
     hw.irq = IRQ_COMPACTFLASH;
-    ide_register_hw(&hw, NULL);
+    ide_register_hw(&hw);
 }
 
 
diff -Nru a/include/asm-arm/arch-arc/ide.h b/include/asm-arm/arch-arc/ide.h
--- a/include/asm-arm/arch-arc/ide.h	Wed May 29 11:43:02 2002
+++ b/include/asm-arm/arch-arc/ide.h	Wed May 29 11:43:02 2002
@@ -50,6 +50,6 @@
 
 		ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
 		hw.irq = IRQ_HARDDISK;
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 }
diff -Nru a/include/asm-arm/arch-cl7500/ide.h b/include/asm-arm/arch-cl7500/ide.h
--- a/include/asm-arm/arch-cl7500/ide.h	Wed May 29 11:43:03 2002
+++ b/include/asm-arm/arch-cl7500/ide.h	Wed May 29 11:43:03 2002
@@ -43,8 +43,8 @@
 ide_init_default_hwifs(void)
 {
 	hw_regs_t hw;
-   
+
 	ide_init_hwif_ports(&hw, ISASLOT_IO + 0x1f0, ISASLOT_IO + 0x3f6, NULL);
-   	hw.irq = IRQ_ISA_14;
-	ide_register_hw(&hw, NULL);
+	hw.irq = IRQ_ISA_14;
+	ide_register_hw(&hw);
 }
diff -Nru a/include/asm-arm/arch-ebsa285/ide.h b/include/asm-arm/arch-ebsa285/ide.h
--- a/include/asm-arm/arch-ebsa285/ide.h	Wed May 29 11:43:03 2002
+++ b/include/asm-arm/arch-ebsa285/ide.h	Wed May 29 11:43:03 2002
@@ -44,6 +44,6 @@
 
 	ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
 	hw.irq = IRQ_HARDDISK;
-	ide_register_hw(&hw, NULL);
+	ide_register_hw(&hw);
 #endif
 }
diff -Nru a/include/asm-arm/arch-rpc/ide.h b/include/asm-arm/arch-rpc/ide.h
--- a/include/asm-arm/arch-rpc/ide.h	Wed May 29 11:43:02 2002
+++ b/include/asm-arm/arch-rpc/ide.h	Wed May 29 11:43:02 2002
@@ -44,5 +44,5 @@
 
 	ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
 	hw.irq = IRQ_HARDDISK;
-	ide_register_hw(&hw, NULL);
+	ide_register_hw(&hw);
 }
diff -Nru a/include/asm-arm/arch-sa1100/ide.h b/include/asm-arm/arch-sa1100/ide.h
--- a/include/asm-arm/arch-sa1100/ide.h	Wed May 29 11:43:01 2002
+++ b/include/asm-arm/arch-sa1100/ide.h	Wed May 29 11:43:01 2002
@@ -84,10 +84,10 @@
 	   doesn't match the silkscreen however. */
 	ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x40, PCMCIA_IO_0_BASE + 0x78, NULL);
 	hw.irq = EMPEG_IRQ_IDE2;
-	ide_register_hw(&hw, NULL);
+	ide_register_hw(&hw);
 	ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x00, PCMCIA_IO_0_BASE + 0x38, NULL);
 	hw.irq = ,EMPEG_IRQ_IDE1;
-	ide_register_hw(&hw, NULL);
+	ide_register_hw(&hw);
 #endif
     }
 
@@ -104,7 +104,7 @@
 
 	ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x1f0, PCMCIA_IO_0_BASE + 0x3f6, NULL);
 	hw.irq = IRQ_GPIO7;
-	ide_register_hw(&hw, NULL);
+	ide_register_hw(&hw);
 #endif
     }
     else if (machine_is_lart()) {
@@ -114,14 +114,14 @@
         /* Enable GPIO as interrupt line */
         GPDR &= ~LART_GPIO_IDE;
 	set_irq_type(LART_IRQ_IDE, IRQT_RISING);
-        
+
         /* set PCMCIA interface timing */
         MECR = 0x00060006;
 
         /* init the interface */
 	ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x0000, PCMCIA_IO_0_BASE + 0x1000, NULL);
         hw.irq = LART_IRQ_IDE;
-        ide_register_hw(&hw, NULL);
+        ide_register_hw(&hw);
 #endif
     }
 }
diff -Nru a/include/asm-arm/arch-shark/ide.h b/include/asm-arm/arch-shark/ide.h
--- a/include/asm-arm/arch-shark/ide.h	Wed May 29 11:43:03 2002
+++ b/include/asm-arm/arch-shark/ide.h	Wed May 29 11:43:03 2002
@@ -42,6 +42,6 @@
 
 	ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
 	hw.irq = 14;
-	ide_register_hw(&hw, NULL);
+	ide_register_hw(&hw);
 }
 
diff -Nru a/include/asm-arm/errno.h b/include/asm-arm/errno.h
--- a/include/asm-arm/errno.h	Wed May 29 11:43:02 2002
+++ b/include/asm-arm/errno.h	Wed May 29 11:43:02 2002
@@ -1,132 +1,6 @@
 #ifndef _ARM_ERRNO_H
 #define _ARM_ERRNO_H
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
-#define	EDEADLK		35	/* Resource deadlock would occur */
-#define	ENAMETOOLONG	36	/* File name too long */
-#define	ENOLCK		37	/* No record locks available */
-#define	ENOSYS		38	/* Function not implemented */
-#define	ENOTEMPTY	39	/* Directory not empty */
-#define	ELOOP		40	/* Too many symbolic links encountered */
-#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
-#define	ENOMSG		42	/* No message of desired type */
-#define	EIDRM		43	/* Identifier removed */
-#define	ECHRNG		44	/* Channel number out of range */
-#define	EL2NSYNC	45	/* Level 2 not synchronized */
-#define	EL3HLT		46	/* Level 3 halted */
-#define	EL3RST		47	/* Level 3 reset */
-#define	ELNRNG		48	/* Link number out of range */
-#define	EUNATCH		49	/* Protocol driver not attached */
-#define	ENOCSI		50	/* No CSI structure available */
-#define	EL2HLT		51	/* Level 2 halted */
-#define	EBADE		52	/* Invalid exchange */
-#define	EBADR		53	/* Invalid request descriptor */
-#define	EXFULL		54	/* Exchange full */
-#define	ENOANO		55	/* No anode */
-#define	EBADRQC		56	/* Invalid request code */
-#define	EBADSLT		57	/* Invalid slot */
-
-#define	EDEADLOCK	EDEADLK
-
-#define	EBFONT		59	/* Bad font file format */
-#define	ENOSTR		60	/* Device not a stream */
-#define	ENODATA		61	/* No data available */
-#define	ETIME		62	/* Timer expired */
-#define	ENOSR		63	/* Out of streams resources */
-#define	ENONET		64	/* Machine is not on the network */
-#define	ENOPKG		65	/* Package not installed */
-#define	EREMOTE		66	/* Object is remote */
-#define	ENOLINK		67	/* Link has been severed */
-#define	EADV		68	/* Advertise error */
-#define	ESRMNT		69	/* Srmount error */
-#define	ECOMM		70	/* Communication error on send */
-#define	EPROTO		71	/* Protocol error */
-#define	EMULTIHOP	72	/* Multihop attempted */
-#define	EDOTDOT		73	/* RFS specific error */
-#define	EBADMSG		74	/* Not a data message */
-#define	EOVERFLOW	75	/* Value too large for defined data type */
-#define	ENOTUNIQ	76	/* Name not unique on network */
-#define	EBADFD		77	/* File descriptor in bad state */
-#define	EREMCHG		78	/* Remote address changed */
-#define	ELIBACC		79	/* Can not access a needed shared library */
-#define	ELIBBAD		80	/* Accessing a corrupted shared library */
-#define	ELIBSCN		81	/* .lib section in a.out corrupted */
-#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
-#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
-#define	EILSEQ		84	/* Illegal byte sequence */
-#define	ERESTART	85	/* Interrupted system call should be restarted */
-#define	ESTRPIPE	86	/* Streams pipe error */
-#define	EUSERS		87	/* Too many users */
-#define	ENOTSOCK	88	/* Socket operation on non-socket */
-#define	EDESTADDRREQ	89	/* Destination address required */
-#define	EMSGSIZE	90	/* Message too long */
-#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
-#define	ENOPROTOOPT	92	/* Protocol not available */
-#define	EPROTONOSUPPORT	93	/* Protocol not supported */
-#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
-#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
-#define	EPFNOSUPPORT	96	/* Protocol family not supported */
-#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
-#define	EADDRINUSE	98	/* Address already in use */
-#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
-#define	ENETDOWN	100	/* Network is down */
-#define	ENETUNREACH	101	/* Network is unreachable */
-#define	ENETRESET	102	/* Network dropped connection because of reset */
-#define	ECONNABORTED	103	/* Software caused connection abort */
-#define	ECONNRESET	104	/* Connection reset by peer */
-#define	ENOBUFS		105	/* No buffer space available */
-#define	EISCONN		106	/* Transport endpoint is already connected */
-#define	ENOTCONN	107	/* Transport endpoint is not connected */
-#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
-#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
-#define	ETIMEDOUT	110	/* Connection timed out */
-#define	ECONNREFUSED	111	/* Connection refused */
-#define	EHOSTDOWN	112	/* Host is down */
-#define	EHOSTUNREACH	113	/* No route to host */
-#define	EALREADY	114	/* Operation already in progress */
-#define	EINPROGRESS	115	/* Operation now in progress */
-#define	ESTALE		116	/* Stale NFS file handle */
-#define	EUCLEAN		117	/* Structure needs cleaning */
-#define	ENOTNAM		118	/* Not a XENIX named type file */
-#define	ENAVAIL		119	/* No XENIX semaphores available */
-#define	EISNAM		120	/* Is a named type file */
-#define	EREMOTEIO	121	/* Remote I/O error */
-#define	EDQUOT		122	/* Quota exceeded */
-
-#define	ENOMEDIUM	123	/* No medium found */
-#define	EMEDIUMTYPE	124	/* Wrong medium type */
+#include <asm-generic/errno.h>
 
 #endif
diff -Nru a/include/asm-arm/siginfo.h b/include/asm-arm/siginfo.h
--- a/include/asm-arm/siginfo.h	Wed May 29 11:43:01 2002
+++ b/include/asm-arm/siginfo.h	Wed May 29 11:43:01 2002
@@ -1,234 +1,6 @@
 #ifndef _ASMARM_SIGINFO_H
 #define _ASMARM_SIGINFO_H
 
-#include <linux/types.h>
-
-/* XXX: This structure was copied from the Alpha; is there an iBCS version?  */
-
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE];
-
-		/* kill() */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
-			int _status;		/* exit code */
-			clock_t _utime;
-			clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-		struct {
-			void *_addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} siginfo_t;
-
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
-
-/*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
-#define SI_TKILL	-6		/* sent by tkill system call */
-#define SI_DETHREAD	-7		/* sent by execve() killing subsidiary threads */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
-
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-static inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
-#endif /* __KERNEL__ */
+#include <asm-generic/siginfo.h>
 
 #endif
diff -Nru a/include/asm-arm/signal.h b/include/asm-arm/signal.h
--- a/include/asm-arm/signal.h	Wed May 29 11:43:03 2002
+++ b/include/asm-arm/signal.h	Wed May 29 11:43:03 2002
@@ -187,6 +187,8 @@
 
 #define sigmask(sig)	(1UL << ((sig) - 1))
 
+#define HAVE_ARCH_GET_SIGNAL_TO_DELIVER
+
 #endif
 
 #endif
diff -Nru a/include/asm-cris/errno.h b/include/asm-cris/errno.h
--- a/include/asm-cris/errno.h	Wed May 29 11:43:02 2002
+++ b/include/asm-cris/errno.h	Wed May 29 11:43:02 2002
@@ -1,134 +1,6 @@
-/* verbatim copy of asm-i386/errno.h */
-
 #ifndef _CRIS_ERRNO_H
 #define _CRIS_ERRNO_H
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
-#define	EDEADLK		35	/* Resource deadlock would occur */
-#define	ENAMETOOLONG	36	/* File name too long */
-#define	ENOLCK		37	/* No record locks available */
-#define	ENOSYS		38	/* Function not implemented */
-#define	ENOTEMPTY	39	/* Directory not empty */
-#define	ELOOP		40	/* Too many symbolic links encountered */
-#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
-#define	ENOMSG		42	/* No message of desired type */
-#define	EIDRM		43	/* Identifier removed */
-#define	ECHRNG		44	/* Channel number out of range */
-#define	EL2NSYNC	45	/* Level 2 not synchronized */
-#define	EL3HLT		46	/* Level 3 halted */
-#define	EL3RST		47	/* Level 3 reset */
-#define	ELNRNG		48	/* Link number out of range */
-#define	EUNATCH		49	/* Protocol driver not attached */
-#define	ENOCSI		50	/* No CSI structure available */
-#define	EL2HLT		51	/* Level 2 halted */
-#define	EBADE		52	/* Invalid exchange */
-#define	EBADR		53	/* Invalid request descriptor */
-#define	EXFULL		54	/* Exchange full */
-#define	ENOANO		55	/* No anode */
-#define	EBADRQC		56	/* Invalid request code */
-#define	EBADSLT		57	/* Invalid slot */
-
-#define	EDEADLOCK	EDEADLK
-
-#define	EBFONT		59	/* Bad font file format */
-#define	ENOSTR		60	/* Device not a stream */
-#define	ENODATA		61	/* No data available */
-#define	ETIME		62	/* Timer expired */
-#define	ENOSR		63	/* Out of streams resources */
-#define	ENONET		64	/* Machine is not on the network */
-#define	ENOPKG		65	/* Package not installed */
-#define	EREMOTE		66	/* Object is remote */
-#define	ENOLINK		67	/* Link has been severed */
-#define	EADV		68	/* Advertise error */
-#define	ESRMNT		69	/* Srmount error */
-#define	ECOMM		70	/* Communication error on send */
-#define	EPROTO		71	/* Protocol error */
-#define	EMULTIHOP	72	/* Multihop attempted */
-#define	EDOTDOT		73	/* RFS specific error */
-#define	EBADMSG		74	/* Not a data message */
-#define	EOVERFLOW	75	/* Value too large for defined data type */
-#define	ENOTUNIQ	76	/* Name not unique on network */
-#define	EBADFD		77	/* File descriptor in bad state */
-#define	EREMCHG		78	/* Remote address changed */
-#define	ELIBACC		79	/* Can not access a needed shared library */
-#define	ELIBBAD		80	/* Accessing a corrupted shared library */
-#define	ELIBSCN		81	/* .lib section in a.out corrupted */
-#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
-#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
-#define	EILSEQ		84	/* Illegal byte sequence */
-#define	ERESTART	85	/* Interrupted system call should be restarted */
-#define	ESTRPIPE	86	/* Streams pipe error */
-#define	EUSERS		87	/* Too many users */
-#define	ENOTSOCK	88	/* Socket operation on non-socket */
-#define	EDESTADDRREQ	89	/* Destination address required */
-#define	EMSGSIZE	90	/* Message too long */
-#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
-#define	ENOPROTOOPT	92	/* Protocol not available */
-#define	EPROTONOSUPPORT	93	/* Protocol not supported */
-#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
-#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
-#define	EPFNOSUPPORT	96	/* Protocol family not supported */
-#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
-#define	EADDRINUSE	98	/* Address already in use */
-#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
-#define	ENETDOWN	100	/* Network is down */
-#define	ENETUNREACH	101	/* Network is unreachable */
-#define	ENETRESET	102	/* Network dropped connection because of reset */
-#define	ECONNABORTED	103	/* Software caused connection abort */
-#define	ECONNRESET	104	/* Connection reset by peer */
-#define	ENOBUFS		105	/* No buffer space available */
-#define	EISCONN		106	/* Transport endpoint is already connected */
-#define	ENOTCONN	107	/* Transport endpoint is not connected */
-#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
-#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
-#define	ETIMEDOUT	110	/* Connection timed out */
-#define	ECONNREFUSED	111	/* Connection refused */
-#define	EHOSTDOWN	112	/* Host is down */
-#define	EHOSTUNREACH	113	/* No route to host */
-#define	EALREADY	114	/* Operation already in progress */
-#define	EINPROGRESS	115	/* Operation now in progress */
-#define	ESTALE		116	/* Stale NFS file handle */
-#define	EUCLEAN		117	/* Structure needs cleaning */
-#define	ENOTNAM		118	/* Not a XENIX named type file */
-#define	ENAVAIL		119	/* No XENIX semaphores available */
-#define	EISNAM		120	/* Is a named type file */
-#define	EREMOTEIO	121	/* Remote I/O error */
-#define	EDQUOT		122	/* Quota exceeded */
-
-#define	ENOMEDIUM	123	/* No medium found */
-#define	EMEDIUMTYPE	124	/* Wrong medium type */
+#include <asm-generic/errno.h>
 
 #endif
diff -Nru a/include/asm-cris/ide.h b/include/asm-cris/ide.h
--- a/include/asm-cris/ide.h	Wed May 29 11:43:02 2002
+++ b/include/asm-cris/ide.h	Wed May 29 11:43:02 2002
@@ -84,7 +84,7 @@
 	for(index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 }
 
diff -Nru a/include/asm-cris/siginfo.h b/include/asm-cris/siginfo.h
--- a/include/asm-cris/siginfo.h	Wed May 29 11:43:03 2002
+++ b/include/asm-cris/siginfo.h	Wed May 29 11:43:03 2002
@@ -1,233 +1,6 @@
 #ifndef _CRIS_SIGINFO_H
 #define _CRIS_SIGINFO_H
 
-#include <linux/types.h>
-
-/* This is copied from asm-m68k/siginfo.h.  */
-
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE];
-
-		/* kill() */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
-			int _status;		/* exit code */
-			clock_t _utime;
-			clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-		struct {
-			void *_addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} siginfo_t;
-
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
-
-/*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
-#define SI_TKILL	-6		/* sent by tkill system call */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
-
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
-#endif /* __KERNEL__ */
+#include <asm-generic/siginfo.h>
 
 #endif
diff -Nru a/include/asm-generic/errno-base.h b/include/asm-generic/errno-base.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-generic/errno-base.h	Wed May 29 11:43:03 2002
@@ -0,0 +1,39 @@
+#ifndef _ASM_GENERIC_ERRNO_BASE_H
+#define _ASM_GENERIC_ERRNO_BASE_H
+
+#define	EPERM		 1	/* Operation not permitted */
+#define	ENOENT		 2	/* No such file or directory */
+#define	ESRCH		 3	/* No such process */
+#define	EINTR		 4	/* Interrupted system call */
+#define	EIO		 5	/* I/O error */
+#define	ENXIO		 6	/* No such device or address */
+#define	E2BIG		 7	/* Argument list too long */
+#define	ENOEXEC		 8	/* Exec format error */
+#define	EBADF		 9	/* Bad file number */
+#define	ECHILD		10	/* No child processes */
+#define	EAGAIN		11	/* Try again */
+#define	ENOMEM		12	/* Out of memory */
+#define	EACCES		13	/* Permission denied */
+#define	EFAULT		14	/* Bad address */
+#define	ENOTBLK		15	/* Block device required */
+#define	EBUSY		16	/* Device or resource busy */
+#define	EEXIST		17	/* File exists */
+#define	EXDEV		18	/* Cross-device link */
+#define	ENODEV		19	/* No such device */
+#define	ENOTDIR		20	/* Not a directory */
+#define	EISDIR		21	/* Is a directory */
+#define	EINVAL		22	/* Invalid argument */
+#define	ENFILE		23	/* File table overflow */
+#define	EMFILE		24	/* Too many open files */
+#define	ENOTTY		25	/* Not a typewriter */
+#define	ETXTBSY		26	/* Text file busy */
+#define	EFBIG		27	/* File too large */
+#define	ENOSPC		28	/* No space left on device */
+#define	ESPIPE		29	/* Illegal seek */
+#define	EROFS		30	/* Read-only file system */
+#define	EMLINK		31	/* Too many links */
+#define	EPIPE		32	/* Broken pipe */
+#define	EDOM		33	/* Math argument out of domain of func */
+#define	ERANGE		34	/* Math result not representable */
+
+#endif
diff -Nru a/include/asm-generic/errno.h b/include/asm-generic/errno.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-generic/errno.h	Wed May 29 11:43:03 2002
@@ -0,0 +1,100 @@
+#ifndef _ASM_GENERIC_ERRNO_H
+#define _ASM_GENERIC_ERRNO_H
+
+#include <asm-generic/errno-base.h>
+
+#define	EDEADLK		35	/* Resource deadlock would occur */
+#define	ENAMETOOLONG	36	/* File name too long */
+#define	ENOLCK		37	/* No record locks available */
+#define	ENOSYS		38	/* Function not implemented */
+#define	ENOTEMPTY	39	/* Directory not empty */
+#define	ELOOP		40	/* Too many symbolic links encountered */
+#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
+#define	ENOMSG		42	/* No message of desired type */
+#define	EIDRM		43	/* Identifier removed */
+#define	ECHRNG		44	/* Channel number out of range */
+#define	EL2NSYNC	45	/* Level 2 not synchronized */
+#define	EL3HLT		46	/* Level 3 halted */
+#define	EL3RST		47	/* Level 3 reset */
+#define	ELNRNG		48	/* Link number out of range */
+#define	EUNATCH		49	/* Protocol driver not attached */
+#define	ENOCSI		50	/* No CSI structure available */
+#define	EL2HLT		51	/* Level 2 halted */
+#define	EBADE		52	/* Invalid exchange */
+#define	EBADR		53	/* Invalid request descriptor */
+#define	EXFULL		54	/* Exchange full */
+#define	ENOANO		55	/* No anode */
+#define	EBADRQC		56	/* Invalid request code */
+#define	EBADSLT		57	/* Invalid slot */
+
+#define	EDEADLOCK	EDEADLK
+
+#define	EBFONT		59	/* Bad font file format */
+#define	ENOSTR		60	/* Device not a stream */
+#define	ENODATA		61	/* No data available */
+#define	ETIME		62	/* Timer expired */
+#define	ENOSR		63	/* Out of streams resources */
+#define	ENONET		64	/* Machine is not on the network */
+#define	ENOPKG		65	/* Package not installed */
+#define	EREMOTE		66	/* Object is remote */
+#define	ENOLINK		67	/* Link has been severed */
+#define	EADV		68	/* Advertise error */
+#define	ESRMNT		69	/* Srmount error */
+#define	ECOMM		70	/* Communication error on send */
+#define	EPROTO		71	/* Protocol error */
+#define	EMULTIHOP	72	/* Multihop attempted */
+#define	EDOTDOT		73	/* RFS specific error */
+#define	EBADMSG		74	/* Not a data message */
+#define	EOVERFLOW	75	/* Value too large for defined data type */
+#define	ENOTUNIQ	76	/* Name not unique on network */
+#define	EBADFD		77	/* File descriptor in bad state */
+#define	EREMCHG		78	/* Remote address changed */
+#define	ELIBACC		79	/* Can not access a needed shared library */
+#define	ELIBBAD		80	/* Accessing a corrupted shared library */
+#define	ELIBSCN		81	/* .lib section in a.out corrupted */
+#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
+#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
+#define	EILSEQ		84	/* Illegal byte sequence */
+#define	ERESTART	85	/* Interrupted system call should be restarted */
+#define	ESTRPIPE	86	/* Streams pipe error */
+#define	EUSERS		87	/* Too many users */
+#define	ENOTSOCK	88	/* Socket operation on non-socket */
+#define	EDESTADDRREQ	89	/* Destination address required */
+#define	EMSGSIZE	90	/* Message too long */
+#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
+#define	ENOPROTOOPT	92	/* Protocol not available */
+#define	EPROTONOSUPPORT	93	/* Protocol not supported */
+#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
+#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
+#define	EPFNOSUPPORT	96	/* Protocol family not supported */
+#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
+#define	EADDRINUSE	98	/* Address already in use */
+#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
+#define	ENETDOWN	100	/* Network is down */
+#define	ENETUNREACH	101	/* Network is unreachable */
+#define	ENETRESET	102	/* Network dropped connection because of reset */
+#define	ECONNABORTED	103	/* Software caused connection abort */
+#define	ECONNRESET	104	/* Connection reset by peer */
+#define	ENOBUFS		105	/* No buffer space available */
+#define	EISCONN		106	/* Transport endpoint is already connected */
+#define	ENOTCONN	107	/* Transport endpoint is not connected */
+#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
+#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
+#define	ETIMEDOUT	110	/* Connection timed out */
+#define	ECONNREFUSED	111	/* Connection refused */
+#define	EHOSTDOWN	112	/* Host is down */
+#define	EHOSTUNREACH	113	/* No route to host */
+#define	EALREADY	114	/* Operation already in progress */
+#define	EINPROGRESS	115	/* Operation now in progress */
+#define	ESTALE		116	/* Stale NFS file handle */
+#define	EUCLEAN		117	/* Structure needs cleaning */
+#define	ENOTNAM		118	/* Not a XENIX named type file */
+#define	ENAVAIL		119	/* No XENIX semaphores available */
+#define	EISNAM		120	/* Is a named type file */
+#define	EREMOTEIO	121	/* Remote I/O error */
+#define	EDQUOT		122	/* Quota exceeded */
+
+#define	ENOMEDIUM	123	/* No medium found */
+#define	EMEDIUMTYPE	124	/* Wrong medium type */
+
+#endif
diff -Nru a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-generic/siginfo.h	Wed May 29 11:43:03 2002
@@ -0,0 +1,254 @@
+#ifndef _ASM_GENERIC_SIGINFO_H
+#define _ASM_GENERIC_SIGINFO_H
+
+#include <linux/types.h>
+
+typedef union sigval {
+	int sival_int;
+	void *sival_ptr;
+} sigval_t;
+
+#define SI_MAX_SIZE	128
+#ifndef SI_PAD_SIZE
+#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
+#endif
+
+#ifndef HAVE_ARCH_SIGINFO_T
+
+typedef struct siginfo {
+	int si_signo;
+	int si_errno;
+	int si_code;
+
+	union {
+		int _pad[SI_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+			sigval_t _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
+			int _status;		/* exit code */
+			clock_t _utime;
+			clock_t _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			void *_addr; /* faulting insn/memory ref. */
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+	} _sifields;
+} siginfo_t;
+
+#endif
+
+/*
+ * How these fields are to be accessed.
+ */
+#define si_pid		_sifields._kill._pid
+#define si_uid		_sifields._kill._uid
+#define si_timer1	_sifields._timer._timer1
+#define si_timer2	_sifields._timer._timer2
+#define si_status	_sifields._sigchld._status
+#define si_utime	_sifields._sigchld._utime
+#define si_stime	_sifields._sigchld._stime
+#define si_value	_sifields._rt._sigval
+#define si_int		_sifields._rt._sigval.sival_int
+#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_addr		_sifields._sigfault._addr
+#define si_band		_sifields._sigpoll._band
+#define si_fd		_sifields._sigpoll._fd
+
+#ifdef __KERNEL__
+#define __SI_MASK	0xffff0000
+#define __SI_KILL	(0 << 16)
+#define __SI_TIMER	(1 << 16)
+#define __SI_POLL	(2 << 16)
+#define __SI_FAULT	(3 << 16)
+#define __SI_CHLD	(4 << 16)
+#define __SI_RT		(5 << 16)
+#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
+#else
+#define __SI_KILL	0
+#define __SI_TIMER	0
+#define __SI_POLL	0
+#define __SI_FAULT	0
+#define __SI_CHLD	0
+#define __SI_RT		0
+#define __SI_CODE(T,N)	(N)
+#endif
+
+/*
+ * si_code values
+ * Digital reserves positive values for kernel-generated signals.
+ */
+#define SI_USER		0		/* sent by kill, sigsend, raise */
+#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
+#define SI_QUEUE	-1		/* sent by sigqueue */
+#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
+#define SI_MESGQ	-3		/* sent by real time mesq state change */
+#define SI_ASYNCIO	-4		/* sent by AIO completion */
+#define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
+#define SI_DETHREAD	-7		/* sent by execve() killing subsidiary threads */
+
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+
+#ifndef HAVE_ARCH_SI_CODES
+/*
+ * SIGILL si_codes
+ */
+#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
+#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
+#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
+#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
+#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
+#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
+#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
+#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
+#define NSIGILL		8
+
+/*
+ * SIGFPE si_codes
+ */
+#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
+#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
+#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
+#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
+#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
+#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
+#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
+#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
+#define NSIGFPE		8
+
+/*
+ * SIGSEGV si_codes
+ */
+#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
+#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
+#define NSIGSEGV	2
+
+/*
+ * SIGBUS si_codes
+ */
+#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
+#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
+#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
+#define NSIGBUS		3
+
+/*
+ * SIGTRAP si_codes
+ */
+#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
+#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
+#define NSIGTRAP	2
+
+/*
+ * SIGCHLD si_codes
+ */
+#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
+#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
+#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
+#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
+#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
+#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
+#define NSIGCHLD	6
+
+/*
+ * SIGPOLL si_codes
+ */
+#define POLL_IN		(__SI_POLL|1)	/* data input available */
+#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
+#define POLL_MSG	(__SI_POLL|3)	/* input message available */
+#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
+#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
+#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
+#define NSIGPOLL	6
+
+#endif
+
+/*
+ * sigevent definitions
+ * 
+ * It seems likely that SIGEV_THREAD will have to be handled from 
+ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
+ * thread manager then catches and does the appropriate nonsense.
+ * However, everything is written out here so as to not get lost.
+ */
+#define SIGEV_SIGNAL	0	/* notify via signal */
+#define SIGEV_NONE	1	/* other notification: meaningless */
+#define SIGEV_THREAD	2	/* deliver via thread creation */
+
+#define SIGEV_MAX_SIZE	64
+#ifndef SIGEV_PAD_SIZE
+#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
+#endif
+
+#ifndef HAVE_ARCH_SIGEVENT_T
+
+typedef struct sigevent {
+	sigval_t sigev_value;
+	int sigev_signo;
+	int sigev_notify;
+	union {
+		int _pad[SIGEV_PAD_SIZE];
+
+		struct {
+			void (*_function)(sigval_t);
+			void *_attribute;	/* really pthread_attr_t */
+		} _sigev_thread;
+	} _sigev_un;
+} sigevent_t;
+
+#endif
+
+#define sigev_notify_function	_sigev_un._sigev_thread._function
+#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
+
+#ifdef __KERNEL__
+
+#ifndef HAVE_ARCH_COPY_SIGINFO
+
+#include <linux/string.h>
+
+static inline void copy_siginfo(struct siginfo *to, struct siginfo *from)
+{
+	if (from->si_code < 0)
+		memcpy(to, from, sizeof(*to));
+	else
+		/* _sigchld is currently the largest know union member */
+		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
+}
+
+#endif
+
+extern int copy_siginfo_to_user(struct siginfo *to, struct siginfo *from);
+
+#endif /* __KERNEL__ */
+
+#endif
diff -Nru a/include/asm-i386/errno.h b/include/asm-i386/errno.h
--- a/include/asm-i386/errno.h	Wed May 29 11:43:02 2002
+++ b/include/asm-i386/errno.h	Wed May 29 11:43:02 2002
@@ -1,132 +1,6 @@
 #ifndef _I386_ERRNO_H
 #define _I386_ERRNO_H
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Argument list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
-#define	EDEADLK		35	/* Resource deadlock would occur */
-#define	ENAMETOOLONG	36	/* File name too long */
-#define	ENOLCK		37	/* No record locks available */
-#define	ENOSYS		38	/* Function not implemented */
-#define	ENOTEMPTY	39	/* Directory not empty */
-#define	ELOOP		40	/* Too many symbolic links encountered */
-#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
-#define	ENOMSG		42	/* No message of desired type */
-#define	EIDRM		43	/* Identifier removed */
-#define	ECHRNG		44	/* Channel number out of range */
-#define	EL2NSYNC	45	/* Level 2 not synchronized */
-#define	EL3HLT		46	/* Level 3 halted */
-#define	EL3RST		47	/* Level 3 reset */
-#define	ELNRNG		48	/* Link number out of range */
-#define	EUNATCH		49	/* Protocol driver not attached */
-#define	ENOCSI		50	/* No CSI structure available */
-#define	EL2HLT		51	/* Level 2 halted */
-#define	EBADE		52	/* Invalid exchange */
-#define	EBADR		53	/* Invalid request descriptor */
-#define	EXFULL		54	/* Exchange full */
-#define	ENOANO		55	/* No anode */
-#define	EBADRQC		56	/* Invalid request code */
-#define	EBADSLT		57	/* Invalid slot */
-
-#define	EDEADLOCK	EDEADLK
-
-#define	EBFONT		59	/* Bad font file format */
-#define	ENOSTR		60	/* Device not a stream */
-#define	ENODATA		61	/* No data available */
-#define	ETIME		62	/* Timer expired */
-#define	ENOSR		63	/* Out of streams resources */
-#define	ENONET		64	/* Machine is not on the network */
-#define	ENOPKG		65	/* Package not installed */
-#define	EREMOTE		66	/* Object is remote */
-#define	ENOLINK		67	/* Link has been severed */
-#define	EADV		68	/* Advertise error */
-#define	ESRMNT		69	/* Srmount error */
-#define	ECOMM		70	/* Communication error on send */
-#define	EPROTO		71	/* Protocol error */
-#define	EMULTIHOP	72	/* Multihop attempted */
-#define	EDOTDOT		73	/* RFS specific error */
-#define	EBADMSG		74	/* Not a data message */
-#define	EOVERFLOW	75	/* Value too large for defined data type */
-#define	ENOTUNIQ	76	/* Name not unique on network */
-#define	EBADFD		77	/* File descriptor in bad state */
-#define	EREMCHG		78	/* Remote address changed */
-#define	ELIBACC		79	/* Can not access a needed shared library */
-#define	ELIBBAD		80	/* Accessing a corrupted shared library */
-#define	ELIBSCN		81	/* .lib section in a.out corrupted */
-#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
-#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
-#define	EILSEQ		84	/* Illegal byte sequence */
-#define	ERESTART	85	/* Interrupted system call should be restarted */
-#define	ESTRPIPE	86	/* Streams pipe error */
-#define	EUSERS		87	/* Too many users */
-#define	ENOTSOCK	88	/* Socket operation on non-socket */
-#define	EDESTADDRREQ	89	/* Destination address required */
-#define	EMSGSIZE	90	/* Message too long */
-#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
-#define	ENOPROTOOPT	92	/* Protocol not available */
-#define	EPROTONOSUPPORT	93	/* Protocol not supported */
-#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
-#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
-#define	EPFNOSUPPORT	96	/* Protocol family not supported */
-#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
-#define	EADDRINUSE	98	/* Address already in use */
-#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
-#define	ENETDOWN	100	/* Network is down */
-#define	ENETUNREACH	101	/* Network is unreachable */
-#define	ENETRESET	102	/* Network dropped connection because of reset */
-#define	ECONNABORTED	103	/* Software caused connection abort */
-#define	ECONNRESET	104	/* Connection reset by peer */
-#define	ENOBUFS		105	/* No buffer space available */
-#define	EISCONN		106	/* Transport endpoint is already connected */
-#define	ENOTCONN	107	/* Transport endpoint is not connected */
-#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
-#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
-#define	ETIMEDOUT	110	/* Connection timed out */
-#define	ECONNREFUSED	111	/* Connection refused */
-#define	EHOSTDOWN	112	/* Host is down */
-#define	EHOSTUNREACH	113	/* No route to host */
-#define	EALREADY	114	/* Operation already in progress */
-#define	EINPROGRESS	115	/* Operation now in progress */
-#define	ESTALE		116	/* Stale NFS file handle */
-#define	EUCLEAN		117	/* Structure needs cleaning */
-#define	ENOTNAM		118	/* Not a XENIX named type file */
-#define	ENAVAIL		119	/* No XENIX semaphores available */
-#define	EISNAM		120	/* Is a named type file */
-#define	EREMOTEIO	121	/* Remote I/O error */
-#define	EDQUOT		122	/* Quota exceeded */
-
-#define	ENOMEDIUM	123	/* No medium found */
-#define	EMEDIUMTYPE	124	/* Wrong medium type */
+#include <asm-generic/errno.h>
 
 #endif
diff -Nru a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
--- a/include/asm-i386/hw_irq.h	Wed May 29 11:43:03 2002
+++ b/include/asm-i386/hw_irq.h	Wed May 29 11:43:03 2002
@@ -28,6 +28,7 @@
 
 extern void (*interrupt[NR_IRQS])(void);
 
+extern asmlinkage void thermal_interrupt(void);
 extern asmlinkage void smp_thermal_interrupt(struct pt_regs);
 
 #ifdef CONFIG_SMP
diff -Nru a/include/asm-i386/ide.h b/include/asm-i386/ide.h
--- a/include/asm-i386/ide.h	Wed May 29 11:43:01 2002
+++ b/include/asm-i386/ide.h	Wed May 29 11:43:01 2002
@@ -41,16 +41,9 @@
 
 static __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
-	switch (index) {
-		case 0:	return 0x1f0;
-		case 1:	return 0x170;
-		case 2: return 0x1e8;
-		case 3: return 0x168;
-		case 4: return 0x1e0;
-		case 5: return 0x160;
-		default:
-			return 0;
-	}
+	static unsigned long ata_io_base[MAX_HWIFS] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
+
+	return ata_io_base[index];
 }
 
 static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
@@ -81,7 +74,7 @@
 	for(index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 #endif
 }
diff -Nru a/include/asm-i386/pgtable-2level.h b/include/asm-i386/pgtable-2level.h
--- a/include/asm-i386/pgtable-2level.h	Wed May 29 11:43:01 2002
+++ b/include/asm-i386/pgtable-2level.h	Wed May 29 11:43:01 2002
@@ -60,5 +60,6 @@
 #define pte_none(x)		(!(x).pte_low)
 #define pte_pfn(x)		((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
 #define pfn_pte(pfn, prot)	__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pfn_pmd(pfn, prot)	__pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
 
 #endif /* _I386_PGTABLE_2LEVEL_H */
diff -Nru a/include/asm-i386/pgtable-3level.h b/include/asm-i386/pgtable-3level.h
--- a/include/asm-i386/pgtable-3level.h	Wed May 29 11:43:03 2002
+++ b/include/asm-i386/pgtable-3level.h	Wed May 29 11:43:03 2002
@@ -99,4 +99,9 @@
 	return pte;
 }
 
+static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
+{
+	return __pmd(((unsigned long long)page_nr << PAGE_SHIFT) | pgprot_val(pgprot));
+}
+
 #endif /* _I386_PGTABLE_3LEVEL_H */
diff -Nru a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
--- a/include/asm-i386/pgtable.h	Wed May 29 11:43:03 2002
+++ b/include/asm-i386/pgtable.h	Wed May 29 11:43:03 2002
@@ -132,27 +132,18 @@
 #define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 
-#define __PAGE_KERNEL \
+#define _PAGE_KERNEL \
 	(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-#define __PAGE_KERNEL_NOCACHE \
-	(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED)
-#define __PAGE_KERNEL_RO \
-	(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
 
-# define MAKE_GLOBAL(x)						\
-	({							\
-		pgprot_t __ret;					\
-								\
-		if (cpu_has_pge)				\
-			__ret = __pgprot((x) | _PAGE_GLOBAL);	\
-		else						\
-			__ret = __pgprot(x);			\
-		__ret;						\
-	})
+extern unsigned long __PAGE_KERNEL;
+#define __PAGE_KERNEL_RO	(__PAGE_KERNEL & ~_PAGE_RW)
+#define __PAGE_KERNEL_NOCACHE	(__PAGE_KERNEL | _PAGE_PCD)
+#define __PAGE_KERNEL_LARGE	(__PAGE_KERNEL | _PAGE_PSE)
 
-#define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL)
-#define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO)
-#define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
+#define PAGE_KERNEL		__pgprot(__PAGE_KERNEL)
+#define PAGE_KERNEL_RO		__pgprot(__PAGE_KERNEL_RO)
+#define PAGE_KERNEL_NOCACHE	__pgprot(__PAGE_KERNEL_NOCACHE)
+#define PAGE_KERNEL_LARGE	__pgprot(__PAGE_KERNEL_LARGE)
 
 /*
  * The i386 can't do page protection for execute, and considers that
diff -Nru a/include/asm-i386/siginfo.h b/include/asm-i386/siginfo.h
--- a/include/asm-i386/siginfo.h	Wed May 29 11:43:02 2002
+++ b/include/asm-i386/siginfo.h	Wed May 29 11:43:02 2002
@@ -1,234 +1,6 @@
 #ifndef _I386_SIGINFO_H
 #define _I386_SIGINFO_H
 
-#include <linux/types.h>
-
-/* XXX: This structure was copied from the Alpha; is there an iBCS version?  */
-
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE];
-
-		/* kill() */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
-			int _status;		/* exit code */
-			clock_t _utime;
-			clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-		struct {
-			void *_addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} siginfo_t;
-
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
-
-/*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
-#define SI_TKILL	-6		/* sent by tkill system call */
-#define SI_DETHREAD	-7		/* sent by execve() killing subsidiary threads */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
-
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-static inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
-#endif /* __KERNEL__ */
+#include <asm-generic/siginfo.h>
 
 #endif
diff -Nru a/include/asm-i386/suspend.h b/include/asm-i386/suspend.h
--- a/include/asm-i386/suspend.h	Wed May 29 11:43:02 2002
+++ b/include/asm-i386/suspend.h	Wed May 29 11:43:02 2002
@@ -1,13 +1,8 @@
-#ifndef __ASM_I386_SUSPEND_H
-#define __ASM_I386_SUSPEND_H
-#endif
-
 /*
  * Copyright 2001-2002 Pavel Machek <pavel@suse.cz>
  * Based on code
  * Copyright 2001 Patrick Mochel <mochel@osdl.org>
  */
-#if defined(SUSPEND_C) || defined(ACPI_C)
 #include <asm/desc.h>
 #include <asm/i387.h>
 
@@ -225,7 +220,6 @@
 	do_fpu_end();
 }
 
-#endif
 #ifdef SUSPEND_C
 /* Local variables for do_magic */
 static int loop __nosavedata = 0;
diff -Nru a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h
--- a/include/asm-ia64/bitops.h	Wed May 29 11:43:03 2002
+++ b/include/asm-ia64/bitops.h	Wed May 29 11:43:03 2002
@@ -326,6 +326,12 @@
 	return exp - 0xffff;
 }
 
+static int
+fls (int x)
+{
+	return ia64_fls((unsigned int) x);
+}
+
 /*
  * ffs: find first bit set. This is defined the same way as the libc and compiler builtin
  * ffs routines, therefore differs in spirit from the above ffz (man ffs): it operates on
diff -Nru a/include/asm-ia64/efi.h b/include/asm-ia64/efi.h
--- a/include/asm-ia64/efi.h	Wed May 29 11:43:03 2002
+++ b/include/asm-ia64/efi.h	Wed May 29 11:43:03 2002
@@ -7,9 +7,9 @@
  *
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999 Hewlett-Packard Co.
- * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 1999, 2002 Hewlett-Packard Co.
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *	Stephane Eranian <eranian@hpl.hp.com>
  */
 #include <linux/init.h>
 #include <linux/string.h>
@@ -258,8 +258,9 @@
 extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
 extern void efi_gettimeofday (struct timeval *tv);
 extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if possible */
-extern u64  efi_get_iobase (void);
-extern u32  efi_mem_type (u64 phys_addr);
+extern u64 efi_get_iobase (void);
+extern u32 efi_mem_type (unsigned long phys_addr);
+extern u64 efi_mem_attributes (unsigned long phys_addr);
 
 /*
  * Variable Attributes
diff -Nru a/include/asm-ia64/elf.h b/include/asm-ia64/elf.h
--- a/include/asm-ia64/elf.h	Wed May 29 11:43:03 2002
+++ b/include/asm-ia64/elf.h	Wed May 29 11:43:03 2002
@@ -38,7 +38,7 @@
  * the way of the program that it will "exec", and that there is
  * sufficient room for the brk.
  */
-#define ELF_ET_DYN_BASE		(TASK_UNMAPPED_BASE + 0x1000000)
+#define ELF_ET_DYN_BASE		(TASK_UNMAPPED_BASE + 0x800000000)
 
 
 /*
diff -Nru a/include/asm-ia64/errno.h b/include/asm-ia64/errno.h
--- a/include/asm-ia64/errno.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ia64/errno.h	Wed May 29 11:43:02 2002
@@ -8,132 +8,6 @@
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Argument list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
-#define	EDEADLK		35	/* Resource deadlock would occur */
-#define	ENAMETOOLONG	36	/* File name too long */
-#define	ENOLCK		37	/* No record locks available */
-#define	ENOSYS		38	/* Function not implemented */
-#define	ENOTEMPTY	39	/* Directory not empty */
-#define	ELOOP		40	/* Too many symbolic links encountered */
-#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
-#define	ENOMSG		42	/* No message of desired type */
-#define	EIDRM		43	/* Identifier removed */
-#define	ECHRNG		44	/* Channel number out of range */
-#define	EL2NSYNC	45	/* Level 2 not synchronized */
-#define	EL3HLT		46	/* Level 3 halted */
-#define	EL3RST		47	/* Level 3 reset */
-#define	ELNRNG		48	/* Link number out of range */
-#define	EUNATCH		49	/* Protocol driver not attached */
-#define	ENOCSI		50	/* No CSI structure available */
-#define	EL2HLT		51	/* Level 2 halted */
-#define	EBADE		52	/* Invalid exchange */
-#define	EBADR		53	/* Invalid request descriptor */
-#define	EXFULL		54	/* Exchange full */
-#define	ENOANO		55	/* No anode */
-#define	EBADRQC		56	/* Invalid request code */
-#define	EBADSLT		57	/* Invalid slot */
-
-#define	EDEADLOCK	EDEADLK
-
-#define	EBFONT		59	/* Bad font file format */
-#define	ENOSTR		60	/* Device not a stream */
-#define	ENODATA		61	/* No data available */
-#define	ETIME		62	/* Timer expired */
-#define	ENOSR		63	/* Out of streams resources */
-#define	ENONET		64	/* Machine is not on the network */
-#define	ENOPKG		65	/* Package not installed */
-#define	EREMOTE		66	/* Object is remote */
-#define	ENOLINK		67	/* Link has been severed */
-#define	EADV		68	/* Advertise error */
-#define	ESRMNT		69	/* Srmount error */
-#define	ECOMM		70	/* Communication error on send */
-#define	EPROTO		71	/* Protocol error */
-#define	EMULTIHOP	72	/* Multihop attempted */
-#define	EDOTDOT		73	/* RFS specific error */
-#define	EBADMSG		74	/* Not a data message */
-#define	EOVERFLOW	75	/* Value too large for defined data type */
-#define	ENOTUNIQ	76	/* Name not unique on network */
-#define	EBADFD		77	/* File descriptor in bad state */
-#define	EREMCHG		78	/* Remote address changed */
-#define	ELIBACC		79	/* Can not access a needed shared library */
-#define	ELIBBAD		80	/* Accessing a corrupted shared library */
-#define	ELIBSCN		81	/* .lib section in a.out corrupted */
-#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
-#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
-#define	EILSEQ		84	/* Illegal byte sequence */
-#define	ERESTART	85	/* Interrupted system call should be restarted */
-#define	ESTRPIPE	86	/* Streams pipe error */
-#define	EUSERS		87	/* Too many users */
-#define	ENOTSOCK	88	/* Socket operation on non-socket */
-#define	EDESTADDRREQ	89	/* Destination address required */
-#define	EMSGSIZE	90	/* Message too long */
-#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
-#define	ENOPROTOOPT	92	/* Protocol not available */
-#define	EPROTONOSUPPORT	93	/* Protocol not supported */
-#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
-#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
-#define	EPFNOSUPPORT	96	/* Protocol family not supported */
-#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
-#define	EADDRINUSE	98	/* Address already in use */
-#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
-#define	ENETDOWN	100	/* Network is down */
-#define	ENETUNREACH	101	/* Network is unreachable */
-#define	ENETRESET	102	/* Network dropped connection because of reset */
-#define	ECONNABORTED	103	/* Software caused connection abort */
-#define	ECONNRESET	104	/* Connection reset by peer */
-#define	ENOBUFS		105	/* No buffer space available */
-#define	EISCONN		106	/* Transport endpoint is already connected */
-#define	ENOTCONN	107	/* Transport endpoint is not connected */
-#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
-#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
-#define	ETIMEDOUT	110	/* Connection timed out */
-#define	ECONNREFUSED	111	/* Connection refused */
-#define	EHOSTDOWN	112	/* Host is down */
-#define	EHOSTUNREACH	113	/* No route to host */
-#define	EALREADY	114	/* Operation already in progress */
-#define	EINPROGRESS	115	/* Operation now in progress */
-#define	ESTALE		116	/* Stale NFS file handle */
-#define	EUCLEAN		117	/* Structure needs cleaning */
-#define	ENOTNAM		118	/* Not a XENIX named type file */
-#define	ENAVAIL		119	/* No XENIX semaphores available */
-#define	EISNAM		120	/* Is a named type file */
-#define	EREMOTEIO	121	/* Remote I/O error */
-#define	EDQUOT		122	/* Quota exceeded */
-
-#define	ENOMEDIUM	123	/* No medium found */
-#define	EMEDIUMTYPE	124	/* Wrong medium type */
+#include <asm-generic/errno.h>
 
 #endif /* _ASM_IA64_ERRNO_H */
diff -Nru a/include/asm-ia64/ide.h b/include/asm-ia64/ide.h
--- a/include/asm-ia64/ide.h	Wed May 29 11:43:03 2002
+++ b/include/asm-ia64/ide.h	Wed May 29 11:43:03 2002
@@ -87,7 +87,7 @@
 	for(index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 #endif
 }
diff -Nru a/include/asm-ia64/kregs.h b/include/asm-ia64/kregs.h
--- a/include/asm-ia64/kregs.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ia64/kregs.h	Wed May 29 11:43:02 2002
@@ -2,8 +2,8 @@
 #define _ASM_IA64_KREGS_H
 
 /*
- * Copyright (C) 2001 Hewlett-Packard Co
- * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2001-2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 /*
  * This file defines the kernel register usage convention used by Linux/ia64.
@@ -30,5 +30,122 @@
 #define IA64_TR_PALCODE		1	/* itr1: maps PALcode as required by EFI */
 #define IA64_TR_PERCPU_DATA	1	/* dtr1: percpu data */
 #define IA64_TR_CURRENT_STACK	2	/* dtr2: maps kernel's memory- & register-stacks */
+
+/* Processor status register bits: */
+#define IA64_PSR_BE_BIT		1
+#define IA64_PSR_UP_BIT		2
+#define IA64_PSR_AC_BIT		3
+#define IA64_PSR_MFL_BIT	4
+#define IA64_PSR_MFH_BIT	5
+#define IA64_PSR_IC_BIT		13
+#define IA64_PSR_I_BIT		14
+#define IA64_PSR_PK_BIT		15
+#define IA64_PSR_DT_BIT		17
+#define IA64_PSR_DFL_BIT	18
+#define IA64_PSR_DFH_BIT	19
+#define IA64_PSR_SP_BIT		20
+#define IA64_PSR_PP_BIT		21
+#define IA64_PSR_DI_BIT		22
+#define IA64_PSR_SI_BIT		23
+#define IA64_PSR_DB_BIT		24
+#define IA64_PSR_LP_BIT		25
+#define IA64_PSR_TB_BIT		26
+#define IA64_PSR_RT_BIT		27
+/* The following are not affected by save_flags()/restore_flags(): */
+#define IA64_PSR_CPL0_BIT	32
+#define IA64_PSR_CPL1_BIT	33
+#define IA64_PSR_IS_BIT		34
+#define IA64_PSR_MC_BIT		35
+#define IA64_PSR_IT_BIT		36
+#define IA64_PSR_ID_BIT		37
+#define IA64_PSR_DA_BIT		38
+#define IA64_PSR_DD_BIT		39
+#define IA64_PSR_SS_BIT		40
+#define IA64_PSR_RI_BIT		41
+#define IA64_PSR_ED_BIT		43
+#define IA64_PSR_BN_BIT		44
+
+#define IA64_PSR_BE	(__IA64_UL(1) << IA64_PSR_BE_BIT)
+#define IA64_PSR_UP	(__IA64_UL(1) << IA64_PSR_UP_BIT)
+#define IA64_PSR_AC	(__IA64_UL(1) << IA64_PSR_AC_BIT)
+#define IA64_PSR_MFL	(__IA64_UL(1) << IA64_PSR_MFL_BIT)
+#define IA64_PSR_MFH	(__IA64_UL(1) << IA64_PSR_MFH_BIT)
+#define IA64_PSR_IC	(__IA64_UL(1) << IA64_PSR_IC_BIT)
+#define IA64_PSR_I	(__IA64_UL(1) << IA64_PSR_I_BIT)
+#define IA64_PSR_PK	(__IA64_UL(1) << IA64_PSR_PK_BIT)
+#define IA64_PSR_DT	(__IA64_UL(1) << IA64_PSR_DT_BIT)
+#define IA64_PSR_DFL	(__IA64_UL(1) << IA64_PSR_DFL_BIT)
+#define IA64_PSR_DFH	(__IA64_UL(1) << IA64_PSR_DFH_BIT)
+#define IA64_PSR_SP	(__IA64_UL(1) << IA64_PSR_SP_BIT)
+#define IA64_PSR_PP	(__IA64_UL(1) << IA64_PSR_PP_BIT)
+#define IA64_PSR_DI	(__IA64_UL(1) << IA64_PSR_DI_BIT)
+#define IA64_PSR_SI	(__IA64_UL(1) << IA64_PSR_SI_BIT)
+#define IA64_PSR_DB	(__IA64_UL(1) << IA64_PSR_DB_BIT)
+#define IA64_PSR_LP	(__IA64_UL(1) << IA64_PSR_LP_BIT)
+#define IA64_PSR_TB	(__IA64_UL(1) << IA64_PSR_TB_BIT)
+#define IA64_PSR_RT	(__IA64_UL(1) << IA64_PSR_RT_BIT)
+/* The following are not affected by save_flags()/restore_flags(): */
+#define IA64_PSR_IS	(__IA64_UL(1) << IA64_PSR_IS_BIT)
+#define IA64_PSR_MC	(__IA64_UL(1) << IA64_PSR_MC_BIT)
+#define IA64_PSR_IT	(__IA64_UL(1) << IA64_PSR_IT_BIT)
+#define IA64_PSR_ID	(__IA64_UL(1) << IA64_PSR_ID_BIT)
+#define IA64_PSR_DA	(__IA64_UL(1) << IA64_PSR_DA_BIT)
+#define IA64_PSR_DD	(__IA64_UL(1) << IA64_PSR_DD_BIT)
+#define IA64_PSR_SS	(__IA64_UL(1) << IA64_PSR_SS_BIT)
+#define IA64_PSR_RI	(__IA64_UL(3) << IA64_PSR_RI_BIT)
+#define IA64_PSR_ED	(__IA64_UL(1) << IA64_PSR_ED_BIT)
+#define IA64_PSR_BN	(__IA64_UL(1) << IA64_PSR_BN_BIT)
+
+/* User mask bits: */
+#define IA64_PSR_UM	(IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL | IA64_PSR_MFH)
+
+/* Default Control Register */
+#define IA64_DCR_PP_BIT		 0	/* privileged performance monitor default */
+#define IA64_DCR_BE_BIT		 1	/* big-endian default */
+#define IA64_DCR_LC_BIT		 2	/* ia32 lock-check enable */
+#define IA64_DCR_DM_BIT		 8	/* defer TLB miss faults */
+#define IA64_DCR_DP_BIT		 9	/* defer page-not-present faults */
+#define IA64_DCR_DK_BIT		10	/* defer key miss faults */
+#define IA64_DCR_DX_BIT		11	/* defer key permission faults */
+#define IA64_DCR_DR_BIT		12	/* defer access right faults */
+#define IA64_DCR_DA_BIT		13	/* defer access bit faults */
+#define IA64_DCR_DD_BIT		14	/* defer debug faults */
+
+#define IA64_DCR_PP	(__IA64_UL(1) << IA64_DCR_PP_BIT)
+#define IA64_DCR_BE	(__IA64_UL(1) << IA64_DCR_BE_BIT)
+#define IA64_DCR_LC	(__IA64_UL(1) << IA64_DCR_LC_BIT)
+#define IA64_DCR_DM	(__IA64_UL(1) << IA64_DCR_DM_BIT)
+#define IA64_DCR_DP	(__IA64_UL(1) << IA64_DCR_DP_BIT)
+#define IA64_DCR_DK	(__IA64_UL(1) << IA64_DCR_DK_BIT)
+#define IA64_DCR_DX	(__IA64_UL(1) << IA64_DCR_DX_BIT)
+#define IA64_DCR_DR	(__IA64_UL(1) << IA64_DCR_DR_BIT)
+#define IA64_DCR_DA	(__IA64_UL(1) << IA64_DCR_DA_BIT)
+#define IA64_DCR_DD	(__IA64_UL(1) << IA64_DCR_DD_BIT)
+
+/* Interrupt Status Register */
+#define IA64_ISR_X_BIT		32	/* execute access */
+#define IA64_ISR_W_BIT		33	/* write access */
+#define IA64_ISR_R_BIT		34	/* read access */
+#define IA64_ISR_NA_BIT		35	/* non-access */
+#define IA64_ISR_SP_BIT		36	/* speculative load exception */
+#define IA64_ISR_RS_BIT		37	/* mandatory register-stack exception */
+#define IA64_ISR_IR_BIT		38	/* invalid register frame exception */
+#define IA64_ISR_CODE_MASK	0xf
+
+#define IA64_ISR_X	(__IA64_UL(1) << IA64_ISR_X_BIT)
+#define IA64_ISR_W	(__IA64_UL(1) << IA64_ISR_W_BIT)
+#define IA64_ISR_R	(__IA64_UL(1) << IA64_ISR_R_BIT)
+#define IA64_ISR_NA	(__IA64_UL(1) << IA64_ISR_NA_BIT)
+#define IA64_ISR_SP	(__IA64_UL(1) << IA64_ISR_SP_BIT)
+#define IA64_ISR_RS	(__IA64_UL(1) << IA64_ISR_RS_BIT)
+#define IA64_ISR_IR	(__IA64_UL(1) << IA64_ISR_IR_BIT)
+
+/* ISR code field for non-access instructions */
+#define IA64_ISR_CODE_TPA	0
+#define IA64_ISR_CODE_FC	1
+#define IA64_ISR_CODE_PROBE	2
+#define IA64_ISR_CODE_TAK	3
+#define IA64_ISR_CODE_LFETCH	4
+#define IA64_ISR_CODE_PROBEF	5
 
 #endif /* _ASM_IA64_kREGS_H */
diff -Nru a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
--- a/include/asm-ia64/machvec.h	Wed May 29 11:43:01 2002
+++ b/include/asm-ia64/machvec.h	Wed May 29 11:43:01 2002
@@ -18,6 +18,7 @@
 struct pt_regs;
 struct scatterlist;
 struct irq_desc;
+struct page;
 
 typedef void ia64_mv_setup_t (char **);
 typedef void ia64_mv_cpu_init_t(void);
@@ -45,6 +46,8 @@
 typedef void ia64_mv_pci_dma_sync_single (struct pci_dev *, dma_addr_t, size_t, int);
 typedef void ia64_mv_pci_dma_sync_sg (struct pci_dev *, struct scatterlist *, int, int);
 typedef unsigned long ia64_mv_pci_dma_address (struct scatterlist *);
+typedef int ia64_mv_pci_dma_supported (struct pci_dev *, u64);
+
 /*
  * WARNING: The legacy I/O space is _architected_.  Platforms are
  * expected to follow this architected model (see Section 10.7 in the
@@ -101,6 +104,7 @@
 #  define platform_pci_dma_sync_single	ia64_mv.sync_single
 #  define platform_pci_dma_sync_sg	ia64_mv.sync_sg
 #  define platform_pci_dma_address	ia64_mv.dma_address
+#  define platform_pci_dma_supported	ia64_mv.dma_supported
 #  define platform_irq_desc		ia64_mv.irq_desc
 #  define platform_irq_to_vector	ia64_mv.irq_to_vector
 #  define platform_local_vector_to_irq	ia64_mv.local_vector_to_irq
@@ -136,6 +140,7 @@
 	ia64_mv_pci_dma_sync_single *sync_single;
 	ia64_mv_pci_dma_sync_sg *sync_sg;
 	ia64_mv_pci_dma_address *dma_address;
+	ia64_mv_pci_dma_supported *dma_supported;
 	ia64_mv_irq_desc *irq_desc;
 	ia64_mv_irq_to_vector *irq_to_vector;
 	ia64_mv_local_vector_to_irq *local_vector_to_irq;
@@ -172,6 +177,7 @@
 	platform_pci_dma_sync_single,		\
 	platform_pci_dma_sync_sg,		\
 	platform_pci_dma_address,		\
+	platform_pci_dma_supported,		\
 	platform_irq_desc,			\
 	platform_irq_to_vector,			\
 	platform_local_vector_to_irq,		\
@@ -268,6 +274,9 @@
 #endif
 #ifndef platform_pci_dma_address
 # define  platform_pci_dma_address	swiotlb_dma_address
+#endif
+#ifndef platform_pci_dma_supported
+# define  platform_pci_dma_supported	swiotlb_pci_dma_supported
 #endif
 #ifndef platform_irq_desc
 # define platform_irq_desc		__ia64_irq_desc
diff -Nru a/include/asm-ia64/machvec_hpzx1.h b/include/asm-ia64/machvec_hpzx1.h
--- a/include/asm-ia64/machvec_hpzx1.h	Wed May 29 11:43:01 2002
+++ b/include/asm-ia64/machvec_hpzx1.h	Wed May 29 11:43:01 2002
@@ -11,6 +11,7 @@
 extern ia64_mv_pci_map_sg sba_map_sg;
 extern ia64_mv_pci_unmap_sg sba_unmap_sg;
 extern ia64_mv_pci_dma_address sba_dma_address;
+extern ia64_mv_pci_dma_supported sba_dma_supported;
 
 /*
  * This stuff has dual use!
@@ -33,42 +34,6 @@
 #define platform_pci_dma_sync_single	((ia64_mv_pci_dma_sync_single *) machvec_noop)
 #define platform_pci_dma_sync_sg	((ia64_mv_pci_dma_sync_sg *) machvec_noop)
 #define platform_pci_dma_address	sba_dma_address
-
-#endif /* _ASM_IA64_MACHVEC_HPZX1_h */
-#ifndef _ASM_IA64_MACHVEC_HPZX1_h
-#define _ASM_IA64_MACHVEC_HPZX1_h
-
-extern ia64_mv_setup_t dig_setup;
-extern ia64_mv_pci_fixup_t hpzx1_pci_fixup;
-extern ia64_mv_map_nr_t map_nr_dense;
-extern ia64_mv_pci_alloc_consistent sba_alloc_consistent;
-extern ia64_mv_pci_free_consistent sba_free_consistent;
-extern ia64_mv_pci_map_single sba_map_single;
-extern ia64_mv_pci_unmap_single sba_unmap_single;
-extern ia64_mv_pci_map_sg sba_map_sg;
-extern ia64_mv_pci_unmap_sg sba_unmap_sg;
-extern ia64_mv_pci_dma_address sba_dma_address;
-
-/*
- * This stuff has dual use!
- *
- * For a generic kernel, the macros are used to initialize the
- * platform's machvec structure.  When compiling a non-generic kernel,
- * the macros are used directly.
- */
-#define platform_name			"hpzx1"
-#define platform_setup			dig_setup
-#define platform_pci_fixup		hpzx1_pci_fixup
-#define platform_map_nr			map_nr_dense
-#define platform_pci_dma_init		((ia64_mv_pci_dma_init *) machvec_noop)
-#define platform_pci_alloc_consistent	sba_alloc_consistent
-#define platform_pci_free_consistent	sba_free_consistent
-#define platform_pci_map_single		sba_map_single
-#define platform_pci_unmap_single	sba_unmap_single
-#define platform_pci_map_sg		sba_map_sg
-#define platform_pci_unmap_sg		sba_unmap_sg
-#define platform_pci_dma_sync_single	((ia64_mv_pci_dma_sync_single *) machvec_noop)
-#define platform_pci_dma_sync_sg	((ia64_mv_pci_dma_sync_sg *) machvec_noop)
-#define platform_pci_dma_address	sba_dma_address
+#define platform_pci_dma_supported	sba_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_HPZX1_h */
diff -Nru a/include/asm-ia64/offsets.h b/include/asm-ia64/offsets.h
--- a/include/asm-ia64/offsets.h	Wed May 29 11:43:03 2002
+++ b/include/asm-ia64/offsets.h	Wed May 29 11:43:03 2002
@@ -106,6 +106,7 @@
 #define IA64_SWITCH_STACK_AR_RNAT_OFFSET 536	/* 0x218 */
 #define IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET 544	/* 0x220 */
 #define IA64_SWITCH_STACK_PR_OFFSET	552	/* 0x228 */
+#define IA64_SIGCONTEXT_IP_OFFSET	40	/* 0x28 */
 #define IA64_SIGCONTEXT_AR_BSP_OFFSET	72	/* 0x48 */
 #define IA64_SIGCONTEXT_AR_FPSR_OFFSET	104	/* 0x68 */
 #define IA64_SIGCONTEXT_AR_RNAT_OFFSET	80	/* 0x50 */
diff -Nru a/include/asm-ia64/page.h b/include/asm-ia64/page.h
--- a/include/asm-ia64/page.h	Wed May 29 11:43:01 2002
+++ b/include/asm-ia64/page.h	Wed May 29 11:43:01 2002
@@ -56,32 +56,12 @@
 	flush_dcache_page(page);		\
 } while (0)
 
-/*
- * Note: the MAP_NR_*() macro can't use __pa() because MAP_NR_*(X) MUST
- * map to something >= max_mapnr if X is outside the identity mapped
- * kernel space.
- */
-
-/*
- * The dense variant can be used as long as the size of memory holes isn't
- * very big.
- */
-#define MAP_NR_DENSE(addr)	(((unsigned long) (addr) - PAGE_OFFSET) >> PAGE_SHIFT)
-
-#ifdef CONFIG_IA64_GENERIC
-# include <asm/machvec.h>
-# define virt_to_page(kaddr)	(mem_map + platform_map_nr(kaddr))
-# define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
-#elif defined (CONFIG_IA64_SGI_SN1)
-# ifndef CONFIG_DISCONTIGMEM
-#  define virt_to_page(kaddr)	(mem_map + MAP_NR_DENSE(kaddr))
-#  define page_to_phys(page)	XXX fix me
-# endif
-#else
-# define virt_to_page(kaddr)	(mem_map + MAP_NR_DENSE(kaddr))
-# define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
-#endif
-#define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+#define pfn_valid(pfn)		((pfn) < max_mapnr)
+#define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#define page_to_pfn(page)	((unsigned long) (page - mem_map))
+#define pfn_to_page(pfn)	(mem_map + (pfn))
+#define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
 
 typedef union ia64_va {
 	struct {
@@ -105,7 +85,7 @@
 #define REGION_OFFSET(x)	({ia64_va _v; _v.l = (long) (x); _v.f.off;})
 
 #define REGION_SIZE		REGION_NUMBER(1)
-#define REGION_KERNEL	7
+#define REGION_KERNEL		7
 
 #define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
 #define PAGE_BUG(page) do { BUG(); } while (0)
diff -Nru a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h
--- a/include/asm-ia64/pci.h	Wed May 29 11:43:03 2002
+++ b/include/asm-ia64/pci.h	Wed May 29 11:43:03 2002
@@ -58,6 +58,7 @@
 #define pci_dma_sync_single		platform_pci_dma_sync_single
 #define pci_dma_sync_sg			platform_pci_dma_sync_sg
 #define sg_dma_address			platform_pci_dma_address
+#define pci_dma_supported		platform_pci_dma_supported
 
 /* pci_unmap_{single,page} is not a nop, thus... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
@@ -72,17 +73,6 @@
 	((PTR)->LEN_NAME)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
 	(((PTR)->LEN_NAME) = (VAL))
-
-/*
- * Return whether the given PCI device DMA address mask can be supported properly.  For
- * example, if your device can only drive the low 24-bits during PCI bus mastering, then
- * you would pass 0x00ffffff as the mask to this function.
- */
-static inline int
-pci_dma_supported (struct pci_dev *hwdev, u64 mask)
-{
-	return 1;
-}
 
 #define pci_map_page(dev,pg,off,size,dir)				\
 	pci_map_single((dev), page_address(pg) + (off), (size), (dir))
diff -Nru a/include/asm-ia64/perfmon.h b/include/asm-ia64/perfmon.h
--- a/include/asm-ia64/perfmon.h	Wed May 29 11:43:03 2002
+++ b/include/asm-ia64/perfmon.h	Wed May 29 11:43:03 2002
@@ -23,6 +23,7 @@
 #define PFM_GET_FEATURES	0x0c
 #define PFM_DEBUG		0x0d
 #define PFM_UNPROTECT_CONTEXT	0x0e
+#define PFM_GET_PMC_RESET_VAL	0x0f
 
 
 /*
@@ -172,6 +173,8 @@
 extern int  pfm_cleanup_smpl_buf(struct task_struct *);
 extern void pfm_syst_wide_update_task(struct task_struct *, int);
 extern void pfm_ovfl_block_reset (void);
+
+extern int pfm_syst_wide;
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h
--- a/include/asm-ia64/pgalloc.h	Wed May 29 11:43:01 2002
+++ b/include/asm-ia64/pgalloc.h	Wed May 29 11:43:01 2002
@@ -106,6 +106,8 @@
 	++pgtable_cache_size;
 }
 
+#define pmd_free_tlb(tlb, pmd)	pmd_free(pmd)
+
 static inline void
 pmd_populate (struct mm_struct *mm, pmd_t *pmd_entry, struct page *pte)
 {
@@ -149,6 +151,8 @@
 {
 	free_page((unsigned long) pte);
 }
+
+#define pte_free_tlb(tlb, pte)	tlb_remove_page((tlb), (pte))
 
 extern void check_pgt_cache (void);
 
diff -Nru a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
--- a/include/asm-ia64/pgtable.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ia64/pgtable.h	Wed May 29 11:43:02 2002
@@ -207,20 +207,16 @@
 #define VMALLOC_END		(0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9)))
 
 /*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
+ * Conversion functions: convert page frame number (pfn) and a protection value to a page
+ * table entry (pte).
  */
-#define mk_pte(page,pgprot)						\
-({									\
-	pte_t __pte;							\
-									\
-	pte_val(__pte) = (page_to_phys(page)) | pgprot_val(pgprot);	\
-	__pte;								\
-})
+#define pfn_pte(pfn, pgprot) \
+({ pte_t __pte; pte_val(__pte) = ((pfn) << PAGE_SHIFT) | pgprot_val(pgprot); __pte; })
 
-/* This takes a physical page address that is used by the remapping functions */
-#define mk_pte_phys(physpage, pgprot) \
-({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })
+/* Extract pfn from pte.  */
+#define pte_pfn(_pte)		((pte_val(_pte) & _PFN_MASK) >> PAGE_SHIFT)
+
+#define mk_pte(page, pgprot)	pfn_pte(page_to_pfn(page), (pgprot))
 
 #define pte_modify(_pte, newprot) \
 	(__pte((pte_val(_pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)))
diff -Nru a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
--- a/include/asm-ia64/processor.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ia64/processor.h	Wed May 29 11:43:02 2002
@@ -55,123 +55,6 @@
 #define MCA_bus 0
 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
 
-/* Processor status register bits: */
-#define IA64_PSR_BE_BIT		1
-#define IA64_PSR_UP_BIT		2
-#define IA64_PSR_AC_BIT		3
-#define IA64_PSR_MFL_BIT	4
-#define IA64_PSR_MFH_BIT	5
-#define IA64_PSR_IC_BIT		13
-#define IA64_PSR_I_BIT		14
-#define IA64_PSR_PK_BIT		15
-#define IA64_PSR_DT_BIT		17
-#define IA64_PSR_DFL_BIT	18
-#define IA64_PSR_DFH_BIT	19
-#define IA64_PSR_SP_BIT		20
-#define IA64_PSR_PP_BIT		21
-#define IA64_PSR_DI_BIT		22
-#define IA64_PSR_SI_BIT		23
-#define IA64_PSR_DB_BIT		24
-#define IA64_PSR_LP_BIT		25
-#define IA64_PSR_TB_BIT		26
-#define IA64_PSR_RT_BIT		27
-/* The following are not affected by save_flags()/restore_flags(): */
-#define IA64_PSR_CPL0_BIT	32
-#define IA64_PSR_CPL1_BIT	33
-#define IA64_PSR_IS_BIT		34
-#define IA64_PSR_MC_BIT		35
-#define IA64_PSR_IT_BIT		36
-#define IA64_PSR_ID_BIT		37
-#define IA64_PSR_DA_BIT		38
-#define IA64_PSR_DD_BIT		39
-#define IA64_PSR_SS_BIT		40
-#define IA64_PSR_RI_BIT		41
-#define IA64_PSR_ED_BIT		43
-#define IA64_PSR_BN_BIT		44
-
-#define IA64_PSR_BE	(__IA64_UL(1) << IA64_PSR_BE_BIT)
-#define IA64_PSR_UP	(__IA64_UL(1) << IA64_PSR_UP_BIT)
-#define IA64_PSR_AC	(__IA64_UL(1) << IA64_PSR_AC_BIT)
-#define IA64_PSR_MFL	(__IA64_UL(1) << IA64_PSR_MFL_BIT)
-#define IA64_PSR_MFH	(__IA64_UL(1) << IA64_PSR_MFH_BIT)
-#define IA64_PSR_IC	(__IA64_UL(1) << IA64_PSR_IC_BIT)
-#define IA64_PSR_I	(__IA64_UL(1) << IA64_PSR_I_BIT)
-#define IA64_PSR_PK	(__IA64_UL(1) << IA64_PSR_PK_BIT)
-#define IA64_PSR_DT	(__IA64_UL(1) << IA64_PSR_DT_BIT)
-#define IA64_PSR_DFL	(__IA64_UL(1) << IA64_PSR_DFL_BIT)
-#define IA64_PSR_DFH	(__IA64_UL(1) << IA64_PSR_DFH_BIT)
-#define IA64_PSR_SP	(__IA64_UL(1) << IA64_PSR_SP_BIT)
-#define IA64_PSR_PP	(__IA64_UL(1) << IA64_PSR_PP_BIT)
-#define IA64_PSR_DI	(__IA64_UL(1) << IA64_PSR_DI_BIT)
-#define IA64_PSR_SI	(__IA64_UL(1) << IA64_PSR_SI_BIT)
-#define IA64_PSR_DB	(__IA64_UL(1) << IA64_PSR_DB_BIT)
-#define IA64_PSR_LP	(__IA64_UL(1) << IA64_PSR_LP_BIT)
-#define IA64_PSR_TB	(__IA64_UL(1) << IA64_PSR_TB_BIT)
-#define IA64_PSR_RT	(__IA64_UL(1) << IA64_PSR_RT_BIT)
-/* The following are not affected by save_flags()/restore_flags(): */
-#define IA64_PSR_IS	(__IA64_UL(1) << IA64_PSR_IS_BIT)
-#define IA64_PSR_MC	(__IA64_UL(1) << IA64_PSR_MC_BIT)
-#define IA64_PSR_IT	(__IA64_UL(1) << IA64_PSR_IT_BIT)
-#define IA64_PSR_ID	(__IA64_UL(1) << IA64_PSR_ID_BIT)
-#define IA64_PSR_DA	(__IA64_UL(1) << IA64_PSR_DA_BIT)
-#define IA64_PSR_DD	(__IA64_UL(1) << IA64_PSR_DD_BIT)
-#define IA64_PSR_SS	(__IA64_UL(1) << IA64_PSR_SS_BIT)
-#define IA64_PSR_RI	(__IA64_UL(3) << IA64_PSR_RI_BIT)
-#define IA64_PSR_ED	(__IA64_UL(1) << IA64_PSR_ED_BIT)
-#define IA64_PSR_BN	(__IA64_UL(1) << IA64_PSR_BN_BIT)
-
-/* User mask bits: */
-#define IA64_PSR_UM	(IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL | IA64_PSR_MFH)
-
-/* Default Control Register */
-#define IA64_DCR_PP_BIT		 0	/* privileged performance monitor default */
-#define IA64_DCR_BE_BIT		 1	/* big-endian default */
-#define IA64_DCR_LC_BIT		 2	/* ia32 lock-check enable */
-#define IA64_DCR_DM_BIT		 8	/* defer TLB miss faults */
-#define IA64_DCR_DP_BIT		 9	/* defer page-not-present faults */
-#define IA64_DCR_DK_BIT		10	/* defer key miss faults */
-#define IA64_DCR_DX_BIT		11	/* defer key permission faults */
-#define IA64_DCR_DR_BIT		12	/* defer access right faults */
-#define IA64_DCR_DA_BIT		13	/* defer access bit faults */
-#define IA64_DCR_DD_BIT		14	/* defer debug faults */
-
-#define IA64_DCR_PP	(__IA64_UL(1) << IA64_DCR_PP_BIT)
-#define IA64_DCR_BE	(__IA64_UL(1) << IA64_DCR_BE_BIT)
-#define IA64_DCR_LC	(__IA64_UL(1) << IA64_DCR_LC_BIT)
-#define IA64_DCR_DM	(__IA64_UL(1) << IA64_DCR_DM_BIT)
-#define IA64_DCR_DP	(__IA64_UL(1) << IA64_DCR_DP_BIT)
-#define IA64_DCR_DK	(__IA64_UL(1) << IA64_DCR_DK_BIT)
-#define IA64_DCR_DX	(__IA64_UL(1) << IA64_DCR_DX_BIT)
-#define IA64_DCR_DR	(__IA64_UL(1) << IA64_DCR_DR_BIT)
-#define IA64_DCR_DA	(__IA64_UL(1) << IA64_DCR_DA_BIT)
-#define IA64_DCR_DD	(__IA64_UL(1) << IA64_DCR_DD_BIT)
-
-/* Interrupt Status Register */
-#define IA64_ISR_X_BIT		32	/* execute access */
-#define IA64_ISR_W_BIT		33	/* write access */
-#define IA64_ISR_R_BIT		34	/* read access */
-#define IA64_ISR_NA_BIT		35	/* non-access */
-#define IA64_ISR_SP_BIT		36	/* speculative load exception */
-#define IA64_ISR_RS_BIT		37	/* mandatory register-stack exception */
-#define IA64_ISR_IR_BIT		38	/* invalid register frame exception */
-#define IA64_ISR_CODE_MASK	0xf
-
-#define IA64_ISR_X	(__IA64_UL(1) << IA64_ISR_X_BIT)
-#define IA64_ISR_W	(__IA64_UL(1) << IA64_ISR_W_BIT)
-#define IA64_ISR_R	(__IA64_UL(1) << IA64_ISR_R_BIT)
-#define IA64_ISR_NA	(__IA64_UL(1) << IA64_ISR_NA_BIT)
-#define IA64_ISR_SP	(__IA64_UL(1) << IA64_ISR_SP_BIT)
-#define IA64_ISR_RS	(__IA64_UL(1) << IA64_ISR_RS_BIT)
-#define IA64_ISR_IR	(__IA64_UL(1) << IA64_ISR_IR_BIT)
-
-/* ISR code field for non-access instructions */
-#define IA64_ISR_CODE_TPA	0
-#define IA64_ISR_CODE_FC	1
-#define IA64_ISR_CODE_PROBE	2
-#define IA64_ISR_CODE_TAK	3
-#define IA64_ISR_CODE_LFETCH	4
-#define IA64_ISR_CODE_PROBEF	5
-
 #define IA64_THREAD_FPH_VALID	(__IA64_UL(1) << 0)	/* floating-point high state valid? */
 #define IA64_THREAD_DBG_VALID	(__IA64_UL(1) << 1)	/* debug registers valid? */
 #define IA64_THREAD_PM_VALID	(__IA64_UL(1) << 2)	/* performance registers valid? */
@@ -290,8 +173,6 @@
 	__u64 ipi_count;
 	__u64 prof_counter;
 	__u64 prof_multiplier;
-	__u32 pfm_syst_wide;
-	__u32 pfm_dcr_pp;
 #endif
 } cpu_info __per_cpu_data;
 
@@ -632,14 +513,22 @@
 	asm volatile ("invala" ::: "memory");
 }
 
+static inline __u64
+ia64_clear_ic (void)
+{
+	__u64 psr;
+	asm volatile ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;" : "=r"(psr) :: "memory");
+	return psr;
+}
+
 /*
- * Save the processor status flags in FLAGS and then clear the interrupt collection and
- * interrupt enable bits.  Don't trigger any mandatory RSE references while this bit is
- * off!
+ * Restore the psr.
  */
-#define ia64_clear_ic(flags)						\
-	asm volatile ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;"	\
-			      : "=r"(flags) :: "memory");
+static inline void
+ia64_set_psr (__u64 psr)
+{
+	asm volatile (";; mov psr.l=%0;; srlz.d" :: "r" (psr) : "memory");
+}
 
 /*
  * Insert a translation into an instruction and/or data translation
diff -Nru a/include/asm-ia64/siginfo.h b/include/asm-ia64/siginfo.h
--- a/include/asm-ia64/siginfo.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ia64/siginfo.h	Wed May 29 11:43:02 2002
@@ -6,15 +6,15 @@
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
-#include <linux/types.h>
+#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 4)
+
+#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
 
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
+#define HAVE_ARCH_SIGINFO_T
 
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 4)
+#define HAVE_ARCH_COPY_SIGINFO
+
+#include <asm-generic/siginfo.h>
 
 typedef struct siginfo {
 	int si_signo;
@@ -75,18 +75,6 @@
 	} _sifields;
 } siginfo_t;
 
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
 #define si_imm		_sifields._sigfault._imm	/* as per UNIX SysV ABI spec */
 #define si_flags	_sifields._sigfault._flags
 /*
@@ -94,8 +82,6 @@
  * si_code is non-zero and __ISR_VALID is set in si_flags.
  */
 #define si_isr		_sifields._sigfault._isr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
 #define si_pfm_ovfl	_sifields._sigprof._pfm_ovfl_counters
 
 /*
@@ -109,155 +95,49 @@
  * Positive values for kernel-generated signals.
  */
 #ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
 #define __SI_PROF	(6 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
 #endif
 
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	(-1)		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	(-3)		/* sent by real time mesq state change */
-#define SI_ASYNCIO	(-4)		/* sent by AIO completion */
-#define SI_SIGIO	(-5)		/* sent by queued SIGIO */
-#define SI_TKILL	(-6)		/* sent by tkill system call */
-#define SI_DETHREAD	(-7)		/* sent by execve() killing subsidiary threads */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
 /*
  * SIGILL si_codes
  */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
 #define ILL_BADIADDR	(__SI_FAULT|9)	/* unimplemented instruction address */
 #define __ILL_BREAK	(__SI_FAULT|10)	/* illegal break */
 #define __ILL_BNDMOD	(__SI_FAULT|11)	/* bundle-update (modification) in progress */
+#undef NSIGILL
 #define NSIGILL		11
 
 /*
  * SIGFPE si_codes
  */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
 #define __FPE_DECOVF	(__SI_FAULT|9)	/* decimal overflow */
 #define __FPE_DECDIV	(__SI_FAULT|10)	/* decimal division by zero */
 #define __FPE_DECERR	(__SI_FAULT|11)	/* packed decimal error */
 #define __FPE_INVASC	(__SI_FAULT|12)	/* invalid ASCII digit */
 #define __FPE_INVDEC	(__SI_FAULT|13)	/* invalid decimal digit */
+#undef NSIGFPE
 #define NSIGFPE		13
 
 /*
  * SIGSEGV si_codes
  */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
 #define __SEGV_PSTKOVF	(__SI_FAULT|3)	/* paragraph stack overflow */
+#undef NSIGSEGV
 #define NSIGSEGV	3
 
 /*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
  * SIGTRAP si_codes
  */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
 #define TRAP_BRANCH	(__SI_FAULT|3)	/* process taken branch trap */
 #define TRAP_HWBKPT	(__SI_FAULT|4)	/* hardware breakpoint or watchpoint */
+#undef NSIGTRAP
 #define NSIGTRAP	4
 
 /*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
-
-/*
  * SIGPROF si_codes
  */
 #define PROF_OVFL	(__SI_PROF|1)  /* some counters overflowed */
 
-/*
- * sigevent definitions
- *
- * It seems likely that SIGEV_THREAD will have to be handled from userspace, libpthread
- * transmuting it to SIGEV_SIGNAL, which the thread manager then catches and does the
- * appropriate nonsense.  However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
 #ifdef __KERNEL__
 #include <linux/string.h>
 
@@ -268,10 +148,9 @@
 		memcpy(to, from, sizeof(siginfo_t));
 	else
 		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
+		memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigchld));
 }
 
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
 extern int copy_siginfo_from_user(siginfo_t *to, siginfo_t *from);
 
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ia64/signal.h b/include/asm-ia64/signal.h
--- a/include/asm-ia64/signal.h	Wed May 29 11:43:01 2002
+++ b/include/asm-ia64/signal.h	Wed May 29 11:43:01 2002
@@ -166,6 +166,8 @@
 
 #  include <asm/sigcontext.h>
 
+#define HAVE_ARCH_GET_SIGNAL_TO_DELIVER
+
 #endif /* __KERNEL__ */
 
 # endif /* !__ASSEMBLY__ */
diff -Nru a/include/asm-ia64/system.h b/include/asm-ia64/system.h
--- a/include/asm-ia64/system.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ia64/system.h	Wed May 29 11:43:02 2002
@@ -14,6 +14,7 @@
  */
 #include <linux/config.h>
 
+#include <asm/kregs.h>
 #include <asm/page.h>
 
 #define KERNEL_START		(PAGE_OFFSET + 68*1024*1024)
@@ -30,7 +31,7 @@
 	__u16 bus;	/* PCI Bus number */
 	__u32 pci_id;	/* ACPI split 16 bits device, 16 bits function (see section 6.1.1) */
 	__u8 pin;	/* PCI PIN (0 = A, 1 = B, 2 = C, 3 = D) */
-	__u8 irq;	/* IRQ assigned */
+	__u32 irq;	/* IRQ assigned */
 };
 
 extern struct ia64_boot_param {
@@ -135,16 +136,21 @@
 	}										\
 } while (0)
 
-# define local_irq_restore(x)						 \
-do {									 \
-	unsigned long ip, old_psr, psr = (x);				 \
-									 \
-	__asm__ __volatile__ (";;mov %0=psr; mov psr.l=%1;; srlz.d"	 \
-			      : "=&r" (old_psr) : "r" (psr) : "memory"); \
-	if ((old_psr & (1UL << 14)) && !(psr & (1UL << 14))) {		 \
-		__asm__ ("mov %0=ip" : "=r"(ip));			 \
-		last_cli_ip = ip;					 \
-	}								 \
+# define local_irq_restore(x)							\
+do {										\
+	unsigned long ip, old_psr, psr = (x);					\
+										\
+	__asm__ __volatile__ ("mov %0=psr;"					\
+			      "cmp.ne p6,p7=%1,r0;;"				\
+			      "(p6) ssm psr.i;"					\
+			      "(p7) rsm psr.i;;"				\
+			      "srlz.d"						\
+			      : "=&r" (old_psr) : "r"((psr) & IA64_PSR_I)	\
+			      : "p6", "p7", "memory");				\
+	if ((old_psr & IA64_PSR_I) && !(psr & IA64_PSR_I)) {			\
+		__asm__ ("mov %0=ip" : "=r"(ip));				\
+		last_cli_ip = ip;						\
+	}									\
 } while (0)
 
 #else /* !CONFIG_IA64_DEBUG_IRQ */
@@ -153,8 +159,12 @@
 						      : "=r" (x) :: "memory")
 # define local_irq_disable()	__asm__ __volatile__ (";; rsm psr.i;;" ::: "memory")
 /* (potentially) setting psr.i requires data serialization: */
-# define local_irq_restore(x)	__asm__ __volatile__ (";; mov psr.l=%0;; srlz.d"	\
-						      :: "r" (x) : "memory")
+# define local_irq_restore(x)	__asm__ __volatile__ ("cmp.ne p6,p7=%0,r0;;"	\
+						      "(p6) ssm psr.i;"		\
+						      "(p7) rsm psr.i;;"	\
+						      "srlz.d"			\
+						      :: "r"((x) & IA64_PSR_I)	\
+						      : "p6", "p7", "memory")
 #endif /* !CONFIG_IA64_DEBUG_IRQ */
 
 #define local_irq_enable()	__asm__ __volatile__ (";; ssm psr.i;; srlz.d" ::: "memory")
diff -Nru a/include/asm-ia64/tlb.h b/include/asm-ia64/tlb.h
--- a/include/asm-ia64/tlb.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ia64/tlb.h	Wed May 29 11:43:02 2002
@@ -1 +1,7 @@
+/* XXX fix me! */
+#define tlb_start_vma(tlb, vma)			do { } while (0)
+#define tlb_end_vma(tlb, vma)			do { } while (0)
+#define tlb_remove_tlb_entry(tlb, pte, address) do { } while (0)
+#define tlb_flush(tlb)				flush_tlb_mm((tlb)->mm)
+
 #include <asm-generic/tlb.h>
diff -Nru a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
--- a/include/asm-ia64/unistd.h	Wed May 29 11:43:01 2002
+++ b/include/asm-ia64/unistd.h	Wed May 29 11:43:01 2002
@@ -222,6 +222,7 @@
 #define __NR_futex			1230
 #define __NR_sched_setaffinity		1231
 #define __NR_sched_getaffinity		1232
+#define __NR_security			1233
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
diff -Nru a/include/asm-m68k/errno.h b/include/asm-m68k/errno.h
--- a/include/asm-m68k/errno.h	Wed May 29 11:43:03 2002
+++ b/include/asm-m68k/errno.h	Wed May 29 11:43:03 2002
@@ -1,132 +1,6 @@
 #ifndef _M68K_ERRNO_H
 #define _M68K_ERRNO_H
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
-#define	EDEADLK		35	/* Resource deadlock would occur */
-#define	ENAMETOOLONG	36	/* File name too long */
-#define	ENOLCK		37	/* No record locks available */
-#define	ENOSYS		38	/* Function not implemented */
-#define	ENOTEMPTY	39	/* Directory not empty */
-#define	ELOOP		40	/* Too many symbolic links encountered */
-#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
-#define	ENOMSG		42	/* No message of desired type */
-#define	EIDRM		43	/* Identifier removed */
-#define	ECHRNG		44	/* Channel number out of range */
-#define	EL2NSYNC	45	/* Level 2 not synchronized */
-#define	EL3HLT		46	/* Level 3 halted */
-#define	EL3RST		47	/* Level 3 reset */
-#define	ELNRNG		48	/* Link number out of range */
-#define	EUNATCH		49	/* Protocol driver not attached */
-#define	ENOCSI		50	/* No CSI structure available */
-#define	EL2HLT		51	/* Level 2 halted */
-#define	EBADE		52	/* Invalid exchange */
-#define	EBADR		53	/* Invalid request descriptor */
-#define	EXFULL		54	/* Exchange full */
-#define	ENOANO		55	/* No anode */
-#define	EBADRQC		56	/* Invalid request code */
-#define	EBADSLT		57	/* Invalid slot */
-
-#define	EDEADLOCK	EDEADLK
-
-#define	EBFONT		59	/* Bad font file format */
-#define	ENOSTR		60	/* Device not a stream */
-#define	ENODATA		61	/* No data available */
-#define	ETIME		62	/* Timer expired */
-#define	ENOSR		63	/* Out of streams resources */
-#define	ENONET		64	/* Machine is not on the network */
-#define	ENOPKG		65	/* Package not installed */
-#define	EREMOTE		66	/* Object is remote */
-#define	ENOLINK		67	/* Link has been severed */
-#define	EADV		68	/* Advertise error */
-#define	ESRMNT		69	/* Srmount error */
-#define	ECOMM		70	/* Communication error on send */
-#define	EPROTO		71	/* Protocol error */
-#define	EMULTIHOP	72	/* Multihop attempted */
-#define	EDOTDOT		73	/* RFS specific error */
-#define	EBADMSG		74	/* Not a data message */
-#define	EOVERFLOW	75	/* Value too large for defined data type */
-#define	ENOTUNIQ	76	/* Name not unique on network */
-#define	EBADFD		77	/* File descriptor in bad state */
-#define	EREMCHG		78	/* Remote address changed */
-#define	ELIBACC		79	/* Can not access a needed shared library */
-#define	ELIBBAD		80	/* Accessing a corrupted shared library */
-#define	ELIBSCN		81	/* .lib section in a.out corrupted */
-#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
-#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
-#define	EILSEQ		84	/* Illegal byte sequence */
-#define	ERESTART	85	/* Interrupted system call should be restarted */
-#define	ESTRPIPE	86	/* Streams pipe error */
-#define	EUSERS		87	/* Too many users */
-#define	ENOTSOCK	88	/* Socket operation on non-socket */
-#define	EDESTADDRREQ	89	/* Destination address required */
-#define	EMSGSIZE	90	/* Message too long */
-#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
-#define	ENOPROTOOPT	92	/* Protocol not available */
-#define	EPROTONOSUPPORT	93	/* Protocol not supported */
-#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
-#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
-#define	EPFNOSUPPORT	96	/* Protocol family not supported */
-#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
-#define	EADDRINUSE	98	/* Address already in use */
-#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
-#define	ENETDOWN	100	/* Network is down */
-#define	ENETUNREACH	101	/* Network is unreachable */
-#define	ENETRESET	102	/* Network dropped connection because of reset */
-#define	ECONNABORTED	103	/* Software caused connection abort */
-#define	ECONNRESET	104	/* Connection reset by peer */
-#define	ENOBUFS		105	/* No buffer space available */
-#define	EISCONN		106	/* Transport endpoint is already connected */
-#define	ENOTCONN	107	/* Transport endpoint is not connected */
-#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
-#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
-#define	ETIMEDOUT	110	/* Connection timed out */
-#define	ECONNREFUSED	111	/* Connection refused */
-#define	EHOSTDOWN	112	/* Host is down */
-#define	EHOSTUNREACH	113	/* No route to host */
-#define	EALREADY	114	/* Operation already in progress */
-#define	EINPROGRESS	115	/* Operation now in progress */
-#define	ESTALE		116	/* Stale NFS file handle */
-#define	EUCLEAN		117	/* Structure needs cleaning */
-#define	ENOTNAM		118	/* Not a XENIX named type file */
-#define	ENAVAIL		119	/* No XENIX semaphores available */
-#define	EISNAM		120	/* Is a named type file */
-#define	EREMOTEIO	121	/* Remote I/O error */
-#define	EDQUOT		122	/* Quota exceeded */
-
-#define	ENOMEDIUM	123	/* No medium found */
-#define	EMEDIUMTYPE	124	/* Wrong medium type */
+#include <asm-generic/errno.h>
 
 #endif /* _M68K_ERRNO_H */
diff -Nru a/include/asm-m68k/siginfo.h b/include/asm-m68k/siginfo.h
--- a/include/asm-m68k/siginfo.h	Wed May 29 11:43:01 2002
+++ b/include/asm-m68k/siginfo.h	Wed May 29 11:43:01 2002
@@ -1,17 +1,9 @@
 #ifndef _M68K_SIGINFO_H
 #define _M68K_SIGINFO_H
 
-#include <linux/types.h>
+#define HAVE_ARCH_SIGINFO_T
 
-/* This is copied from asm-alpha/siginfo.h.  */
-
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
+#include <asm-generic/siginfo.h>
 
 typedef struct siginfo {
 	int si_signo;
@@ -70,174 +62,12 @@
 /*
  * How these fields are to be accessed.
  */
-#define si_pid		_sifields._kill._pid
+#undef si_uid
 #ifdef __KERNEL__
 #define si_uid		_sifields._kill._uid32
 #define si_uid16	_sifields._kill._uid
 #else
 #define si_uid		_sifields._kill._uid
-#endif /* __KERNEL__ */
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
-
-/*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
-#define SI_TKILL	-6		/* sent by tkill system call */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
-
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
 #endif /* __KERNEL__ */
 
 #endif
diff -Nru a/include/asm-m68k/signal.h b/include/asm-m68k/signal.h
--- a/include/asm-m68k/signal.h	Wed May 29 11:43:02 2002
+++ b/include/asm-m68k/signal.h	Wed May 29 11:43:02 2002
@@ -215,6 +215,8 @@
 	return word ^ 31;
 }
 
+#define HAVE_ARCH_GET_SIGNAL_TO_DELIVER
+
 #endif /* __KERNEL__ */
 
 #endif /* _M68K_SIGNAL_H */
diff -Nru a/include/asm-mips/errno.h b/include/asm-mips/errno.h
--- a/include/asm-mips/errno.h	Wed May 29 11:43:03 2002
+++ b/include/asm-mips/errno.h	Wed May 29 11:43:03 2002
@@ -11,40 +11,9 @@
 /*
  * These error numbers are intended to be MIPS ABI compatible
  */
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
+
+#include <asm-generic/errno-base.h>
+
 #define	ENOMSG		35	/* No message of desired type */
 #define	EIDRM		36	/* Identifier removed */
 #define	ECHRNG		37	/* Channel number out of range */
diff -Nru a/include/asm-mips/ide.h b/include/asm-mips/ide.h
--- a/include/asm-mips/ide.h	Wed May 29 11:43:02 2002
+++ b/include/asm-mips/ide.h	Wed May 29 11:43:02 2002
@@ -60,7 +60,7 @@
 	for(index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 #endif
 }
diff -Nru a/include/asm-mips/siginfo.h b/include/asm-mips/siginfo.h
--- a/include/asm-mips/siginfo.h	Wed May 29 11:43:03 2002
+++ b/include/asm-mips/siginfo.h	Wed May 29 11:43:03 2002
@@ -9,21 +9,19 @@
 #ifndef _ASM_SIGINFO_H
 #define _ASM_SIGINFO_H
 
-#include <linux/types.h>
+#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
+
+#define HAVE_ARCH_SIGINFO_T
+
+#define HAVE_ARCH_SIGEVENT_T
 
-/* This structure matches IRIX 32/n32 ABIs for binary compatibility. */
+#include <asm-generic/siginfo.h>
 
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
+/* The sigval union matches IRIX 32/n32 ABIs for binary compatibility. */
 
 /* This structure matches IRIX 32/n32 ABIs for binary compatibility but
    has Linux extensions.  */
 
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
-
 typedef struct siginfo {
 	int si_signo;
 	int si_code;
@@ -83,124 +81,15 @@
 } siginfo_t;
 
 /*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
-
-/*
  * si_code values
  * Again these have been choosen to be IRIX compatible.
  */
-#define SI_USER		0	/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80	/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1	/* sent by sigqueue */
+#undef SI_ASYNCIO
+#undef SI_TIMER
+#undef SI_MESGQ
 #define SI_ASYNCIO	-2	/* sent by AIO completion */
 #define SI_TIMER __SI_CODE(__SI_TIMER,-3) /* sent by timer expiration */
 #define SI_MESGQ	-4	/* sent by real time mesq state change */
-#define SI_SIGIO	-5	/* sent by queued SIGIO */
-#define SI_TKILL	-6	/* sent by tkill system call */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
 
 /*
  * sigevent definitions
@@ -210,14 +99,14 @@
  * thread manager then catches and does the appropriate nonsense.
  * However, everything is written out here so as to not get lost.
  */
+#undef SIGEV_NONE
+#undef SIGEV_SIGNAL
+#undef SIGEV_THREAD
 #define SIGEV_NONE	128	/* other notification: meaningless */
 #define SIGEV_SIGNAL	129	/* notify via signal */
 #define SIGEV_CALLBACK	130	/* ??? */
 #define SIGEV_THREAD	131	/* deliver via thread creation */
 
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
-
 /* XXX This one isn't yet IRIX / ABI compatible.  */
 typedef struct sigevent {
 	int sigev_notify;
@@ -232,24 +121,5 @@
 		} _sigev_thread;
 	} _sigev_un;
 } sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
-#endif /* __KERNEL__ */
 
 #endif /* _ASM_SIGINFO_H */
diff -Nru a/include/asm-mips64/errno.h b/include/asm-mips64/errno.h
--- a/include/asm-mips64/errno.h	Wed May 29 11:43:03 2002
+++ b/include/asm-mips64/errno.h	Wed May 29 11:43:03 2002
@@ -12,40 +12,9 @@
 /*
  * These error numbers are intended to be MIPS ABI compatible
  */
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
+
+#include <asm-generic/errno-base.h>
+
 #define	ENOMSG		35	/* No message of desired type */
 #define	EIDRM		36	/* Identifier removed */
 #define	ECHRNG		37	/* Channel number out of range */
diff -Nru a/include/asm-mips64/ide.h b/include/asm-mips64/ide.h
--- a/include/asm-mips64/ide.h	Wed May 29 11:43:01 2002
+++ b/include/asm-mips64/ide.h	Wed May 29 11:43:01 2002
@@ -63,7 +63,7 @@
 	for(index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 #endif
 }
diff -Nru a/include/asm-mips64/mmzone.h b/include/asm-mips64/mmzone.h
--- a/include/asm-mips64/mmzone.h	Wed May 29 11:43:01 2002
+++ b/include/asm-mips64/mmzone.h	Wed May 29 11:43:01 2002
@@ -76,7 +76,7 @@
 #define MIPS64_NR(kaddr) (((unsigned long)(kaddr) > (unsigned long)high_memory)\
 		? (max_mapnr + 1) : (LOCAL_MAP_NR((kaddr)) + \
 		(((unsigned long)ADDR_TO_MAPBASE((kaddr)) - PAGE_OFFSET) / \
-		sizeof(mem_map_t))))
+		sizeof(struct page))))
 
 #define kern_addr_valid(addr)	((KVADDR_TO_NID((unsigned long)addr) > \
 	-1) ? 0 : (test_bit(LOCAL_MAP_NR((addr)), \
diff -Nru a/include/asm-mips64/siginfo.h b/include/asm-mips64/siginfo.h
--- a/include/asm-mips64/siginfo.h	Wed May 29 11:43:02 2002
+++ b/include/asm-mips64/siginfo.h	Wed May 29 11:43:02 2002
@@ -9,21 +9,18 @@
 #ifndef _ASM_SIGINFO_H
 #define _ASM_SIGINFO_H
 
-#include <linux/types.h>
+#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
+
+#define HAVE_ARCH_SIGINFO_T
+#define HAVE_ARCH_SIGEVENT_T
 
-/* This structure matches IRIX 32/n32 ABIs for binary compatibility. */
+#include <asm-generic/siginfo.h>
 
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
+/* The sigval union matches IRIX 32/n32 ABIs for binary compatibility. */
 
 /* This structure matches IRIX 32/n32 ABIs for binary compatibility but
    has Linux extensions.  */
 
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
-
 typedef struct siginfo {
 	int si_signo;
 	int si_code;
@@ -83,124 +80,15 @@
 } siginfo_t;
 
 /*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
-
-/*
  * si_code values
  * Again these have been choosen to be IRIX compatible.
  */
-#define SI_USER		0	/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80	/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1	/* sent by sigqueue */
+#undef SI_ASYNCIO
+#undef SI_TIMER
+#undef SI_MESGQ
 #define SI_ASYNCIO	-2	/* sent by AIO completion */
 #define SI_TIMER __SI_CODE(__SI_TIMER,-3) /* sent by timer expiration */
 #define SI_MESGQ	-4	/* sent by real time mesq state change */
-#define SI_SIGIO	-5	/* sent by queued SIGIO */
-#define SI_TKILL	-6	/* sent by tkill system call */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
 
 /*
  * sigevent definitions
@@ -210,14 +98,14 @@
  * thread manager then catches and does the appropriate nonsense.
  * However, everything is written out here so as to not get lost.
  */
+#undef SIGEV_NONE
+#undef SIGEV_SIGNAL
+#undef SIGEV_THREAD
 #define SIGEV_NONE	128	/* other notification: meaningless */
 #define SIGEV_SIGNAL	129	/* notify via signal */
 #define SIGEV_CALLBACK	130	/* ??? */
 #define SIGEV_THREAD	131	/* deliver via thread creation */
 
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
-
 /* XXX This one isn't yet IRIX / ABI compatible.  */
 typedef struct sigevent {
 	int sigev_notify;
@@ -232,24 +120,5 @@
 		} _sigev_thread;
 	} _sigev_un;
 } sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
-#endif /* __KERNEL__ */
 
 #endif /* _ASM_SIGINFO_H */
diff -Nru a/include/asm-parisc/errno.h b/include/asm-parisc/errno.h
--- a/include/asm-parisc/errno.h	Wed May 29 11:43:03 2002
+++ b/include/asm-parisc/errno.h	Wed May 29 11:43:03 2002
@@ -1,40 +1,8 @@
 #ifndef _PARISC_ERRNO_H
 #define _PARISC_ERRNO_H
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
+#include <asm-generic/errno-base.h>
+
 #define	ENOMSG		35	/* No message of desired type */
 #define	EIDRM		36	/* Identifier removed */
 #define	ECHRNG		37	/* Channel number out of range */
diff -Nru a/include/asm-parisc/ide.h b/include/asm-parisc/ide.h
--- a/include/asm-parisc/ide.h	Wed May 29 11:43:02 2002
+++ b/include/asm-parisc/ide.h	Wed May 29 11:43:02 2002
@@ -76,7 +76,7 @@
 	for(index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 #endif
 }
diff -Nru a/include/asm-parisc/siginfo.h b/include/asm-parisc/siginfo.h
--- a/include/asm-parisc/siginfo.h	Wed May 29 11:43:03 2002
+++ b/include/asm-parisc/siginfo.h	Wed May 29 11:43:03 2002
@@ -1,235 +1,14 @@
 #ifndef _PARISC_SIGINFO_H
 #define _PARISC_SIGINFO_H
 
-#include <linux/types.h>
-
-/* XXX: This structure was copied from the Alpha; is there an iBCS version?  */
-
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE];
-
-		/* kill() */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
-			int _status;		/* exit code */
-			clock_t _utime;
-			clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-		struct {
-			void *_addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} siginfo_t;
-
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
-
-/*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
-#define SI_TKILL	-6		/* sent by tkill system call */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
+#include <asm-generic/siginfo.h>
 
 /*
  * SIGTRAP si_codes
  */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
 #define TRAP_BRANCH	(__SI_FAULT|3)	/* process taken branch trap */
 #define TRAP_HWBKPT	(__SI_FAULT|4)	/* hardware breakpoint or watchpoint */
+#undef NSIGTRAP
 #define NSIGTRAP	4
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
-
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
-#endif /* __KERNEL__ */
 
 #endif
diff -Nru a/include/asm-ppc/bitops.h b/include/asm-ppc/bitops.h
--- a/include/asm-ppc/bitops.h	Wed May 29 11:43:03 2002
+++ b/include/asm-ppc/bitops.h	Wed May 29 11:43:03 2002
@@ -263,6 +263,18 @@
 }
 
 /*
+ * fls: find last (most-significant) bit set.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+static __inline__ int fls(unsigned int x)
+{
+	int lz;
+
+	asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x));
+	return 32 - lz;
+}
+
+/*
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
  */
diff -Nru a/include/asm-ppc/errno.h b/include/asm-ppc/errno.h
--- a/include/asm-ppc/errno.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ppc/errno.h	Wed May 29 11:43:02 2002
@@ -4,131 +4,10 @@
 #ifndef _PPC_ERRNO_H
 #define _PPC_ERRNO_H
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
-#define	EDEADLK		35	/* Resource deadlock would occur */
-#define	ENAMETOOLONG	36	/* File name too long */
-#define	ENOLCK		37	/* No record locks available */
-#define	ENOSYS		38	/* Function not implemented */
-#define	ENOTEMPTY	39	/* Directory not empty */
-#define	ELOOP		40	/* Too many symbolic links encountered */
-#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
-#define	ENOMSG		42	/* No message of desired type */
-#define	EIDRM		43	/* Identifier removed */
-#define	ECHRNG		44	/* Channel number out of range */
-#define	EL2NSYNC	45	/* Level 2 not synchronized */
-#define	EL3HLT		46	/* Level 3 halted */
-#define	EL3RST		47	/* Level 3 reset */
-#define	ELNRNG		48	/* Link number out of range */
-#define	EUNATCH		49	/* Protocol driver not attached */
-#define	ENOCSI		50	/* No CSI structure available */
-#define	EL2HLT		51	/* Level 2 halted */
-#define	EBADE		52	/* Invalid exchange */
-#define	EBADR		53	/* Invalid request descriptor */
-#define	EXFULL		54	/* Exchange full */
-#define	ENOANO		55	/* No anode */
-#define	EBADRQC		56	/* Invalid request code */
-#define	EBADSLT		57	/* Invalid slot */
-#define	EDEADLOCK	58	/* File locking deadlock error */
-#define	EBFONT		59	/* Bad font file format */
-#define	ENOSTR		60	/* Device not a stream */
-#define	ENODATA		61	/* No data available */
-#define	ETIME		62	/* Timer expired */
-#define	ENOSR		63	/* Out of streams resources */
-#define	ENONET		64	/* Machine is not on the network */
-#define	ENOPKG		65	/* Package not installed */
-#define	EREMOTE		66	/* Object is remote */
-#define	ENOLINK		67	/* Link has been severed */
-#define	EADV		68	/* Advertise error */
-#define	ESRMNT		69	/* Srmount error */
-#define	ECOMM		70	/* Communication error on send */
-#define	EPROTO		71	/* Protocol error */
-#define	EMULTIHOP	72	/* Multihop attempted */
-#define	EDOTDOT		73	/* RFS specific error */
-#define	EBADMSG		74	/* Not a data message */
-#define	EOVERFLOW	75	/* Value too large for defined data type */
-#define	ENOTUNIQ	76	/* Name not unique on network */
-#define	EBADFD		77	/* File descriptor in bad state */
-#define	EREMCHG		78	/* Remote address changed */
-#define	ELIBACC		79	/* Can not access a needed shared library */
-#define	ELIBBAD		80	/* Accessing a corrupted shared library */
-#define	ELIBSCN		81	/* .lib section in a.out corrupted */
-#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
-#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
-#define	EILSEQ		84	/* Illegal byte sequence */
-#define	ERESTART	85	/* Interrupted system call should be restarted */
-#define	ESTRPIPE	86	/* Streams pipe error */
-#define	EUSERS		87	/* Too many users */
-#define	ENOTSOCK	88	/* Socket operation on non-socket */
-#define	EDESTADDRREQ	89	/* Destination address required */
-#define	EMSGSIZE	90	/* Message too long */
-#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
-#define	ENOPROTOOPT	92	/* Protocol not available */
-#define	EPROTONOSUPPORT	93	/* Protocol not supported */
-#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
-#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
-#define	EPFNOSUPPORT	96	/* Protocol family not supported */
-#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
-#define	EADDRINUSE	98	/* Address already in use */
-#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
-#define	ENETDOWN	100	/* Network is down */
-#define	ENETUNREACH	101	/* Network is unreachable */
-#define	ENETRESET	102	/* Network dropped connection because of reset */
-#define	ECONNABORTED	103	/* Software caused connection abort */
-#define	ECONNRESET	104	/* Connection reset by peer */
-#define	ENOBUFS		105	/* No buffer space available */
-#define	EISCONN		106	/* Transport endpoint is already connected */
-#define	ENOTCONN	107	/* Transport endpoint is not connected */
-#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
-#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
-#define	ETIMEDOUT	110	/* Connection timed out */
-#define	ECONNREFUSED	111	/* Connection refused */
-#define	EHOSTDOWN	112	/* Host is down */
-#define	EHOSTUNREACH	113	/* No route to host */
-#define	EALREADY	114	/* Operation already in progress */
-#define	EINPROGRESS	115	/* Operation now in progress */
-#define	ESTALE		116	/* Stale NFS file handle */
-#define	EUCLEAN		117	/* Structure needs cleaning */
-#define	ENOTNAM		118	/* Not a XENIX named type file */
-#define	ENAVAIL		119	/* No XENIX semaphores available */
-#define	EISNAM		120	/* Is a named type file */
-#define	EREMOTEIO	121	/* Remote I/O error */
-#define	EDQUOT		122	/* Quota exceeded */
+#include <asm-generic/errno.h>
 
-#define	ENOMEDIUM	123	/* No medium found */
-#define	EMEDIUMTYPE	124	/* Wrong medium type */
+#undef	EDEADLOCK
+#define	EDEADLOCK	58	/* File locking deadlock error */
 
 /* Should never be seen by user programs */
 #define ERESTARTSYS	512
diff -Nru a/include/asm-ppc/hardirq.h b/include/asm-ppc/hardirq.h
--- a/include/asm-ppc/hardirq.h	Wed May 29 11:43:01 2002
+++ b/include/asm-ppc/hardirq.h	Wed May 29 11:43:01 2002
@@ -59,7 +59,7 @@
 	for (i = 0; i < smp_num_cpus; i++)
 		if (local_irq_count(i))
 			return 1;
-		return 0;
+	return 0;
 }
 
 static inline void release_irqlock(int cpu)
diff -Nru a/include/asm-ppc/i8259.h b/include/asm-ppc/i8259.h
--- a/include/asm-ppc/i8259.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ppc/i8259.h	Wed May 29 11:43:02 2002
@@ -9,8 +9,7 @@
 
 extern struct hw_interrupt_type i8259_pic;
 
-void i8259_init(long);
-int i8259_irq(struct pt_regs *regs);
-int i8259_poll(void);
+extern void i8259_init(long intack_addr);
+extern int i8259_irq(struct pt_regs *regs);
 
 #endif /* _PPC_KERNEL_i8259_H */
diff -Nru a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h
--- a/include/asm-ppc/ibm4xx.h	Wed May 29 11:43:03 2002
+++ b/include/asm-ppc/ibm4xx.h	Wed May 29 11:43:03 2002
@@ -16,7 +16,7 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_4xx
+#ifdef CONFIG_40x
 
 #if defined(CONFIG_ASH)
 #include <platforms/ash.h>
@@ -54,9 +54,7 @@
 #define PPC4xx_MACHINE_NAME	"Unidentified 4xx class"
 #endif
 
-#ifndef NR_BOARD_IRQS
-#define NR_BOARD_IRQS 0
-#endif
+
 
 /* IO_BASE is for PCI I/O.
  * ISA not supported, just here to resolve copilation.
@@ -95,6 +93,6 @@
 		asm volatile("mtdcr " stringify(rn) ",%0" : : "r" (v));}
 
 #endif /* __ASSEMBLY__ */
-#endif /* CONFIG_4xx */
+#endif /* CONFIG_40x */
 #endif /* __ASM_IBM4XX_H__ */
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h
--- a/include/asm-ppc/ide.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ppc/ide.h	Wed May 29 11:43:02 2002
@@ -100,7 +100,7 @@
 			continue;
 		ide_init_hwif_ports(&hw, base, 0, NULL);
 		hw.irq = ide_default_irq(base);
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 #endif
 }
diff -Nru a/include/asm-ppc/io.h b/include/asm-ppc/io.h
--- a/include/asm-ppc/io.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ppc/io.h	Wed May 29 11:43:02 2002
@@ -26,7 +26,7 @@
 #define PREP_ISA_MEM_BASE 	0xc0000000
 #define PREP_PCI_DRAM_OFFSET 	0x80000000
 
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_40x)
 #include <asm/ibm4xx.h>
 #elif defined(CONFIG_8xx)
 #include <asm/mpc8xx.h>
@@ -412,11 +412,43 @@
 	return 0;
 }
 
-/* Nothing to do */
+#ifdef CONFIG_NOT_COHERENT_CACHE
+
+/*
+ * DMA-consistent mapping functions for PowerPCs that don't support
+ * cache snooping.  These allocate/free a region of uncached mapped
+ * memory space for use with DMA devices.  Alternatively, you could
+ * allocate the space "normally" and use the cache management functions
+ * to ensure it is consistent.
+ */
+extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle);
+extern void consistent_free(void *vaddr);
+extern void consistent_sync(void *vaddr, size_t size, int rw);
+extern void consistent_sync_page(struct page *page, unsigned long offset,
+				 size_t size, int rw);
+
+#define dma_cache_inv(_start,_size) \
+	invalidate_dcache_range(_start, (_start + _size))
+#define dma_cache_wback(_start,_size) \
+	clean_dcache_range(_start, (_start + _size))
+#define dma_cache_wback_inv(_start,_size) \
+	flush_dcache_range(_start, (_start + _size))
+
+#else /* ! CONFIG_NOT_COHERENT_CACHE */
+
+/*
+ * Cache coherent cores.
+ */
 
 #define dma_cache_inv(_start,_size)		do { } while (0)
 #define dma_cache_wback(_start,_size)		do { } while (0)
 #define dma_cache_wback_inv(_start,_size)	do { } while (0)
 
-#endif
+#define consistent_alloc(gfp, size, handle)	NULL
+#define consistent_free(addr, size)		do { } while (0)
+#define consistent_sync(addr, size, rw)		do { } while (0)
+#define consistent_sync_page(pg, off, sz, rw)	do { } while (0)
+
+#endif /* ! CONFIG_NOT_COHERENT_CACHE */
+#endif /* _PPC_IO_H */
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h
--- a/include/asm-ppc/irq.h	Wed May 29 11:43:01 2002
+++ b/include/asm-ppc/irq.h	Wed May 29 11:43:01 2002
@@ -13,8 +13,22 @@
 extern void disable_irq_nosync(unsigned int);
 extern void enable_irq(unsigned int);
 
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_40x)
 #include <asm/ibm4xx.h>
+
+#ifndef NR_BOARD_IRQS
+#define NR_BOARD_IRQS 0
+#endif
+
+#ifndef UIC_WIDTH /* Number of interrupts per device */
+#define UIC_WIDTH 32
+#endif
+
+#ifndef NR_UICS /* number  of UIC devices */
+#define NR_UICS 1
+#endif
+
+#if defined (CONFIG_403)
 /*
  * The PowerPC 403 cores' Asynchronous Interrupt Controller (AIC) has
  * 32 possible interrupts, a majority of which are not implemented on
@@ -22,26 +36,36 @@
  * there are eight internal interrupts for the on-chip serial port
  * (SPU), DMA controller, and JTAG controller.
  *
- * The PowerPC 405 cores' Universal Interrupt Controller (UIC) has 32
+ */
+
+#define	NR_AIC_IRQS 32 
+#define	NR_IRQS	 (NR_AIC_IRQS + NR_BOARD_IRQS)
+
+#elif !defined (CONFIG_403)
+
+/*
+ *  The PowerPC 405 cores' Universal Interrupt Controller (UIC) has 32
  * possible interrupts as well. There are seven, configurable external
  * interrupt pins and there are 17 internal interrupts for the on-chip
  * serial port, DMA controller, on-chip Ethernet controller, PCI, etc.
  *
  */
 
-#define	NR_AIC_IRQS	32
-#define	NR_IRQS		(NR_AIC_IRQS + NR_BOARD_IRQS)
 
+#define NR_UIC_IRQS UIC_WIDTH
+#define NR_IRQS		((NR_UIC_IRQS * NR_UICS) + NR_BOARD_IRQS)
+#endif
 static __inline__ int
 irq_cannonicalize(int irq)
 {
 	return (irq);
 }
 
-#elif defined (CONFIG_NP405)
+#elif defined(CONFIG_440)
+#include <asm/ibm440.h>
 
-#define NR_AIC_IRQS	32
-#define NR_IRQS		(NR_AIC_IRQS + NR_BOARD_IRQS)
+#define	NR_UIC_IRQS	64
+#define	NR_IRQS		(NR_UIC_IRQS + NR_BOARD_IRQS)
 
 static __inline__ int
 irq_cannonicalize(int irq)
@@ -119,7 +143,7 @@
 	return irq;
 }
 
-#else /* CONFIG_4xx + CONFIG_8xx */
+#else /* CONFIG_40x + CONFIG_8xx */
 /*
  * this is the # irq's for all ppc arch's (pmac/chrp/prep)
  * so it is the max of them all
diff -Nru a/include/asm-ppc/pgalloc.h b/include/asm-ppc/pgalloc.h
--- a/include/asm-ppc/pgalloc.h	Wed May 29 11:43:01 2002
+++ b/include/asm-ppc/pgalloc.h	Wed May 29 11:43:01 2002
@@ -20,6 +20,7 @@
  */
 #define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); })
 #define pmd_free(x)                     do { } while (0)
+#define pmd_free_tlb(tlb,x)		do { } while (0)
 #define pgd_populate(mm, pmd, pte)      BUG()
 
 #define pmd_populate_kernel(mm, pmd, pte)	\
@@ -31,6 +32,8 @@
 extern struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr);
 extern void pte_free_kernel(pte_t *pte);
 extern void pte_free(struct page *pte);
+
+#define pte_free_tlb(tlb, pte)	pte_free((pte))
 
 #define check_pgt_cache()	do { } while (0)
 
diff -Nru a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
--- a/include/asm-ppc/pgtable.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ppc/pgtable.h	Wed May 29 11:43:02 2002
@@ -125,9 +125,9 @@
  * (hardware-defined) PowerPC PTE as closely as possible.
  */
 
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_40x)
 
-/* There are several potential gotchas here.  The 4xx hardware TLBLO
+/* There are several potential gotchas here.  The 40x hardware TLBLO
    field looks like this:
 
    0  1  2  3  4  ... 18 19 20 21 22 23 24 25 26 27 28 29 30 31
@@ -135,7 +135,7 @@
 
    Where possible we make the Linux PTE bits match up with this
 
-   - bits 20 and 21 must be cleared, because we use 4k pages (4xx can
+   - bits 20 and 21 must be cleared, because we use 4k pages (40x can
      support down to 1k pages), this is done in the TLBMiss exception
      handler.
    - We use only zones 0 (for kernel pages) and 1 (for user pages)
@@ -143,7 +143,7 @@
      miss handler.  Bit 27 is PAGE_USER, thus selecting the correct
      zone.
    - PRESENT *must* be in the bottom two bits because swap cache
-     entries use the top 30 bits.  Because 4xx doesn't support SMP
+     entries use the top 30 bits.  Because 40x doesn't support SMP
      anyway, M is irrelevant so we borrow it for PAGE_PRESENT.  Bit 30
      is cleared in the TLB miss handler before the TLB entry is loaded.
    - All other bits of the PTE are loaded into TLBLO without
@@ -153,7 +153,7 @@
      PRESENT.
 */
 
-/* Definitions for 4xx embedded chips. */
+/* Definitions for 40x embedded chips. */
 #define	_PAGE_GUARDED	0x001	/* G: page is guarded from prefetch */
 #define _PAGE_PRESENT	0x002	/* software: PTE contains a translation */
 #define	_PAGE_NO_CACHE	0x004	/* I: caching is inhibited */
@@ -451,7 +451,7 @@
 
 /* Find an entry in the third-level page table.. */
 #define __pte_offset(address)		\
-	((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+	(((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
 #define pte_offset_kernel(dir, addr)	\
 	((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(addr))
 #define pte_offset_map(dir, addr)		\
diff -Nru a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h
--- a/include/asm-ppc/serial.h	Wed May 29 11:43:03 2002
+++ b/include/asm-ppc/serial.h	Wed May 29 11:43:03 2002
@@ -33,7 +33,7 @@
 #include <platforms/spruce_serial.h>
 #elif defined(CONFIG_ZX4500)
 #include <platforms/zx4500_serial.h>
-#elif defined(CONFIG_4xx)
+#elif defined(CONFIG_40x)
 #include <asm/ibm4xx.h>
 #else
 
diff -Nru a/include/asm-ppc/siginfo.h b/include/asm-ppc/siginfo.h
--- a/include/asm-ppc/siginfo.h	Wed May 29 11:43:01 2002
+++ b/include/asm-ppc/siginfo.h	Wed May 29 11:43:01 2002
@@ -4,231 +4,6 @@
 #ifndef _PPC_SIGINFO_H
 #define _PPC_SIGINFO_H
 
-/* Copied from i386 from alpha. */
-
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE];
-
-		/* kill() */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
-			int _status;		/* exit code */
-			clock_t _utime;
-			clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-		struct {
-			void *_addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} siginfo_t;
-
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
-
-/*
- * si_code values
- */
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
-#define SI_TKILL	-6		/* sent by tkill system call */
-#define SI_DETHREAD	-7		/* sent by execve() killing subsidiary threads */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
-
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
-#endif /* __KERNEL__ */
+#include <asm-generic/siginfo.h>
 
 #endif
diff -Nru a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h
--- a/include/asm-ppc/spinlock.h	Wed May 29 11:43:02 2002
+++ b/include/asm-ppc/spinlock.h	Wed May 29 11:43:02 2002
@@ -65,7 +65,7 @@
 	lock->lock = 0;
 }
 
-#define _raw_spin_trylock(lock) (!test_and_set_bit(0,(lock)))
+#define _raw_spin_trylock(l) (!test_and_set_bit(0,&(l)->lock))
 
 #else
 
diff -Nru a/include/asm-ppc/time.h b/include/asm-ppc/time.h
--- a/include/asm-ppc/time.h	Wed May 29 11:43:01 2002
+++ b/include/asm-ppc/time.h	Wed May 29 11:43:01 2002
@@ -43,7 +43,7 @@
  */
 static __inline__ unsigned int get_dec(void)
 {
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_40x)
 	return (mfspr(SPRN_PIT));
 #else
 	return (mfspr(SPRN_DEC));
@@ -52,7 +52,7 @@
 
 static __inline__ void set_dec(unsigned int val)
 {
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_40x)
 	return;		/* Have to let it auto-reload */
 #elif defined(CONFIG_8xx_CPU6)
 	set_dec_cpu6(val);
diff -Nru a/include/asm-ppc64/errno.h b/include/asm-ppc64/errno.h
--- a/include/asm-ppc64/errno.h	Wed May 29 11:43:01 2002
+++ b/include/asm-ppc64/errno.h	Wed May 29 11:43:01 2002
@@ -8,131 +8,10 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
-#define	EDEADLK		35	/* Resource deadlock would occur */
-#define	ENAMETOOLONG	36	/* File name too long */
-#define	ENOLCK		37	/* No record locks available */
-#define	ENOSYS		38	/* Function not implemented */
-#define	ENOTEMPTY	39	/* Directory not empty */
-#define	ELOOP		40	/* Too many symbolic links encountered */
-#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
-#define	ENOMSG		42	/* No message of desired type */
-#define	EIDRM		43	/* Identifier removed */
-#define	ECHRNG		44	/* Channel number out of range */
-#define	EL2NSYNC	45	/* Level 2 not synchronized */
-#define	EL3HLT		46	/* Level 3 halted */
-#define	EL3RST		47	/* Level 3 reset */
-#define	ELNRNG		48	/* Link number out of range */
-#define	EUNATCH		49	/* Protocol driver not attached */
-#define	ENOCSI		50	/* No CSI structure available */
-#define	EL2HLT		51	/* Level 2 halted */
-#define	EBADE		52	/* Invalid exchange */
-#define	EBADR		53	/* Invalid request descriptor */
-#define	EXFULL		54	/* Exchange full */
-#define	ENOANO		55	/* No anode */
-#define	EBADRQC		56	/* Invalid request code */
-#define	EBADSLT		57	/* Invalid slot */
-#define	EDEADLOCK	58	/* File locking deadlock error */
-#define	EBFONT		59	/* Bad font file format */
-#define	ENOSTR		60	/* Device not a stream */
-#define	ENODATA		61	/* No data available */
-#define	ETIME		62	/* Timer expired */
-#define	ENOSR		63	/* Out of streams resources */
-#define	ENONET		64	/* Machine is not on the network */
-#define	ENOPKG		65	/* Package not installed */
-#define	EREMOTE		66	/* Object is remote */
-#define	ENOLINK		67	/* Link has been severed */
-#define	EADV		68	/* Advertise error */
-#define	ESRMNT		69	/* Srmount error */
-#define	ECOMM		70	/* Communication error on send */
-#define	EPROTO		71	/* Protocol error */
-#define	EMULTIHOP	72	/* Multihop attempted */
-#define	EDOTDOT		73	/* RFS specific error */
-#define	EBADMSG		74	/* Not a data message */
-#define	EOVERFLOW	75	/* Value too large for defined data type */
-#define	ENOTUNIQ	76	/* Name not unique on network */
-#define	EBADFD		77	/* File descriptor in bad state */
-#define	EREMCHG		78	/* Remote address changed */
-#define	ELIBACC		79	/* Can not access a needed shared library */
-#define	ELIBBAD		80	/* Accessing a corrupted shared library */
-#define	ELIBSCN		81	/* .lib section in a.out corrupted */
-#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
-#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
-#define	EILSEQ		84	/* Illegal byte sequence */
-#define	ERESTART	85	/* Interrupted system call should be restarted */
-#define	ESTRPIPE	86	/* Streams pipe error */
-#define	EUSERS		87	/* Too many users */
-#define	ENOTSOCK	88	/* Socket operation on non-socket */
-#define	EDESTADDRREQ	89	/* Destination address required */
-#define	EMSGSIZE	90	/* Message too long */
-#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
-#define	ENOPROTOOPT	92	/* Protocol not available */
-#define	EPROTONOSUPPORT	93	/* Protocol not supported */
-#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
-#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
-#define	EPFNOSUPPORT	96	/* Protocol family not supported */
-#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
-#define	EADDRINUSE	98	/* Address already in use */
-#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
-#define	ENETDOWN	100	/* Network is down */
-#define	ENETUNREACH	101	/* Network is unreachable */
-#define	ENETRESET	102	/* Network dropped connection because of reset */
-#define	ECONNABORTED	103	/* Software caused connection abort */
-#define	ECONNRESET	104	/* Connection reset by peer */
-#define	ENOBUFS		105	/* No buffer space available */
-#define	EISCONN		106	/* Transport endpoint is already connected */
-#define	ENOTCONN	107	/* Transport endpoint is not connected */
-#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
-#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
-#define	ETIMEDOUT	110	/* Connection timed out */
-#define	ECONNREFUSED	111	/* Connection refused */
-#define	EHOSTDOWN	112	/* Host is down */
-#define	EHOSTUNREACH	113	/* No route to host */
-#define	EALREADY	114	/* Operation already in progress */
-#define	EINPROGRESS	115	/* Operation now in progress */
-#define	ESTALE		116	/* Stale NFS file handle */
-#define	EUCLEAN		117	/* Structure needs cleaning */
-#define	ENOTNAM		118	/* Not a XENIX named type file */
-#define	ENAVAIL		119	/* No XENIX semaphores available */
-#define	EISNAM		120	/* Is a named type file */
-#define	EREMOTEIO	121	/* Remote I/O error */
-#define	EDQUOT		122	/* Quota exceeded */
+#include <asm-generic/errno.h>
 
-#define	ENOMEDIUM	123	/* No medium found */
-#define	EMEDIUMTYPE	124	/* Wrong medium type */
+#undef	EDEADLOCK
+#define	EDEADLOCK	58	/* File locking deadlock error */
 
 /* Should never be seen by user programs */
 #define ERESTARTSYS	512
diff -Nru a/include/asm-ppc64/siginfo.h b/include/asm-ppc64/siginfo.h
--- a/include/asm-ppc64/siginfo.h	Wed May 29 11:43:03 2002
+++ b/include/asm-ppc64/siginfo.h	Wed May 29 11:43:03 2002
@@ -8,232 +8,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/types.h>
-
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE];
-
-		/* kill() */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
-			int _status;		/* exit code */
-			clock_t _utime;
-			clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-		struct {
-			void *_addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} siginfo_t;
-
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
-
-/*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
-#define SI_TKILL	-6		/* sent by tkill system call */
-#define SI_DETHREAD	-7		/* sent by execve() killing subsidiary threads */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
-
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-static inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
-#endif /* __KERNEL__ */
+#include <asm-generic/siginfo.h>
 
 #endif /* _PPC64_SIGINFO_H */
diff -Nru a/include/asm-s390/errno.h b/include/asm-s390/errno.h
--- a/include/asm-s390/errno.h	Wed May 29 11:43:01 2002
+++ b/include/asm-s390/errno.h	Wed May 29 11:43:01 2002
@@ -3,138 +3,11 @@
  *
  *  S390 version
  *
- *  Derived from "include/asm-i386/errno.h"
  */
 
 #ifndef _S390_ERRNO_H
 #define _S390_ERRNO_H
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
-#define	EDEADLK		35	/* Resource deadlock would occur */
-#define	ENAMETOOLONG	36	/* File name too long */
-#define	ENOLCK		37	/* No record locks available */
-#define	ENOSYS		38	/* Function not implemented */
-#define	ENOTEMPTY	39	/* Directory not empty */
-#define	ELOOP		40	/* Too many symbolic links encountered */
-#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
-#define	ENOMSG		42	/* No message of desired type */
-#define	EIDRM		43	/* Identifier removed */
-#define	ECHRNG		44	/* Channel number out of range */
-#define	EL2NSYNC	45	/* Level 2 not synchronized */
-#define	EL3HLT		46	/* Level 3 halted */
-#define	EL3RST		47	/* Level 3 reset */
-#define	ELNRNG		48	/* Link number out of range */
-#define	EUNATCH		49	/* Protocol driver not attached */
-#define	ENOCSI		50	/* No CSI structure available */
-#define	EL2HLT		51	/* Level 2 halted */
-#define	EBADE		52	/* Invalid exchange */
-#define	EBADR		53	/* Invalid request descriptor */
-#define	EXFULL		54	/* Exchange full */
-#define	ENOANO		55	/* No anode */
-#define	EBADRQC		56	/* Invalid request code */
-#define	EBADSLT		57	/* Invalid slot */
-
-#define	EDEADLOCK	EDEADLK
-
-#define	EBFONT		59	/* Bad font file format */
-#define	ENOSTR		60	/* Device not a stream */
-#define	ENODATA		61	/* No data available */
-#define	ETIME		62	/* Timer expired */
-#define	ENOSR		63	/* Out of streams resources */
-#define	ENONET		64	/* Machine is not on the network */
-#define	ENOPKG		65	/* Package not installed */
-#define	EREMOTE		66	/* Object is remote */
-#define	ENOLINK		67	/* Link has been severed */
-#define	EADV		68	/* Advertise error */
-#define	ESRMNT		69	/* Srmount error */
-#define	ECOMM		70	/* Communication error on send */
-#define	EPROTO		71	/* Protocol error */
-#define	EMULTIHOP	72	/* Multihop attempted */
-#define	EDOTDOT		73	/* RFS specific error */
-#define	EBADMSG		74	/* Not a data message */
-#define	EOVERFLOW	75	/* Value too large for defined data type */
-#define	ENOTUNIQ	76	/* Name not unique on network */
-#define	EBADFD		77	/* File descriptor in bad state */
-#define	EREMCHG		78	/* Remote address changed */
-#define	ELIBACC		79	/* Can not access a needed shared library */
-#define	ELIBBAD		80	/* Accessing a corrupted shared library */
-#define	ELIBSCN		81	/* .lib section in a.out corrupted */
-#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
-#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
-#define	EILSEQ		84	/* Illegal byte sequence */
-#define	ERESTART	85	/* Interrupted system call should be restarted */
-#define	ESTRPIPE	86	/* Streams pipe error */
-#define	EUSERS		87	/* Too many users */
-#define	ENOTSOCK	88	/* Socket operation on non-socket */
-#define	EDESTADDRREQ	89	/* Destination address required */
-#define	EMSGSIZE	90	/* Message too long */
-#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
-#define	ENOPROTOOPT	92	/* Protocol not available */
-#define	EPROTONOSUPPORT	93	/* Protocol not supported */
-#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
-#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
-#define	EPFNOSUPPORT	96	/* Protocol family not supported */
-#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
-#define	EADDRINUSE	98	/* Address already in use */
-#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
-#define	ENETDOWN	100	/* Network is down */
-#define	ENETUNREACH	101	/* Network is unreachable */
-#define	ENETRESET	102	/* Network dropped connection because of reset */
-#define	ECONNABORTED	103	/* Software caused connection abort */
-#define	ECONNRESET	104	/* Connection reset by peer */
-#define	ENOBUFS		105	/* No buffer space available */
-#define	EISCONN		106	/* Transport endpoint is already connected */
-#define	ENOTCONN	107	/* Transport endpoint is not connected */
-#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
-#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
-#define	ETIMEDOUT	110	/* Connection timed out */
-#define	ECONNREFUSED	111	/* Connection refused */
-#define	EHOSTDOWN	112	/* Host is down */
-#define	EHOSTUNREACH	113	/* No route to host */
-#define	EALREADY	114	/* Operation already in progress */
-#define	EINPROGRESS	115	/* Operation now in progress */
-#define	ESTALE		116	/* Stale NFS file handle */
-#define	EUCLEAN		117	/* Structure needs cleaning */
-#define	ENOTNAM		118	/* Not a XENIX named type file */
-#define	ENAVAIL		119	/* No XENIX semaphores available */
-#define	EISNAM		120	/* Is a named type file */
-#define	EREMOTEIO	121	/* Remote I/O error */
-#define	EDQUOT		122	/* Quota exceeded */
-
-#define	ENOMEDIUM	123	/* No medium found */
-#define	EMEDIUMTYPE	124	/* Wrong medium type */
+#include <asm-generic/errno.h>
 
 #endif
diff -Nru a/include/asm-s390/siginfo.h b/include/asm-s390/siginfo.h
--- a/include/asm-s390/siginfo.h	Wed May 29 11:43:02 2002
+++ b/include/asm-s390/siginfo.h	Wed May 29 11:43:02 2002
@@ -9,116 +9,16 @@
 #ifndef _S390_SIGINFO_H
 #define _S390_SIGINFO_H
 
-#include <linux/types.h>
+#define HAVE_ARCH_SI_CODES
 
-/* XXX: This structure was copied from the Alpha; is there an iBCS version?  */
-
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE];
-
-		/* kill() */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
-			int _status;		/* exit code */
-			clock_t _utime;
-			clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-		struct {
-			void *_addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} siginfo_t;
-
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
+#include <asm-generic/siginfo.h>
 
 /*
  * si_code values
  * Digital reserves positive values for kernel-generated signals.
  */
-#define SI_USER		0	/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80	/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1	/* sent by sigqueue */
+#undef SI_TIMER
 #define SI_TIMER	-2	/* sent by timer expiration */
-#define SI_MESGQ	-3	/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4	/* sent by AIO completion */
-#define SI_SIGIO	-5	/* sent by queued SIGIO */
-#define SI_TKILL	-6	/* sent by tkill system call */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
 
 /*
  * SIGILL si_codes
@@ -177,7 +77,7 @@
 #define CLD_TRAPPED	4	/* traced child has trapped */
 #define CLD_STOPPED	5	/* child has stopped */
 #define CLD_CONTINUED	6	/* stopped child has continued */
-#define NSIGCHLD
+#define NSIGCHLD	6
 
 /*
  * SIGPOLL si_codes
@@ -189,53 +89,5 @@
 #define POLL_PRI	5	/* high priority input available */
 #define POLL_HUP	6	/* device disconnected */
 #define NSIGPOLL	6
-
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
-#endif /* __KERNEL__ */
 
 #endif
diff -Nru a/include/asm-s390x/errno.h b/include/asm-s390x/errno.h
--- a/include/asm-s390x/errno.h	Wed May 29 11:43:01 2002
+++ b/include/asm-s390x/errno.h	Wed May 29 11:43:01 2002
@@ -2,139 +2,11 @@
  *  include/asm-s390/errno.h
  *
  *  S390 version
- *
- *  Derived from "include/asm-i386/errno.h"
  */
 
 #ifndef _S390_ERRNO_H
 #define _S390_ERRNO_H
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
-#define	EDEADLK		35	/* Resource deadlock would occur */
-#define	ENAMETOOLONG	36	/* File name too long */
-#define	ENOLCK		37	/* No record locks available */
-#define	ENOSYS		38	/* Function not implemented */
-#define	ENOTEMPTY	39	/* Directory not empty */
-#define	ELOOP		40	/* Too many symbolic links encountered */
-#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
-#define	ENOMSG		42	/* No message of desired type */
-#define	EIDRM		43	/* Identifier removed */
-#define	ECHRNG		44	/* Channel number out of range */
-#define	EL2NSYNC	45	/* Level 2 not synchronized */
-#define	EL3HLT		46	/* Level 3 halted */
-#define	EL3RST		47	/* Level 3 reset */
-#define	ELNRNG		48	/* Link number out of range */
-#define	EUNATCH		49	/* Protocol driver not attached */
-#define	ENOCSI		50	/* No CSI structure available */
-#define	EL2HLT		51	/* Level 2 halted */
-#define	EBADE		52	/* Invalid exchange */
-#define	EBADR		53	/* Invalid request descriptor */
-#define	EXFULL		54	/* Exchange full */
-#define	ENOANO		55	/* No anode */
-#define	EBADRQC		56	/* Invalid request code */
-#define	EBADSLT		57	/* Invalid slot */
-
-#define	EDEADLOCK	EDEADLK
-
-#define	EBFONT		59	/* Bad font file format */
-#define	ENOSTR		60	/* Device not a stream */
-#define	ENODATA		61	/* No data available */
-#define	ETIME		62	/* Timer expired */
-#define	ENOSR		63	/* Out of streams resources */
-#define	ENONET		64	/* Machine is not on the network */
-#define	ENOPKG		65	/* Package not installed */
-#define	EREMOTE		66	/* Object is remote */
-#define	ENOLINK		67	/* Link has been severed */
-#define	EADV		68	/* Advertise error */
-#define	ESRMNT		69	/* Srmount error */
-#define	ECOMM		70	/* Communication error on send */
-#define	EPROTO		71	/* Protocol error */
-#define	EMULTIHOP	72	/* Multihop attempted */
-#define	EDOTDOT		73	/* RFS specific error */
-#define	EBADMSG		74	/* Not a data message */
-#define	EOVERFLOW	75	/* Value too large for defined data type */
-#define	ENOTUNIQ	76	/* Name not unique on network */
-#define	EBADFD		77	/* File descriptor in bad state */
-#define	EREMCHG		78	/* Remote address changed */
-#define	ELIBACC		79	/* Can not access a needed shared library */
-#define	ELIBBAD		80	/* Accessing a corrupted shared library */
-#define	ELIBSCN		81	/* .lib section in a.out corrupted */
-#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
-#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
-#define	EILSEQ		84	/* Illegal byte sequence */
-#define	ERESTART	85	/* Interrupted system call should be restarted */
-#define	ESTRPIPE	86	/* Streams pipe error */
-#define	EUSERS		87	/* Too many users */
-#define	ENOTSOCK	88	/* Socket operation on non-socket */
-#define	EDESTADDRREQ	89	/* Destination address required */
-#define	EMSGSIZE	90	/* Message too long */
-#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
-#define	ENOPROTOOPT	92	/* Protocol not available */
-#define	EPROTONOSUPPORT	93	/* Protocol not supported */
-#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
-#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
-#define	EPFNOSUPPORT	96	/* Protocol family not supported */
-#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
-#define	EADDRINUSE	98	/* Address already in use */
-#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
-#define	ENETDOWN	100	/* Network is down */
-#define	ENETUNREACH	101	/* Network is unreachable */
-#define	ENETRESET	102	/* Network dropped connection because of reset */
-#define	ECONNABORTED	103	/* Software caused connection abort */
-#define	ECONNRESET	104	/* Connection reset by peer */
-#define	ENOBUFS		105	/* No buffer space available */
-#define	EISCONN		106	/* Transport endpoint is already connected */
-#define	ENOTCONN	107	/* Transport endpoint is not connected */
-#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
-#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
-#define	ETIMEDOUT	110	/* Connection timed out */
-#define	ECONNREFUSED	111	/* Connection refused */
-#define	EHOSTDOWN	112	/* Host is down */
-#define	EHOSTUNREACH	113	/* No route to host */
-#define	EALREADY	114	/* Operation already in progress */
-#define	EINPROGRESS	115	/* Operation now in progress */
-#define	ESTALE		116	/* Stale NFS file handle */
-#define	EUCLEAN		117	/* Structure needs cleaning */
-#define	ENOTNAM		118	/* Not a XENIX named type file */
-#define	ENAVAIL		119	/* No XENIX semaphores available */
-#define	EISNAM		120	/* Is a named type file */
-#define	EREMOTEIO	121	/* Remote I/O error */
-#define	EDQUOT		122	/* Quota exceeded */
-
-#define	ENOMEDIUM	123	/* No medium found */
-#define	EMEDIUMTYPE	124	/* Wrong medium type */
+#include <asm-generic/errno.h>
 
 #endif
diff -Nru a/include/asm-s390x/siginfo.h b/include/asm-s390x/siginfo.h
--- a/include/asm-s390x/siginfo.h	Wed May 29 11:43:03 2002
+++ b/include/asm-s390x/siginfo.h	Wed May 29 11:43:03 2002
@@ -9,116 +9,16 @@
 #ifndef _S390_SIGINFO_H
 #define _S390_SIGINFO_H
 
-#include <linux/types.h>
+#define HAVE_ARCH_SI_CODES
 
-/* XXX: This structure was copied from the Alpha; is there an iBCS version?  */
-
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE];
-
-		/* kill() */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
-			int _status;		/* exit code */
-			clock_t _utime;
-			clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-		struct {
-			void *_addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} siginfo_t;
-
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
+#include <asm-generic/siginfo.h>
 
 /*
  * si_code values
  * Digital reserves positive values for kernel-generated signals.
  */
-#define SI_USER		0	/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80	/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1	/* sent by sigqueue */
+#undef SI_TIMER
 #define SI_TIMER	-2	/* sent by timer expiration */
-#define SI_MESGQ	-3	/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4	/* sent by AIO completion */
-#define SI_SIGIO	-5	/* sent by queued SIGIO */
-#define SI_TKILL	-6	/* sent by tkill system call */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
 
 /*
  * SIGILL si_codes
@@ -177,7 +77,7 @@
 #define CLD_TRAPPED	4	/* traced child has trapped */
 #define CLD_STOPPED	5	/* child has stopped */
 #define CLD_CONTINUED	6	/* stopped child has continued */
-#define NSIGCHLD
+#define NSIGCHLD	6
 
 /*
  * SIGPOLL si_codes
@@ -189,53 +89,5 @@
 #define POLL_PRI	5	/* high priority input available */
 #define POLL_HUP	6	/* device disconnected */
 #define NSIGPOLL	6
-
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
-#endif /* __KERNEL__ */
 
 #endif
diff -Nru a/include/asm-sh/errno.h b/include/asm-sh/errno.h
--- a/include/asm-sh/errno.h	Wed May 29 11:43:03 2002
+++ b/include/asm-sh/errno.h	Wed May 29 11:43:03 2002
@@ -1,132 +1,6 @@
 #ifndef __ASM_SH_ERRNO_H
 #define __ASM_SH_ERRNO_H
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
-#define	EDEADLK		35	/* Resource deadlock would occur */
-#define	ENAMETOOLONG	36	/* File name too long */
-#define	ENOLCK		37	/* No record locks available */
-#define	ENOSYS		38	/* Function not implemented */
-#define	ENOTEMPTY	39	/* Directory not empty */
-#define	ELOOP		40	/* Too many symbolic links encountered */
-#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
-#define	ENOMSG		42	/* No message of desired type */
-#define	EIDRM		43	/* Identifier removed */
-#define	ECHRNG		44	/* Channel number out of range */
-#define	EL2NSYNC	45	/* Level 2 not synchronized */
-#define	EL3HLT		46	/* Level 3 halted */
-#define	EL3RST		47	/* Level 3 reset */
-#define	ELNRNG		48	/* Link number out of range */
-#define	EUNATCH		49	/* Protocol driver not attached */
-#define	ENOCSI		50	/* No CSI structure available */
-#define	EL2HLT		51	/* Level 2 halted */
-#define	EBADE		52	/* Invalid exchange */
-#define	EBADR		53	/* Invalid request descriptor */
-#define	EXFULL		54	/* Exchange full */
-#define	ENOANO		55	/* No anode */
-#define	EBADRQC		56	/* Invalid request code */
-#define	EBADSLT		57	/* Invalid slot */
-
-#define	EDEADLOCK	EDEADLK
-
-#define	EBFONT		59	/* Bad font file format */
-#define	ENOSTR		60	/* Device not a stream */
-#define	ENODATA		61	/* No data available */
-#define	ETIME		62	/* Timer expired */
-#define	ENOSR		63	/* Out of streams resources */
-#define	ENONET		64	/* Machine is not on the network */
-#define	ENOPKG		65	/* Package not installed */
-#define	EREMOTE		66	/* Object is remote */
-#define	ENOLINK		67	/* Link has been severed */
-#define	EADV		68	/* Advertise error */
-#define	ESRMNT		69	/* Srmount error */
-#define	ECOMM		70	/* Communication error on send */
-#define	EPROTO		71	/* Protocol error */
-#define	EMULTIHOP	72	/* Multihop attempted */
-#define	EDOTDOT		73	/* RFS specific error */
-#define	EBADMSG		74	/* Not a data message */
-#define	EOVERFLOW	75	/* Value too large for defined data type */
-#define	ENOTUNIQ	76	/* Name not unique on network */
-#define	EBADFD		77	/* File descriptor in bad state */
-#define	EREMCHG		78	/* Remote address changed */
-#define	ELIBACC		79	/* Can not access a needed shared library */
-#define	ELIBBAD		80	/* Accessing a corrupted shared library */
-#define	ELIBSCN		81	/* .lib section in a.out corrupted */
-#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
-#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
-#define	EILSEQ		84	/* Illegal byte sequence */
-#define	ERESTART	85	/* Interrupted system call should be restarted */
-#define	ESTRPIPE	86	/* Streams pipe error */
-#define	EUSERS		87	/* Too many users */
-#define	ENOTSOCK	88	/* Socket operation on non-socket */
-#define	EDESTADDRREQ	89	/* Destination address required */
-#define	EMSGSIZE	90	/* Message too long */
-#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
-#define	ENOPROTOOPT	92	/* Protocol not available */
-#define	EPROTONOSUPPORT	93	/* Protocol not supported */
-#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
-#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
-#define	EPFNOSUPPORT	96	/* Protocol family not supported */
-#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
-#define	EADDRINUSE	98	/* Address already in use */
-#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
-#define	ENETDOWN	100	/* Network is down */
-#define	ENETUNREACH	101	/* Network is unreachable */
-#define	ENETRESET	102	/* Network dropped connection because of reset */
-#define	ECONNABORTED	103	/* Software caused connection abort */
-#define	ECONNRESET	104	/* Connection reset by peer */
-#define	ENOBUFS		105	/* No buffer space available */
-#define	EISCONN		106	/* Transport endpoint is already connected */
-#define	ENOTCONN	107	/* Transport endpoint is not connected */
-#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
-#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
-#define	ETIMEDOUT	110	/* Connection timed out */
-#define	ECONNREFUSED	111	/* Connection refused */
-#define	EHOSTDOWN	112	/* Host is down */
-#define	EHOSTUNREACH	113	/* No route to host */
-#define	EALREADY	114	/* Operation already in progress */
-#define	EINPROGRESS	115	/* Operation now in progress */
-#define	ESTALE		116	/* Stale NFS file handle */
-#define	EUCLEAN		117	/* Structure needs cleaning */
-#define	ENOTNAM		118	/* Not a XENIX named type file */
-#define	ENAVAIL		119	/* No XENIX semaphores available */
-#define	EISNAM		120	/* Is a named type file */
-#define	EREMOTEIO	121	/* Remote I/O error */
-#define	EDQUOT		122	/* Quota exceeded */
-
-#define	ENOMEDIUM	123	/* No medium found */
-#define	EMEDIUMTYPE	124	/* Wrong medium type */
+#include <asm-generic/errno.h>
 
 #endif /* __ASM_SH_ERRNO_H */
diff -Nru a/include/asm-sh/ide.h b/include/asm-sh/ide.h
--- a/include/asm-sh/ide.h	Wed May 29 11:43:02 2002
+++ b/include/asm-sh/ide.h	Wed May 29 11:43:02 2002
@@ -102,7 +102,7 @@
 	for(index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 #endif
 }
diff -Nru a/include/asm-sh/siginfo.h b/include/asm-sh/siginfo.h
--- a/include/asm-sh/siginfo.h	Wed May 29 11:43:02 2002
+++ b/include/asm-sh/siginfo.h	Wed May 29 11:43:02 2002
@@ -1,233 +1,6 @@
 #ifndef __ASM_SH_SIGINFO_H
 #define __ASM_SH_SIGINFO_H
 
-#include <linux/types.h>
-
-/* XXX: This structure was copied from the Alpha; is there an iBCS version?  */
-
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE];
-
-		/* kill() */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
-			int _status;		/* exit code */
-			clock_t _utime;
-			clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-		struct {
-			void *_addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} siginfo_t;
-
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
-
-/*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
-#define SI_TKILL	-6		/* sent by tkill system call */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
-
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-static inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
-#endif /* __KERNEL__ */
+#include <asm-generic/siginfo.h>
 
 #endif /* __ASM_SH_SIGINFO_H */
diff -Nru a/include/asm-sparc/errno.h b/include/asm-sparc/errno.h
--- a/include/asm-sparc/errno.h	Wed May 29 11:43:02 2002
+++ b/include/asm-sparc/errno.h	Wed May 29 11:43:02 2002
@@ -3,40 +3,9 @@
 #define _SPARC_ERRNO_H
 
 /* These match the SunOS error numbering scheme. */
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
+
+#include <asm-generic/errno-base.h>
+
 #define	EWOULDBLOCK	EAGAIN	/* Operation would block */
 #define	EINPROGRESS	36	/* Operation now in progress */
 #define	EALREADY	37	/* Operation already in progress */
diff -Nru a/include/asm-sparc/ide.h b/include/asm-sparc/ide.h
--- a/include/asm-sparc/ide.h	Wed May 29 11:43:03 2002
+++ b/include/asm-sparc/ide.h	Wed May 29 11:43:03 2002
@@ -68,7 +68,7 @@
 	for (index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 #endif
 }
diff -Nru a/include/asm-sparc/siginfo.h b/include/asm-sparc/siginfo.h
--- a/include/asm-sparc/siginfo.h	Wed May 29 11:43:01 2002
+++ b/include/asm-sparc/siginfo.h	Wed May 29 11:43:01 2002
@@ -5,15 +5,10 @@
 #ifndef _SPARC_SIGINFO_H
 #define _SPARC_SIGINFO_H
 
-#include <linux/types.h>
+#define HAVE_ARCH_SIGINFO_T
+#define HAVE_ARCH_COPY_SIGINFO
 
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
+#include <asm-generic/siginfo.h>
 
 typedef struct siginfo {
 	int si_signo;
@@ -65,128 +60,9 @@
 	} _sifields;
 } siginfo_t;
 
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
 #define si_trapno	_sifields._sigfault._trapno
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
 
-/*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
 #define SI_NOINFO	32767		/* no information in siginfo_t */
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
-#define SI_TKILL	-6		/* sent by tkill system call */
-#define SI_DETHREAD	-7		/* sent by execve() killing subsidiary threads */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
 
 /*
  * SIGEMT si_codes
@@ -194,35 +70,6 @@
 #define EMT_TAGOVF	(__SI_FAULT|1)	/* tag overflow */
 #define NSIGEMT		1
 
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
 #ifdef __KERNEL__
 
 #include <linux/string.h>
@@ -236,11 +83,6 @@
 		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
 }
 
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
 #endif /* __KERNEL__ */
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
 
 #endif /* !(_SPARC_SIGINFO_H) */
diff -Nru a/include/asm-sparc/signal.h b/include/asm-sparc/signal.h
--- a/include/asm-sparc/signal.h	Wed May 29 11:43:03 2002
+++ b/include/asm-sparc/signal.h	Wed May 29 11:43:03 2002
@@ -216,6 +216,8 @@
 	size_t		ss_size;
 } stack_t;
 
+#define HAVE_ARCH_GET_SIGNAL_TO_DELIVER
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_ASMSPARC_SIGNAL_H) */
diff -Nru a/include/asm-sparc64/errno.h b/include/asm-sparc64/errno.h
--- a/include/asm-sparc64/errno.h	Wed May 29 11:43:01 2002
+++ b/include/asm-sparc64/errno.h	Wed May 29 11:43:01 2002
@@ -3,40 +3,9 @@
 #define _SPARC64_ERRNO_H
 
 /* These match the SunOS error numbering scheme. */
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
+
+#include <asm-generic/errno-base.h>
+
 #define	EWOULDBLOCK	EAGAIN	/* Operation would block */
 #define	EINPROGRESS	36	/* Operation now in progress */
 #define	EALREADY	37	/* Operation already in progress */
diff -Nru a/include/asm-sparc64/ide.h b/include/asm-sparc64/ide.h
--- a/include/asm-sparc64/ide.h	Wed May 29 11:43:02 2002
+++ b/include/asm-sparc64/ide.h	Wed May 29 11:43:02 2002
@@ -64,7 +64,7 @@
 	for (index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 #endif
 }
diff -Nru a/include/asm-sparc64/siginfo.h b/include/asm-sparc64/siginfo.h
--- a/include/asm-sparc64/siginfo.h	Wed May 29 11:43:03 2002
+++ b/include/asm-sparc64/siginfo.h	Wed May 29 11:43:03 2002
@@ -1,12 +1,17 @@
 #ifndef _SPARC64_SIGINFO_H
 #define _SPARC64_SIGINFO_H
 
-#include <linux/types.h>
+#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 4)
+#define SI_PAD_SIZE32	((SI_MAX_SIZE/sizeof(int)) - 3)
 
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
+#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
+#define SIGEV_PAD_SIZE32 ((SIGEV_MAX_SIZE/sizeof(int)) - 3)
+
+#define HAVE_ARCH_SIGINFO_T
+
+#define HAVE_ARCH_COPY_SIGINFO
+
+#include <asm-generic/siginfo.h>
 
 #ifdef __KERNEL__
 
@@ -17,10 +22,6 @@
 
 #endif /* __KERNEL__ */
 
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 4)
-#define SI_PAD_SIZE32	((SI_MAX_SIZE/sizeof(int)) - 3)
-
 typedef struct siginfo {
 	int si_signo;
 	int si_errno;
@@ -125,128 +126,9 @@
 
 #endif /* __KERNEL__ */
 
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
 #define si_trapno	_sifields._sigfault._trapno
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
 
-/*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
 #define SI_NOINFO	32767		/* no information in siginfo_t */
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
-#define SI_TKILL	-6		/* sent by tkill system call */
-#define SI_DETHREAD	-7		/* sent by execve() killing subsidiary threads */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
 
 /*
  * SIGEMT si_codes
@@ -254,36 +136,6 @@
 #define EMT_TAGOVF	(__SI_FAULT|1)	/* tag overflow */
 #define NSIGEMT		1
 
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
-#define SIGEV_PAD_SIZE32 ((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
 #ifdef __KERNEL__
 
 typedef struct sigevent32 {
@@ -311,12 +163,8 @@
 		memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigchld));
 }
 
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
 extern int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from);
 
 #endif /* __KERNEL__ */
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
 
 #endif
diff -Nru a/include/asm-sparc64/signal.h b/include/asm-sparc64/signal.h
--- a/include/asm-sparc64/signal.h	Wed May 29 11:43:02 2002
+++ b/include/asm-sparc64/signal.h	Wed May 29 11:43:02 2002
@@ -252,6 +252,9 @@
 	int			ss_flags;
 	__kernel_size_t32	ss_size;
 } stack_t32;
+
+#define HAVE_ARCH_GET_SIGNAL_TO_DELIVER
+
 #endif
 
 #endif /* !(__ASSEMBLY__) */
diff -Nru a/include/asm-x86_64/errno.h b/include/asm-x86_64/errno.h
--- a/include/asm-x86_64/errno.h	Wed May 29 11:43:02 2002
+++ b/include/asm-x86_64/errno.h	Wed May 29 11:43:02 2002
@@ -1,132 +1,6 @@
 #ifndef _X8664_ERRNO_H
 #define _X8664_ERRNO_H
 
-#define	EPERM		 1	/* Operation not permitted */
-#define	ENOENT		 2	/* No such file or directory */
-#define	ESRCH		 3	/* No such process */
-#define	EINTR		 4	/* Interrupted system call */
-#define	EIO		 5	/* I/O error */
-#define	ENXIO		 6	/* No such device or address */
-#define	E2BIG		 7	/* Arg list too long */
-#define	ENOEXEC		 8	/* Exec format error */
-#define	EBADF		 9	/* Bad file number */
-#define	ECHILD		10	/* No child processes */
-#define	EAGAIN		11	/* Try again */
-#define	ENOMEM		12	/* Out of memory */
-#define	EACCES		13	/* Permission denied */
-#define	EFAULT		14	/* Bad address */
-#define	ENOTBLK		15	/* Block device required */
-#define	EBUSY		16	/* Device or resource busy */
-#define	EEXIST		17	/* File exists */
-#define	EXDEV		18	/* Cross-device link */
-#define	ENODEV		19	/* No such device */
-#define	ENOTDIR		20	/* Not a directory */
-#define	EISDIR		21	/* Is a directory */
-#define	EINVAL		22	/* Invalid argument */
-#define	ENFILE		23	/* File table overflow */
-#define	EMFILE		24	/* Too many open files */
-#define	ENOTTY		25	/* Not a typewriter */
-#define	ETXTBSY		26	/* Text file busy */
-#define	EFBIG		27	/* File too large */
-#define	ENOSPC		28	/* No space left on device */
-#define	ESPIPE		29	/* Illegal seek */
-#define	EROFS		30	/* Read-only file system */
-#define	EMLINK		31	/* Too many links */
-#define	EPIPE		32	/* Broken pipe */
-#define	EDOM		33	/* Math argument out of domain of func */
-#define	ERANGE		34	/* Math result not representable */
-#define	EDEADLK		35	/* Resource deadlock would occur */
-#define	ENAMETOOLONG	36	/* File name too long */
-#define	ENOLCK		37	/* No record locks available */
-#define	ENOSYS		38	/* Function not implemented */
-#define	ENOTEMPTY	39	/* Directory not empty */
-#define	ELOOP		40	/* Too many symbolic links encountered */
-#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
-#define	ENOMSG		42	/* No message of desired type */
-#define	EIDRM		43	/* Identifier removed */
-#define	ECHRNG		44	/* Channel number out of range */
-#define	EL2NSYNC	45	/* Level 2 not synchronized */
-#define	EL3HLT		46	/* Level 3 halted */
-#define	EL3RST		47	/* Level 3 reset */
-#define	ELNRNG		48	/* Link number out of range */
-#define	EUNATCH		49	/* Protocol driver not attached */
-#define	ENOCSI		50	/* No CSI structure available */
-#define	EL2HLT		51	/* Level 2 halted */
-#define	EBADE		52	/* Invalid exchange */
-#define	EBADR		53	/* Invalid request descriptor */
-#define	EXFULL		54	/* Exchange full */
-#define	ENOANO		55	/* No anode */
-#define	EBADRQC		56	/* Invalid request code */
-#define	EBADSLT		57	/* Invalid slot */
-
-#define	EDEADLOCK	EDEADLK
-
-#define	EBFONT		59	/* Bad font file format */
-#define	ENOSTR		60	/* Device not a stream */
-#define	ENODATA		61	/* No data available */
-#define	ETIME		62	/* Timer expired */
-#define	ENOSR		63	/* Out of streams resources */
-#define	ENONET		64	/* Machine is not on the network */
-#define	ENOPKG		65	/* Package not installed */
-#define	EREMOTE		66	/* Object is remote */
-#define	ENOLINK		67	/* Link has been severed */
-#define	EADV		68	/* Advertise error */
-#define	ESRMNT		69	/* Srmount error */
-#define	ECOMM		70	/* Communication error on send */
-#define	EPROTO		71	/* Protocol error */
-#define	EMULTIHOP	72	/* Multihop attempted */
-#define	EDOTDOT		73	/* RFS specific error */
-#define	EBADMSG		74	/* Not a data message */
-#define	EOVERFLOW	75	/* Value too large for defined data type */
-#define	ENOTUNIQ	76	/* Name not unique on network */
-#define	EBADFD		77	/* File descriptor in bad state */
-#define	EREMCHG		78	/* Remote address changed */
-#define	ELIBACC		79	/* Can not access a needed shared library */
-#define	ELIBBAD		80	/* Accessing a corrupted shared library */
-#define	ELIBSCN		81	/* .lib section in a.out corrupted */
-#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
-#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
-#define	EILSEQ		84	/* Illegal byte sequence */
-#define	ERESTART	85	/* Interrupted system call should be restarted */
-#define	ESTRPIPE	86	/* Streams pipe error */
-#define	EUSERS		87	/* Too many users */
-#define	ENOTSOCK	88	/* Socket operation on non-socket */
-#define	EDESTADDRREQ	89	/* Destination address required */
-#define	EMSGSIZE	90	/* Message too long */
-#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
-#define	ENOPROTOOPT	92	/* Protocol not available */
-#define	EPROTONOSUPPORT	93	/* Protocol not supported */
-#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
-#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
-#define	EPFNOSUPPORT	96	/* Protocol family not supported */
-#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
-#define	EADDRINUSE	98	/* Address already in use */
-#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
-#define	ENETDOWN	100	/* Network is down */
-#define	ENETUNREACH	101	/* Network is unreachable */
-#define	ENETRESET	102	/* Network dropped connection because of reset */
-#define	ECONNABORTED	103	/* Software caused connection abort */
-#define	ECONNRESET	104	/* Connection reset by peer */
-#define	ENOBUFS		105	/* No buffer space available */
-#define	EISCONN		106	/* Transport endpoint is already connected */
-#define	ENOTCONN	107	/* Transport endpoint is not connected */
-#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
-#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
-#define	ETIMEDOUT	110	/* Connection timed out */
-#define	ECONNREFUSED	111	/* Connection refused */
-#define	EHOSTDOWN	112	/* Host is down */
-#define	EHOSTUNREACH	113	/* No route to host */
-#define	EALREADY	114	/* Operation already in progress */
-#define	EINPROGRESS	115	/* Operation now in progress */
-#define	ESTALE		116	/* Stale NFS file handle */
-#define	EUCLEAN		117	/* Structure needs cleaning */
-#define	ENOTNAM		118	/* Not a XENIX named type file */
-#define	ENAVAIL		119	/* No XENIX semaphores available */
-#define	EISNAM		120	/* Is a named type file */
-#define	EREMOTEIO	121	/* Remote I/O error */
-#define	EDQUOT		122	/* Quota exceeded */
-
-#define	ENOMEDIUM	123	/* No medium found */
-#define	EMEDIUMTYPE	124	/* Wrong medium type */
+#include <asm-generic/errno.h>
 
 #endif
diff -Nru a/include/asm-x86_64/ide.h b/include/asm-x86_64/ide.h
--- a/include/asm-x86_64/ide.h	Wed May 29 11:43:03 2002
+++ b/include/asm-x86_64/ide.h	Wed May 29 11:43:03 2002
@@ -41,16 +41,9 @@
 
 static __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
-	switch (index) {
-		case 0:	return 0x1f0;
-		case 1:	return 0x170;
-		case 2: return 0x1e8;
-		case 3: return 0x168;
-		case 4: return 0x1e0;
-		case 5: return 0x160;
-		default:
-			return 0;
-	}
+	static unsigned long ata_io_base[MAX_HWIFS] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
+
+	return ata_io_base[index];
 }
 
 static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
@@ -81,7 +74,7 @@
 	for(index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw);
 	}
 #endif
 }
diff -Nru a/include/asm-x86_64/siginfo.h b/include/asm-x86_64/siginfo.h
--- a/include/asm-x86_64/siginfo.h	Wed May 29 11:43:03 2002
+++ b/include/asm-x86_64/siginfo.h	Wed May 29 11:43:03 2002
@@ -1,233 +1,6 @@
 #ifndef _X8664_SIGINFO_H
 #define _X8664_SIGINFO_H
 
-#include <linux/types.h>
-
-typedef union sigval {
-	int sival_int;
-	void *sival_ptr;
-} sigval_t;
-
-#define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE];
-
-		/* kill() */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
-			int _status;		/* exit code */
-			clock_t _utime;
-			clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-		struct {
-			void *_addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} siginfo_t;
-
-/*
- * How these fields are to be accessed.
- */
-#define si_pid		_sifields._kill._pid
-#define si_uid		_sifields._kill._uid
-#define si_status	_sifields._sigchld._status
-#define si_utime	_sifields._sigchld._utime
-#define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
-#define si_addr		_sifields._sigfault._addr
-#define si_band		_sifields._sigpoll._band
-#define si_fd		_sifields._sigpoll._fd
-
-#ifdef __KERNEL__
-#define __SI_MASK	0xffff0000
-#define __SI_KILL	(0 << 16)
-#define __SI_TIMER	(1 << 16)
-#define __SI_POLL	(2 << 16)
-#define __SI_FAULT	(3 << 16)
-#define __SI_CHLD	(4 << 16)
-#define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
-#else
-#define __SI_KILL	0
-#define __SI_TIMER	0
-#define __SI_POLL	0
-#define __SI_FAULT	0
-#define __SI_CHLD	0
-#define __SI_RT		0
-#define __SI_CODE(T,N)	(N)
-#endif
-
-/*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- * ... And Linux ignores that convention -AK.
- */
-#define SI_USER		0		/* sent by kill, sigsend, raise */
-#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
-#define SI_QUEUE	-1		/* sent by sigqueue */
-#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
-#define SI_MESGQ	-3		/* sent by real time mesq state change */
-#define SI_ASYNCIO	-4		/* sent by AIO completion */
-#define SI_SIGIO	-5		/* sent by queued SIGIO */
-#define SI_TKILL	-6		/* sent by tkill system call */
-#define SI_DETHREAD    -7              /* sent by execve() killing subsidiary thread */
-
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
-
-/*
- * SIGILL si_codes
- */
-#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
-#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
-#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
-#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
-#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
-#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
-#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
-#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
-#define NSIGILL		8
-
-/*
- * SIGFPE si_codes
- */
-#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
-#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
-#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
-#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
-#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
-#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
-#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
-#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
-#define NSIGFPE		8
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
-#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
-#define NSIGSEGV	2
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
-#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
-#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
-#define NSIGBUS		3
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
-#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
-#define NSIGTRAP	2
-
-/*
- * SIGCHLD si_codes
- */
-#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
-#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
-#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
-#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
-#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
-#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
-#define NSIGCHLD	6
-
-/*
- * SIGPOLL si_codes
- */
-#define POLL_IN		(__SI_POLL|1)	/* data input available */
-#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
-#define POLL_MSG	(__SI_POLL|3)	/* input message available */
-#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
-#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
-#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
-#define NSIGPOLL	6
-
-/*
- * sigevent definitions
- * 
- * It seems likely that SIGEV_THREAD will have to be handled from 
- * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
- * thread manager then catches and does the appropriate nonsense.
- * However, everything is written out here so as to not get lost.
- */
-#define SIGEV_SIGNAL	0	/* notify via signal */
-#define SIGEV_NONE	1	/* other notification: meaningless */
-#define SIGEV_THREAD	2	/* deliver via thread creation */
-
-#define SIGEV_MAX_SIZE	64
-#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct sigevent {
-	sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-
-		struct {
-			void (*_function)(sigval_t);
-			void *_attribute;	/* really pthread_attr_t */
-		} _sigev_thread;
-	} _sigev_un;
-} sigevent_t;
-
-#define sigev_notify_function	_sigev_un._sigev_thread._function
-#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
-{
-	if (from->si_code < 0)
-		memcpy(to, from, sizeof(siginfo_t));
-	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
-}
-
-extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
-
-#endif /* __KERNEL__ */
+#include <asm-generic/siginfo.h>
 
 #endif
diff -Nru a/include/linux/atapi.h b/include/linux/atapi.h
--- a/include/linux/atapi.h	Wed May 29 11:43:02 2002
+++ b/include/linux/atapi.h	Wed May 29 11:43:02 2002
@@ -58,8 +58,11 @@
 	} s;
 };
 
+extern void atapi_init_pc(struct atapi_packet_command *pc);
 
-extern void atapi_discard_data(struct ata_device *drive, unsigned int bcount);
-extern void atapi_write_zeros(struct ata_device *drive, unsigned int bcount);
+extern void atapi_discard_data(struct ata_device *, unsigned int);
+extern void atapi_write_zeros(struct ata_device *, unsigned int);
+
+extern void atapi_read(struct ata_device *, u8 *, unsigned int);
+extern void atapi_write(struct ata_device *, u8 *, unsigned int);
 
-extern void atapi_init_pc(struct atapi_packet_command *pc);
diff -Nru a/include/linux/auto_fs.h b/include/linux/auto_fs.h
--- a/include/linux/auto_fs.h	Wed May 29 11:43:01 2002
+++ b/include/linux/auto_fs.h	Wed May 29 11:43:01 2002
@@ -45,7 +45,7 @@
  * If so, 32-bit user-space code should be backwards compatible.
  */
 
-#if defined(__sparc__) || defined(__mips__) || defined(__x86_64__)
+#if defined(__sparc__) || defined(__mips__) || defined(__x86_64__) || defined(__powerpc__)
 typedef unsigned int autofs_wqt_t;
 #else
 typedef unsigned long autofs_wqt_t;
diff -Nru a/include/linux/binfmts.h b/include/linux/binfmts.h
--- a/include/linux/binfmts.h	Wed May 29 11:43:03 2002
+++ b/include/linux/binfmts.h	Wed May 29 11:43:03 2002
@@ -22,6 +22,7 @@
 struct linux_binprm{
 	char buf[BINPRM_BUF_SIZE];
 	struct page *page[MAX_ARG_PAGES];
+	struct mm_struct *mm;
 	unsigned long p; /* current top of mem */
 	int sh_bang;
 	struct file * file;
diff -Nru a/include/linux/blk.h b/include/linux/blk.h
--- a/include/linux/blk.h	Wed May 29 11:43:02 2002
+++ b/include/linux/blk.h	Wed May 29 11:43:02 2002
@@ -293,19 +293,14 @@
 #if !defined(IDE_DRIVER)
 
 #ifndef CURRENT
-#define CURRENT elv_next_request(&blk_dev[MAJOR_NR].request_queue)
+# define CURRENT elv_next_request(&blk_dev[MAJOR_NR].request_queue)
 #endif
 #ifndef QUEUE
-#define QUEUE (&blk_dev[MAJOR_NR].request_queue)
-#endif
-#ifndef QUEUE_EMPTY
-#define QUEUE_EMPTY blk_queue_empty(QUEUE)
+# define QUEUE (&blk_dev[MAJOR_NR].request_queue)
 #endif
 #ifndef DEVICE_NAME
-#define DEVICE_NAME "unknown"
+# define DEVICE_NAME "unknown"
 #endif
-
-#define CURRENT_DEV DEVICE_NR(CURRENT->rq_dev)
 
 #ifdef DEVICE_INTR
 static void (*DEVICE_INTR)(void) = NULL;
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Wed May 29 11:43:02 2002
+++ b/include/linux/blkdev.h	Wed May 29 11:43:02 2002
@@ -177,10 +177,7 @@
 	unsigned long		bounce_pfn;
 	int			bounce_gfp;
 
-	/*
-	 * This is used to remove the plug when tq_disk runs.
-	 */
-	struct tq_struct	plug_tq;
+	struct list_head	plug_list;
 
 	/*
 	 * various queue flags, see QUEUE_* below
@@ -217,6 +214,7 @@
 #define QUEUE_FLAG_PLUGGED	0	/* queue is plugged */
 #define QUEUE_FLAG_CLUSTER	1	/* cluster several segments into 1 */
 #define QUEUE_FLAG_QUEUED	2	/* uses generic tag queueing */
+#define QUEUE_FLAG_STOPPED	3	/* queue is stopped */
 
 #define blk_queue_plugged(q)	test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
 #define blk_mark_plugged(q)	set_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
@@ -303,6 +301,8 @@
 extern inline int blk_phys_contig_segment(request_queue_t *q, struct bio *, struct bio *);
 extern inline int blk_hw_contig_segment(request_queue_t *q, struct bio *, struct bio *);
 extern int block_ioctl(struct block_device *, unsigned int, unsigned long);
+extern void blk_start_queue(request_queue_t *q);
+extern void blk_stop_queue(request_queue_t *q);
 
 /*
  * get ready for proper ref counting
diff -Nru a/include/linux/buffer_head.h b/include/linux/buffer_head.h
--- a/include/linux/buffer_head.h	Wed May 29 11:43:01 2002
+++ b/include/linux/buffer_head.h	Wed May 29 11:43:01 2002
@@ -23,7 +23,7 @@
 	BH_Async_Read,	/* Is under end_buffer_async_read I/O */
 	BH_Async_Write,	/* Is under end_buffer_async_write I/O */
 
-	BH_JBD,		/* Has an attached ext3 journal_head */
+	BH_Boundary,	/* Block is followed by a discontiguity */
 	BH_PrivateStart,/* not a state bit, but the first bit available
 			 * for private allocation by other entities
 			 */
@@ -106,6 +106,7 @@
 BUFFER_FNS(New, new)
 BUFFER_FNS(Async_Read, async_read)
 BUFFER_FNS(Async_Write, async_write)
+BUFFER_FNS(Boundary, boundary)
 
 /*
  * FIXME: this is used only by bh_kmap, which is used only by RAID5.
@@ -160,6 +161,7 @@
 void invalidate_inode_buffers(struct inode *);
 int fsync_buffers_list(spinlock_t *lock, struct list_head *);
 int sync_mapping_buffers(struct address_space *mapping);
+void unmap_underlying_metadata(struct block_device *bdev, sector_t block);
 
 void mark_buffer_async_read(struct buffer_head *bh);
 void mark_buffer_async_write(struct buffer_head *bh);
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Wed May 29 11:43:02 2002
+++ b/include/linux/device.h	Wed May 29 11:43:02 2002
@@ -55,17 +55,77 @@
 
 struct device;
 
+
+struct bus_type {
+	char			* name;
+	rwlock_t		lock;
+	atomic_t		refcount;
+
+	list_t			node;
+	list_t			devices;
+	list_t			drivers;
+
+	struct driver_dir_entry	dir;
+	struct driver_dir_entry	device_dir;
+	struct driver_dir_entry	driver_dir;
+};
+
+
+extern int bus_register(struct bus_type * bus);
+
+static inline struct bus_type * get_bus(struct bus_type * bus)
+{
+	BUG_ON(!atomic_read(&bus->refcount));
+	atomic_inc(&bus->refcount);
+	return bus;
+}
+
+extern void put_bus(struct bus_type * bus);
+
+
 struct device_driver {
+	char			* name;
+	struct bus_type		* bus;
+
+	rwlock_t		lock;
+	atomic_t		refcount;
+
+	list_t			bus_list;
+	list_t			devices;
+
+	struct driver_dir_entry	dir;
+
 	int	(*probe)	(struct device * dev);
 	int 	(*remove)	(struct device * dev, u32 flags);
 
 	int	(*suspend)	(struct device * dev, u32 state, u32 level);
 	int	(*resume)	(struct device * dev, u32 level);
+
+	void	(*release)	(struct device_driver * drv);
 };
 
+
+
+extern int driver_register(struct device_driver * drv);
+
+static inline struct device_driver * get_driver(struct device_driver * drv)
+{
+	BUG_ON(!atomic_read(&drv->refcount));
+	atomic_inc(&drv->refcount);
+	return drv;
+}
+
+extern void put_driver(struct device_driver * drv);
+
+extern int driver_for_each_dev(struct device_driver * drv, void * data, 
+			       int (*callback)(struct device * dev, void * data));
+
+
 struct device {
 	struct list_head g_list;        /* node in depth-first order list */
 	struct list_head node;		/* node in sibling list */
+	struct list_head bus_list;	/* node in bus's list */
+	struct list_head driver_list;
 	struct list_head children;
 	struct device 	* parent;
 
@@ -78,6 +138,7 @@
 	atomic_t	refcount;	/* refcount to make sure the device
 					 * persists for the right amount of time */
 
+	struct bus_type	* bus;		/* type of bus device is on */
 	struct driver_dir_entry	dir;
 
 	struct device_driver *driver;	/* which driver has allocated this
@@ -92,6 +153,8 @@
 					   being off. */
 
 	unsigned char *saved_state;	/* saved device state */
+
+	void	(*release)(struct device * dev);
 };
 
 static inline struct device *
diff -Nru a/include/linux/driverfs_fs.h b/include/linux/driverfs_fs.h
--- a/include/linux/driverfs_fs.h	Wed May 29 11:43:01 2002
+++ b/include/linux/driverfs_fs.h	Wed May 29 11:43:01 2002
@@ -56,6 +56,11 @@
 driverfs_create_file(struct driver_file_entry * entry,
 		     struct driver_dir_entry * parent);
 
+extern int 
+driverfs_create_symlink(struct driver_dir_entry * parent, 
+			struct driver_file_entry * entry,
+			char * target);
+
 extern void
 driverfs_remove_file(struct driver_dir_entry *, const char * name);
 
diff -Nru a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
--- a/include/linux/ext2_fs.h	Wed May 29 11:43:01 2002
+++ b/include/linux/ext2_fs.h	Wed May 29 11:43:01 2002
@@ -211,10 +211,15 @@
 #define EXT2_ECOMPR_FL			0x00000800 /* Compression error */
 /* End compression flags --- maybe not all used */	
 #define EXT2_BTREE_FL			0x00001000 /* btree format dir */
+#define EXT2_INDEX_FL			0x00001000 /* hash-indexed directory */
+#define EXT2_IMAGIC_FL			0x00002000 /* AFS directory */
+#define EXT2_JOURNAL_DATA_FL		0x00004000 /* Reserved for ext3 */
+#define EXT2_NOTAIL_FL			0x00008000 /* file tail should not be merged */
+#define EXT2_DIRSYNC_FL			0x00010000 /* dirsync behaviour (directories only) */
 #define EXT2_RESERVED_FL		0x80000000 /* reserved for ext2 lib */
 
-#define EXT2_FL_USER_VISIBLE		0x00001FFF /* User visible flags */
-#define EXT2_FL_USER_MODIFIABLE		0x000000FF /* User modifiable flags */
+#define EXT2_FL_USER_VISIBLE		0x00011FFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE		0x000100FF /* User modifiable flags */
 
 /*
  * ioctl commands
diff -Nru a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
--- a/include/linux/ext3_fs.h	Wed May 29 11:43:01 2002
+++ b/include/linux/ext3_fs.h	Wed May 29 11:43:01 2002
@@ -203,10 +203,12 @@
 #define EXT3_INDEX_FL			0x00001000 /* hash-indexed directory */
 #define EXT3_IMAGIC_FL			0x00002000 /* AFS directory */
 #define EXT3_JOURNAL_DATA_FL		0x00004000 /* file data should be journaled */
+#define EXT3_NOTAIL_FL			0x00008000 /* file tail should not be merged */
+#define EXT3_DIRSYNC_FL			0x00010000 /* dirsync behaviour (directories only) */
 #define EXT3_RESERVED_FL		0x80000000 /* reserved for ext3 lib */
 
-#define EXT3_FL_USER_VISIBLE		0x00005FFF /* User visible flags */
-#define EXT3_FL_USER_MODIFIABLE		0x000000FF /* User modifiable flags */
+#define EXT3_FL_USER_VISIBLE		0x00015FFF /* User visible flags */
+#define EXT3_FL_USER_MODIFIABLE		0x000100FF /* User modifiable flags */
 
 /*
  * Inode dynamic state flags
diff -Nru a/include/linux/fb.h b/include/linux/fb.h
--- a/include/linux/fb.h	Wed May 29 11:43:02 2002
+++ b/include/linux/fb.h	Wed May 29 11:43:02 2002
@@ -93,7 +93,8 @@
 #define FB_ACCEL_IGS_CYBER2010	34	/* CyberPro 2010		*/
 #define FB_ACCEL_IGS_CYBER5000	35	/* CyberPro 5000		*/
 #define FB_ACCEL_SIS_GLAMOUR    36	/* SiS 300/630/540              */
-
+#define FB_ACCEL_3DLABS_PERMEDIA3 37	/* 3Dlabs Permedia 3		*/
+#define FB_ACCEL_ATI_RADEON	38	/* ATI Radeon family		*/
 
 #define FB_ACCEL_NEOMAGIC_NM2070 90	/* NeoMagic NM2070              */
 #define FB_ACCEL_NEOMAGIC_NM2090 91	/* NeoMagic NM2090              */
@@ -168,6 +169,9 @@
 #define FB_VMODE_YWRAP		256	/* ywrap instead of panning     */
 #define FB_VMODE_SMOOTH_XPAN	512	/* smooth xpan possible (internally used) */
 #define FB_VMODE_CONUPDATE	512	/* don't update x/yoffset	*/
+
+#define PICOS2KHZ(a) (1000000000UL/(a))
+#define KHZ2PICOS(a) (1000000000UL/(a))
 
 struct fb_var_screeninfo {
 	__u32 xres;			/* visible resolution		*/
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Wed May 29 11:43:02 2002
+++ b/include/linux/fs.h	Wed May 29 11:43:02 2002
@@ -107,6 +107,7 @@
 #define MS_SYNCHRONOUS	16	/* Writes are synced at once */
 #define MS_REMOUNT	32	/* Alter flags of a mounted FS */
 #define MS_MANDLOCK	64	/* Allow mandatory locks on an FS */
+#define MS_DIRSYNC	128	/* Directory modifications are synchronous */
 #define MS_NOATIME	1024	/* Do not update access times. */
 #define MS_NODIRATIME	2048	/* Do not update directory access times */
 #define MS_BIND		4096
@@ -137,6 +138,7 @@
 #define S_IMMUTABLE	16	/* Immutable file */
 #define S_DEAD		32	/* removed, but still open directory */
 #define S_NOQUOTA	64	/* Inode is not counted to quota */
+#define S_DIRSYNC	128	/* Directory modifications are synchronous */
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -154,7 +156,10 @@
 #define __IS_FLG(inode,flg) ((inode)->i_sb->s_flags & (flg))
 
 #define IS_RDONLY(inode) ((inode)->i_sb->s_flags & MS_RDONLY)
-#define IS_SYNC(inode)		(__IS_FLG(inode, MS_SYNCHRONOUS) || ((inode)->i_flags & S_SYNC))
+#define IS_SYNC(inode)		(__IS_FLG(inode, MS_SYNCHRONOUS) || \
+					((inode)->i_flags & S_SYNC))
+#define IS_DIRSYNC(inode)	(__IS_FLG(inode, MS_SYNCHRONOUS|MS_DIRSYNC) || \
+					((inode)->i_flags & (S_SYNC|S_DIRSYNC)))
 #define IS_MANDLOCK(inode)	__IS_FLG(inode, MS_MANDLOCK)
 
 #define IS_QUOTAINIT(inode)	((inode)->i_flags & S_QUOTA)
@@ -282,7 +287,7 @@
 	int (*sync_page)(struct page *);
 
 	/* Write back some dirty pages from this mapping. */
-	int (*writeback_mapping)(struct address_space *, int *nr_to_write);
+	int (*writepages)(struct address_space *, int *nr_to_write);
 
 	/* Perform a writeback as a memory-freeing operation. */
 	int (*vm_writeback)(struct page *, int *nr_to_write);
@@ -290,6 +295,9 @@
 	/* Set a page dirty */
 	int (*set_page_dirty)(struct page *page);
 
+	int (*readpages)(struct address_space *mapping,
+			struct list_head *pages, unsigned nr_pages);
+
 	/*
 	 * ext3 requires that a successful prepare_write() call be followed
 	 * by a commit_write() call - they must be balanced
@@ -395,7 +403,6 @@
 	unsigned char		i_sock;
 
 	atomic_t		i_writecount;
-	unsigned int		i_attr_flags;
 	__u32			i_generation;
 	union {
 		void				*generic_ip;
@@ -1079,6 +1086,7 @@
 extern int blkdev_put(struct block_device *, int);
 extern int bd_claim(struct block_device *, void *);
 extern void bd_release(struct block_device *);
+extern void blk_run_queues(void);
 
 /* fs/devices.c */
 extern const struct block_device_operations *get_blkfops(unsigned int);
@@ -1181,6 +1189,7 @@
 extern void force_delete(struct inode *);
 extern struct inode * igrab(struct inode *);
 extern ino_t iunique(struct super_block *, ino_t);
+extern int inode_needs_sync(struct inode *inode);
 
 extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *);
 extern struct inode * iget_locked(struct super_block *, unsigned long);
diff -Nru a/include/linux/hdreg.h b/include/linux/hdreg.h
--- a/include/linux/hdreg.h	Wed May 29 11:43:02 2002
+++ b/include/linux/hdreg.h	Wed May 29 11:43:02 2002
@@ -331,10 +331,13 @@
 #define HDIO_GETGEO_BIG_RAW	0x0331	/* */
 
 #define __NEW_HD_DRIVE_ID
-/* structure returned by HDIO_GET_IDENTITY,
- * as per ANSI NCITS ATA6 rev.1b spec
+
+/*
+ * Structure returned by HDIO_GET_IDENTITY, as per ANSI NCITS ATA6 rev.1b spec.
+ *
+ * If you change something here, please remember to update fix_driveid() in
+ * ide/probe.c.
  */
-/* if you change something here remember to update ide_fix_driveid() */
 struct hd_driveid {
 	unsigned short	config;		/* lots of obsolete bit flags */
 	unsigned short	cyls;		/* Obsolete, "physical" cyls */
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Wed May 29 11:43:02 2002
+++ b/include/linux/ide.h	Wed May 29 11:43:02 2002
@@ -71,18 +71,20 @@
 /*
  * Definitions for accessing IDE controller registers
  */
-#define IDE_NR_PORTS		(10)
 
-#define IDE_DATA_OFFSET		(0)
-#define IDE_ERROR_OFFSET	(1)
-#define IDE_NSECTOR_OFFSET	(2)
-#define IDE_SECTOR_OFFSET	(3)
-#define IDE_LCYL_OFFSET		(4)
-#define IDE_HCYL_OFFSET		(5)
-#define IDE_SELECT_OFFSET	(6)
-#define IDE_STATUS_OFFSET	(7)
-#define IDE_CONTROL_OFFSET	(8)
-#define IDE_IRQ_OFFSET		(9)
+enum {
+	IDE_DATA_OFFSET	    = 0,
+	IDE_ERROR_OFFSET    = 1,
+	IDE_NSECTOR_OFFSET  = 2,
+	IDE_SECTOR_OFFSET   = 3,
+	IDE_LCYL_OFFSET	    = 4,
+	IDE_HCYL_OFFSET	    = 5,
+	IDE_SELECT_OFFSET   = 6,
+	IDE_STATUS_OFFSET   = 7,
+	IDE_CONTROL_OFFSET  = 8,
+	IDE_IRQ_OFFSET	    = 9,
+	IDE_NR_PORTS	    = 10
+};
 
 #define IDE_FEATURE_OFFSET	IDE_ERROR_OFFSET
 #define IDE_COMMAND_OFFSET	IDE_STATUS_OFFSET
@@ -391,7 +393,6 @@
 	int		crc_count;	/* crc counter to reduce drive speed */
 	byte		quirk_list;	/* drive is considered quirky if set for a specific host */
 	byte		suspend_reset;	/* drive suspend mode flag, soft-reset recovers */
-	byte		init_speed;	/* transfer rate set at boot */
 	byte		current_speed;	/* current transfer rate set */
 	byte		dn;		/* now wide spread use */
 	byte		wcache;		/* status of write cache */
@@ -549,7 +550,7 @@
 /*
  * Register new hardware with ide
  */
-extern int ide_register_hw(hw_regs_t *hw, struct ata_channel **hwifp);
+extern int ide_register_hw(hw_regs_t *hw);
 extern void ide_unregister(struct ata_channel *hwif);
 
 struct ata_taskfile;
@@ -742,9 +743,6 @@
 extern void ata_read(struct ata_device *, void *, unsigned int);
 extern void ata_write(struct ata_device *, void *, unsigned int);
 
-extern void atapi_read(struct ata_device *, void *, unsigned int);
-extern void atapi_write(struct ata_device *, void *, unsigned int);
-
 extern ide_startstop_t ata_taskfile(struct ata_device *,
 	struct ata_taskfile *, struct request *);
 
@@ -762,10 +760,7 @@
 extern int ide_raw_taskfile(struct ata_device *, struct ata_taskfile *);
 extern int ide_cmd_ioctl(struct ata_device *drive, unsigned long arg);
 
-void ide_delay_50ms(void);
-
 extern void ide_fix_driveid(struct hd_driveid *id);
-extern int ide_driveid_update(struct ata_device *);
 extern int ide_config_drive_speed(struct ata_device *, byte);
 extern byte eighty_ninty_three(struct ata_device *);
 
@@ -811,7 +806,8 @@
 
 extern int ide_register_subdriver(struct ata_device *, struct ata_operations *);
 extern int ide_unregister_subdriver(struct ata_device *drive);
-extern int ide_revalidate_disk(kdev_t i_rdev);
+extern int ata_revalidate(kdev_t i_rdev);
+extern void ide_driver_module(void);
 
 #ifdef CONFIG_PCI
 # define ON_BOARD		0
@@ -895,11 +891,14 @@
 extern int ata_start_dma(struct ata_device *, struct request *rq);
 
 extern void ata_init_dma(struct ata_channel *,	unsigned long) __init;
+
 #endif
 
+extern void ata_fix_driveid(struct hd_driveid *);
+
 extern spinlock_t ide_lock;
 
-#define DRIVE_LOCK(drive)		((drive)->queue.queue_lock)
+#define DRIVE_LOCK(drive)	((drive)->queue.queue_lock)
 
 extern int drive_is_ready(struct ata_device *drive);
 
diff -Nru a/include/linux/irq.h b/include/linux/irq.h
--- a/include/linux/irq.h	Wed May 29 11:43:02 2002
+++ b/include/linux/irq.h	Wed May 29 11:43:02 2002
@@ -76,4 +76,4 @@
 
 #endif
 
-#endif /* __asm_h */
+#endif /* __irq_h */
diff -Nru a/include/linux/isdn/capilli.h b/include/linux/isdn/capilli.h
--- a/include/linux/isdn/capilli.h	Wed May 29 11:43:02 2002
+++ b/include/linux/isdn/capilli.h	Wed May 29 11:43:02 2002
@@ -36,32 +36,28 @@
 	unsigned int membase;
 } capicardparams;
 
-struct capi_driver;
-
 struct capi_ctr {
-        struct list_head driver_list;		/* contrs by driver */
-        struct capi_driver *driver;
-	int cnr;				/* controller number */
-	char name[32];				/* name of controller */
-	volatile unsigned short cardstate;	/* controller state */
-	volatile int blocked;			/* output blocked */
-	int traceflag;				/* capi trace */
-
+	/* filled in before calling attach_capi_ctr */
+	struct module *owner;
 	void *driverdata;			/* driver specific */
+	char name[32];				/* name of controller */
+	char *driver_name;			/* name of driver */
+	int (*load_firmware)(struct capi_ctr *, capiloaddata *);
+	void (*reset_ctr)(struct capi_ctr *);
+	void (*register_appl)(struct capi_ctr *, u16 appl,
+			      capi_register_params *);
+	void (*release_appl)(struct capi_ctr *, u16 appl);
+	u16  (*send_message)(struct capi_ctr *, struct sk_buff *skb);
+	
+	char *(*procinfo)(struct capi_ctr *);
+	int (*ctr_read_proc)(char *page, char **start, off_t off,
+			     int count, int *eof, struct capi_ctr *card);
 
-	/* filled before calling ready callback */
-	__u8 manu[CAPI_MANUFACTURER_LEN];	/* CAPI_GET_MANUFACTURER */
+	/* filled in before calling ready callback */
+	u8 manu[CAPI_MANUFACTURER_LEN];	/* CAPI_GET_MANUFACTURER */
 	capi_version version;			/* CAPI_GET_VERSION */
 	capi_profile profile;			/* CAPI_GET_PROFILE */
-	__u8 serial[CAPI_SERIAL_LEN];		/* CAPI_GET_SERIAL */
-
-	/* functions */
-        void (*ready)(struct capi_ctr * card);
-        void (*reseted)(struct capi_ctr * card);
-        void (*suspend_output)(struct capi_ctr * card);
-        void (*resume_output)(struct capi_ctr * card);
-        void (*handle_capimsg)(struct capi_ctr * card,
-			   	__u16 appl, struct sk_buff *skb);
+	u8 serial[CAPI_SERIAL_LEN];		/* CAPI_GET_SERIAL */
 
 	/* management information for kcapi */
 
@@ -70,42 +66,23 @@
 	unsigned long nsentctlpkt;
 	unsigned long nsentdatapkt;
 
-	struct proc_dir_entry *procent;
-        char procfn[128];
-};
+	int cnr;				/* controller number */
+	volatile unsigned short cardstate;	/* controller state */
+	volatile int blocked;			/* output blocked */
+	int traceflag;				/* capi trace */
 
-struct capi_driver {
-	struct module *owner;
-	char name[32];				/* driver name */
-	char revision[32];
-	int (*load_firmware)(struct capi_ctr *, capiloaddata *);
-	void (*reset_ctr)(struct capi_ctr *);
-	void (*register_appl)(struct capi_ctr *, __u16 appl,
-			      capi_register_params *);
-	void (*release_appl)(struct capi_ctr *, __u16 appl);
-	u16  (*send_message)(struct capi_ctr *, struct sk_buff *skb);
-	
-	char *(*procinfo)(struct capi_ctr *);
-	int (*ctr_read_proc)(char *page, char **start, off_t off,
-			     int count, int *eof, struct capi_ctr *card);
-	int (*driver_read_proc)(char *page, char **start, off_t off,
-				int count, int *eof, struct capi_driver *driver);
-	
-	/* intitialized by kcapi */
-	struct list_head contr_head;		/* list of controllers */
-	struct list_head driver_list;
-	int ncontroller;
 	struct proc_dir_entry *procent;
-	char procfn[128];
+        char procfn[128];
 };
 
-void attach_capi_driver(struct capi_driver *driver);
-void detach_capi_driver(struct capi_driver *driver);
-
-struct capi_ctr *attach_capi_ctr(struct capi_driver *driver, char *name, void *data);
+int attach_capi_ctr(struct capi_ctr *);
 int detach_capi_ctr(struct capi_ctr *);
 
-
+void capi_ctr_ready(struct capi_ctr * card);
+void capi_ctr_reseted(struct capi_ctr * card);
+void capi_ctr_suspend_output(struct capi_ctr * card);
+void capi_ctr_resume_output(struct capi_ctr * card);
+void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb);
 
 // ---------------------------------------------------------------------------
 // library functions for use by hardware controller drivers
diff -Nru a/include/linux/jbd.h b/include/linux/jbd.h
--- a/include/linux/jbd.h	Wed May 29 11:43:03 2002
+++ b/include/linux/jbd.h	Wed May 29 11:43:03 2002
@@ -226,12 +226,13 @@
 #endif		/* JBD_ASSERTIONS */
 
 enum jbd_state_bits {
-	BH_JWrite
-	  = BH_PrivateStart,	/* 1 if being written to log (@@@ DEBUGGING) */
-	BH_Freed,		/* 1 if buffer has been freed (truncated) */
-	BH_Revoked,		/* 1 if buffer has been revoked from the log */
-	BH_RevokeValid,		/* 1 if buffer revoked flag is valid */
-	BH_JBDDirty,		/* 1 if buffer is dirty but journaled */
+	BH_JBD			/* Has an attached ext3 journal_head */
+	  = BH_PrivateStart,	
+	BH_JWrite,		/* Being written to log (@@@ DEBUGGING) */
+	BH_Freed,		/* Has been freed (truncated) */
+	BH_Revoked,		/* Has been revoked from the log */
+	BH_RevokeValid,		/* Revoked flag is valid */
+	BH_JBDDirty,		/* Is dirty but journaled */
 };
 
 BUFFER_FNS(JBD, jbd)
diff -Nru a/include/linux/jiffies.h b/include/linux/jiffies.h
--- a/include/linux/jiffies.h	Wed May 29 11:43:01 2002
+++ b/include/linux/jiffies.h	Wed May 29 11:43:01 2002
@@ -2,6 +2,7 @@
 #define _LINUX_JIFFIES_H
 
 #include <linux/types.h>
+#include <asm/param.h>			/* for HZ */
 
 /*
  * The 64-bit value is not volatile - you MUST NOT read it
diff -Nru a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h	Wed May 29 11:43:01 2002
+++ b/include/linux/mm.h	Wed May 29 11:43:01 2002
@@ -145,7 +145,7 @@
  *
  * TODO: make this structure smaller, it could be as small as 32 bytes.
  */
-typedef struct page {
+struct page {
 	struct list_head list;		/* ->mapping has some page lists. */
 	struct address_space *mapping;	/* The inode (or ...) we belong to. */
 	unsigned long index;		/* Our offset within mapping. */
@@ -170,7 +170,7 @@
 	void *virtual;			/* Kernel virtual address (NULL if
 					   not kmapped, ie. highmem) */
 #endif /* CONFIG_HIGMEM || WANT_PAGE_VIRTUAL */
-} mem_map_t;
+};
 
 /*
  * Methods to modify the page usage count.
@@ -306,7 +306,7 @@
 #define NOPAGE_OOM	((struct page *) (-1))
 
 /* The array of struct pages */
-extern mem_map_t * mem_map;
+extern struct page *mem_map;
 
 extern void show_free_areas(void);
 extern void show_free_areas_node(pg_data_t *pgdat);
@@ -443,7 +443,7 @@
 extern struct page *filemap_nopage(struct vm_area_struct *, unsigned long, int);
 
 /* mm/page-writeback.c */
-int generic_writeback_mapping(struct address_space *mapping, int *nr_to_write);
+int generic_writepages(struct address_space *mapping, int *nr_to_write);
 int write_one_page(struct page *page, int wait);
 
 /* readahead.c */
diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h
--- a/include/linux/mmzone.h	Wed May 29 11:43:01 2002
+++ b/include/linux/mmzone.h	Wed May 29 11:43:01 2002
@@ -172,8 +172,8 @@
 
 #endif /* !CONFIG_DISCONTIGMEM */
 
-#define MAP_ALIGN(x)	((((x) % sizeof(mem_map_t)) == 0) ? (x) : ((x) + \
-		sizeof(mem_map_t) - ((x) % sizeof(mem_map_t))))
+#define MAP_ALIGN(x)	((((x) % sizeof(struct page)) == 0) ? (x) : ((x) + \
+		sizeof(struct page) - ((x) % sizeof(struct page))))
 
 #endif /* !__ASSEMBLY__ */
 #endif /* __KERNEL__ */
diff -Nru a/include/linux/mpage.h b/include/linux/mpage.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/mpage.h	Wed May 29 11:43:03 2002
@@ -0,0 +1,18 @@
+/*
+ * include/linux/mpage.h
+ *
+ * Contains declarations related to preparing and submitting BIOS which contain
+ * multiple pagecache pages.
+ */
+
+/*
+ * (And no, it doesn't do the #ifdef __MPAGE_H thing, and it doesn't do
+ * nested includes.  Get it right in the .c file).
+ */
+
+int mpage_readpages(struct address_space *mapping, struct list_head *pages,
+				unsigned nr_pages, get_block_t get_block);
+int mpage_readpage(struct page *page, get_block_t get_block);
+int mpage_writepages(struct address_space *mapping,
+		int *nr_to_write, get_block_t get_block);
+
diff -Nru a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
--- a/include/linux/nfs_xdr.h	Wed May 29 11:43:02 2002
+++ b/include/linux/nfs_xdr.h	Wed May 29 11:43:02 2002
@@ -68,8 +68,8 @@
 	struct nfs_fh *		fh;
 	__u64			offset;
 	__u32			count;
-	unsigned int            nriov;
-	struct iovec            iov[NFS_READ_MAXIOV];
+	unsigned int		pgbase;
+	struct page **		pages;
 };
 
 struct nfs_readres {
@@ -87,8 +87,8 @@
 	__u64			offset;
 	__u32			count;
 	enum nfs3_stable_how	stable;
-	unsigned int		nriov;
-	struct iovec		iov[NFS_WRITE_MAXIOV];
+	unsigned int		pgbase;
+	struct page **		pages;
 };
 
 struct nfs_writeverf {
@@ -165,8 +165,8 @@
 struct nfs_readdirargs {
 	struct nfs_fh *		fh;
 	__u32			cookie;
-	void *			buffer;
-	unsigned int		bufsiz;
+	unsigned int		count;
+	struct page **		pages;
 };
 
 struct nfs_diropok {
@@ -176,18 +176,8 @@
 
 struct nfs_readlinkargs {
 	struct nfs_fh *		fh;
-	void *			buffer;
-	unsigned int		bufsiz;
-};
-
-struct nfs_readlinkres {
-	void *			buffer;
-	unsigned int		bufsiz;
-};
-
-struct nfs_readdirres {
-	void *			buffer;
-	unsigned int		bufsiz;
+	unsigned int		count;
+	struct page **		pages;
 };
 
 struct nfs3_sattrargs {
@@ -262,9 +252,9 @@
 	struct nfs_fh *		fh;
 	__u64			cookie;
 	__u32			verf[2];
-	void *			buffer;
-	unsigned int		bufsiz;
 	int			plus;
+	unsigned int            count;
+	struct page **		pages;
 };
 
 struct nfs3_diropres {
@@ -280,14 +270,8 @@
 
 struct nfs3_readlinkargs {
 	struct nfs_fh *		fh;
-	void *			buffer;
-	unsigned int		bufsiz;
-};
-
-struct nfs3_readlinkres {
-	struct nfs_fattr *	fattr;
-	void *			buffer;
-	unsigned int		bufsiz;
+	unsigned int		count;
+	struct page **		pages;
 };
 
 struct nfs3_renameres {
@@ -303,8 +287,6 @@
 struct nfs3_readdirres {
 	struct nfs_fattr *	dir_attr;
 	__u32 *			verf;
-	void *			buffer;
-	unsigned int		bufsiz;
 	int			plus;
 };
 
@@ -322,15 +304,15 @@
 	int	(*lookup)  (struct inode *, struct qstr *,
 			    struct nfs_fh *, struct nfs_fattr *);
 	int	(*access)  (struct inode *, int , int);
-	int	(*readlink)(struct inode *, void *, unsigned int);
+	int	(*readlink)(struct inode *, struct page *);
 	int	(*read)    (struct inode *, struct rpc_cred *,
 			    struct nfs_fattr *,
-			    int, loff_t, unsigned int,
-			    void *buffer, int *eofp);
+			    int, unsigned int, unsigned int,
+			    struct page *, int *eofp);
 	int	(*write)   (struct inode *, struct rpc_cred *,
 			    struct nfs_fattr *,
-			    int, loff_t, unsigned int,
-			    void *buffer, struct nfs_writeverf *verfp);
+			    int, unsigned int, unsigned int,
+			    struct page *, struct nfs_writeverf *verfp);
 	int	(*commit)  (struct inode *, struct nfs_fattr *,
 			    unsigned long, unsigned int);
 	int	(*create)  (struct inode *, struct qstr *, struct iattr *,
@@ -349,7 +331,7 @@
 			    struct nfs_fh *, struct nfs_fattr *);
 	int	(*rmdir)   (struct inode *, struct qstr *);
 	int	(*readdir) (struct inode *, struct rpc_cred *,
-			    u64, void *, unsigned int, int);
+			    u64, struct page *, unsigned int, int);
 	int	(*mknod)   (struct inode *, struct qstr *, struct iattr *,
 			    dev_t, struct nfs_fh *, struct nfs_fattr *);
 	int	(*statfs)  (struct nfs_server *, struct nfs_fh *,
diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h
--- a/include/linux/page-flags.h	Wed May 29 11:43:02 2002
+++ b/include/linux/page-flags.h	Wed May 29 11:43:02 2002
@@ -73,6 +73,8 @@
 	unsigned long nr_dirty;
 	unsigned long nr_writeback;
 	unsigned long nr_pagecache;
+	unsigned long nr_active;	/* on active_list LRU */
+	unsigned long nr_inactive;	/* on inactive_list LRU */
 } ____cacheline_aligned_in_smp page_states[NR_CPUS];
 
 extern void get_page_state(struct page_state *ret);
diff -Nru a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h	Wed May 29 11:43:03 2002
+++ b/include/linux/pci.h	Wed May 29 11:43:03 2002
@@ -439,6 +439,7 @@
 
 extern struct list_head pci_root_buses;	/* list of all known PCI buses */
 extern struct list_head pci_devices;	/* list of all devices */
+extern struct bus_type pci_bus_type;
 
 /*
  * Error values that may be returned by PCI functions.
@@ -486,6 +487,8 @@
 	int  (*suspend) (struct pci_dev *dev, u32 state);	/* Device suspended */
 	int  (*resume) (struct pci_dev *dev);	                /* Device woken up */
 	int  (*enable_wake) (struct pci_dev *dev, u32 state, int enable);   /* Enable wake event */
+
+	struct device_driver	driver;
 };
 
 
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Wed May 29 11:43:02 2002
+++ b/include/linux/pci_ids.h	Wed May 29 11:43:02 2002
@@ -1787,3 +1787,7 @@
 #define PCI_DEVICE_ID_MICROGATE_USC	0x0010
 #define PCI_DEVICE_ID_MICROGATE_SCC	0x0020
 #define PCI_DEVICE_ID_MICROGATE_SCA	0x0030
+
+#define PCI_VENDOR_ID_HINT		0x3388
+#define PCI_DEVICE_ID_HINT_VXPROII_IDE	0x8013
+
diff -Nru a/include/linux/quota.h b/include/linux/quota.h
--- a/include/linux/quota.h	Wed May 29 11:43:02 2002
+++ b/include/linux/quota.h	Wed May 29 11:43:02 2002
@@ -184,22 +184,18 @@
 
 #define sb_dqopt(sb) (&(sb)->s_dquot)
 
-/*
- * Statistics about disc quota.
- */
-enum {
-	DQSTATS_LOOKUPS,
-	DQSTATS_DROPS,
-	DQSTATS_READS,
-	DQSTATS_WRITES,
-	DQSTATS_CACHE_HITS,
-	DQSTATS_ALLOCATED,
-	DQSTATS_FREE,
-	DQSTATS_SYNCS,
-	DQSTATS_SIZE
+struct dqstats {
+	int lookups;
+	int drops;
+	int reads;
+	int writes;
+	int cache_hits;
+	int allocated_dquots;
+	int free_dquots;
+	int syncs;
 };
 
-extern __u32 dqstats_array[DQSTATS_SIZE];
+extern struct dqstats dqstats;
 
 #define NR_DQHASH 43            /* Just an arbitrary number */
 
diff -Nru a/include/linux/quotacompat.h b/include/linux/quotacompat.h
--- a/include/linux/quotacompat.h	Wed May 29 11:43:03 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,86 +0,0 @@
-/*
- *	Definition of symbols used for backward compatible interface
- */
-
-#ifndef _LINUX_QUOTACOMPAT_
-#define _LINUX_QUOTACOMPAT_
-
-#include <linux/types.h>
-#include <linux/quota.h>
-
-struct v1c_mem_dqblk {
-	__u32 dqb_bhardlimit;	/* absolute limit on disk blks alloc */
-	__u32 dqb_bsoftlimit;	/* preferred limit on disk blks */
-	__u32 dqb_curblocks;	/* current block count */
-	__u32 dqb_ihardlimit;	/* maximum # allocated inodes */
-	__u32 dqb_isoftlimit;	/* preferred inode limit */
-	__u32 dqb_curinodes;	/* current # allocated inodes */
-	time_t dqb_btime;	/* time limit for excessive disk use */
-	time_t dqb_itime;	/* time limit for excessive files */
-};
-
-struct v1c_dqstats {
-	__u32 lookups;
-	__u32 drops;
-	__u32 reads;
-	__u32 writes;
-	__u32 cache_hits;
-	__u32 allocated_dquots;
-	__u32 free_dquots;
-	__u32 syncs;
-};
-
-struct v2c_mem_dqblk {
-	unsigned int dqb_ihardlimit;
-	unsigned int dqb_isoftlimit;
-	unsigned int dqb_curinodes;
-	unsigned int dqb_bhardlimit;
-	unsigned int dqb_bsoftlimit;
-	qsize_t dqb_curspace;
-	__kernel_time_t dqb_btime;
-	__kernel_time_t dqb_itime;
-};
-
-struct v2c_mem_dqinfo {
-	unsigned int dqi_bgrace;
-	unsigned int dqi_igrace;
-	unsigned int dqi_flags;
-	unsigned int dqi_blocks;
-	unsigned int dqi_free_blk;
-	unsigned int dqi_free_entry;
-};
-
-struct v2c_dqstats {
-	__u32 lookups;
-	__u32 drops;
-	__u32 reads;
-	__u32 writes;
-	__u32 cache_hits;
-	__u32 allocated_dquots;
-	__u32 free_dquots;
-	__u32 syncs;
-	__u32 version;
-};
-
-#define Q_COMP_QUOTAON  0x0100	/* enable quotas */
-#define Q_COMP_QUOTAOFF 0x0200	/* disable quotas */
-#define Q_COMP_SYNC     0x0600	/* sync disk copy of a filesystems quotas */
-
-#define Q_V1_GETQUOTA 0x0300	/* get limits and usage */
-#define Q_V1_SETQUOTA 0x0400	/* set limits and usage */
-#define Q_V1_SETUSE   0x0500	/* set usage */
-#define Q_V1_SETQLIM  0x0700	/* set limits */
-#define Q_V1_GETSTATS 0x0800	/* get collected stats */
-#define Q_V1_RSQUASH  0x1000	/* set root_squash option */
-
-#define Q_V2_SETQLIM  0x0700	/* set limits */
-#define Q_V2_GETINFO  0x0900	/* get info about quotas - graces, flags... */
-#define Q_V2_SETINFO  0x0A00	/* set info about quotas */
-#define Q_V2_SETGRACE 0x0B00	/* set inode and block grace */
-#define Q_V2_SETFLAGS 0x0C00	/* set flags for quota */
-#define Q_V2_GETQUOTA 0x0D00	/* get limits and usage */
-#define Q_V2_SETQUOTA 0x0E00	/* set limits and usage */
-#define Q_V2_SETUSE   0x0F00	/* set usage */
-#define Q_V2_GETSTATS 0x1100	/* get collected stats */
-
-#endif
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Wed May 29 11:43:01 2002
+++ b/include/linux/sched.h	Wed May 29 11:43:01 2002
@@ -80,6 +80,7 @@
 extern int nr_threads;
 extern int last_pid;
 extern unsigned long nr_running(void);
+extern unsigned long nr_uninterruptible(void);
 
 #include <linux/time.h>
 #include <linux/param.h>
diff -Nru a/include/linux/signal.h b/include/linux/signal.h
--- a/include/linux/signal.h	Wed May 29 11:43:02 2002
+++ b/include/linux/signal.h	Wed May 29 11:43:02 2002
@@ -220,6 +220,10 @@
 
 extern long do_sigpending(void *, unsigned long);
 
+#ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER
+extern int get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs);
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SIGNAL_H */
diff -Nru a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
--- a/include/linux/sunrpc/xdr.h	Wed May 29 11:43:03 2002
+++ b/include/linux/sunrpc/xdr.h	Wed May 29 11:43:03 2002
@@ -35,6 +35,31 @@
 typedef int	(*kxdrproc_t)(void *rqstp, u32 *data, void *obj);
 
 /*
+ * Basic structure for transmission/reception of a client XDR message.
+ * Features a header (for a linear buffer containing RPC headers
+ * and the data payload for short messages), and then an array of
+ * pages.
+ * The tail iovec allows you to append data after the page array. Its
+ * main interest is for appending padding to the pages in order to
+ * satisfy the int_32-alignment requirements in RFC1832.
+ *
+ * For the future, we might want to string several of these together
+ * in a list if anybody wants to make use of NFSv4 COMPOUND
+ * operations and/or has a need for scatter/gather involving pages.
+ */
+struct xdr_buf {
+	struct iovec	head[1],	/* RPC header + non-page data */
+			tail[1];	/* Appended after page data */
+
+	struct page **	pages;		/* Array of contiguous pages */
+	unsigned int	page_base,	/* Start of page data */
+			page_len;	/* Length of page data */
+
+	unsigned int	len;		/* Total length of data */
+
+};
+
+/*
  * pre-xdr'ed macros.
  */
 
@@ -68,6 +93,11 @@
 u32 *	xdr_decode_netobj(u32 *p, struct xdr_netobj *);
 u32 *	xdr_decode_netobj_fixed(u32 *p, void *obj, unsigned int len);
 
+void	xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int,
+			 unsigned int);
+void	xdr_inline_pages(struct xdr_buf *, unsigned int,
+			 struct page **, unsigned int, unsigned int);
+
 /*
  * Decode 64bit quantities (NFSv3 support)
  */
@@ -98,6 +128,40 @@
 
 void xdr_shift_iovec(struct iovec *, int, size_t);
 void xdr_zero_iovec(struct iovec *, int, size_t);
+
+/*
+ * Maximum number of iov's we use.
+ */
+#define MAX_IOVEC	(12)
+
+/*
+ * XDR buffer helper functions
+ */
+extern int xdr_kmap(struct iovec *, struct xdr_buf *, unsigned int);
+extern void xdr_kunmap(struct xdr_buf *, unsigned int);
+extern void xdr_shift_buf(struct xdr_buf *, unsigned int);
+extern void xdr_zero_buf(struct xdr_buf *, unsigned int);
+
+/*
+ * Helper structure for copying from an sk_buff.
+ */
+typedef struct {
+	struct sk_buff	*skb;
+	unsigned int	offset;
+	size_t		count;
+	unsigned int	csum;
+} skb_reader_t;
+
+typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len);
+
+extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int,
+		skb_reader_t *, skb_read_actor_t);
+
+extern int xdr_copy_skb(struct xdr_buf *xdr, unsigned int base,
+		struct sk_buff *skb, unsigned int offset);
+
+extern int xdr_copy_and_csum_skb(struct xdr_buf *xdr, unsigned int base,
+		struct sk_buff *skb, unsigned int offset, unsigned int csum);
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
--- a/include/linux/sunrpc/xprt.h	Wed May 29 11:43:03 2002
+++ b/include/linux/sunrpc/xprt.h	Wed May 29 11:43:03 2002
@@ -13,11 +13,7 @@
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/sunrpc/sched.h>
-
-/*
- * Maximum number of iov's we use.
- */
-#define MAX_IOVEC	10
+#include <linux/sunrpc/xdr.h>
 
 /*
  * The transport code maintains an estimate on the maximum number of out-
@@ -70,15 +66,6 @@
 };
 
 /*
- * This is the RPC buffer
- */
-struct rpc_iov {
-	struct iovec		io_vec[MAX_IOVEC];
-	unsigned int		io_nr;
-	unsigned int		io_len;
-};
-
-/*
  * This describes a complete RPC request
  */
 struct rpc_rqst {
@@ -87,8 +74,8 @@
 	 */
 	struct rpc_xprt *	rq_xprt;		/* RPC client */
 	struct rpc_timeout	rq_timeout;		/* timeout parms */
-	struct rpc_iov		rq_snd_buf;		/* send buffer */
-	struct rpc_iov		rq_rcv_buf;		/* recv buffer */
+	struct xdr_buf		rq_snd_buf;		/* send buffer */
+	struct xdr_buf		rq_rcv_buf;		/* recv buffer */
 
 	/*
 	 * This is the private part
@@ -113,12 +100,10 @@
 	unsigned long		rq_xtime;	/* when transmitted */
 #endif
 };
-#define rq_svec			rq_snd_buf.io_vec
-#define rq_snr			rq_snd_buf.io_nr
-#define rq_slen			rq_snd_buf.io_len
-#define rq_rvec			rq_rcv_buf.io_vec
-#define rq_rnr			rq_rcv_buf.io_nr
-#define rq_rlen			rq_rcv_buf.io_len
+#define rq_svec			rq_snd_buf.head
+#define rq_slen			rq_snd_buf.len
+#define rq_rvec			rq_rcv_buf.head
+#define rq_rlen			rq_rcv_buf.len
 
 #define XPRT_LAST_FRAG		(1 << 0)
 #define XPRT_COPY_RECM		(1 << 1)
diff -Nru a/include/linux/suspend.h b/include/linux/suspend.h
--- a/include/linux/suspend.h	Wed May 29 11:43:02 2002
+++ b/include/linux/suspend.h	Wed May 29 11:43:02 2002
@@ -1,7 +1,9 @@
 #ifndef _LINUX_SWSUSP_H
 #define _LINUX_SWSUSP_H
 
+#if defined(SUSPEND_C) || defined(ACPI_C)
 #include <asm/suspend.h>
+#endif
 #include <linux/swap.h>
 #include <linux/notifier.h>
 #include <linux/config.h>
diff -Nru a/include/linux/swap.h b/include/linux/swap.h
--- a/include/linux/swap.h	Wed May 29 11:43:01 2002
+++ b/include/linux/swap.h	Wed May 29 11:43:01 2002
@@ -102,8 +102,6 @@
 extern unsigned int nr_free_pages(void);
 extern unsigned int nr_free_buffer_pages(void);
 extern unsigned int nr_free_pagecache_pages(void);
-extern int nr_active_pages;
-extern int nr_inactive_pages;
 extern void __remove_inode_page(struct page *);
 
 /* Incomplete types for prototype declarations: */
@@ -191,27 +189,27 @@
 	DEBUG_LRU_PAGE(page);			\
 	SetPageActive(page);			\
 	list_add(&(page)->lru, &active_list);	\
-	nr_active_pages++;			\
+	inc_page_state(nr_active);		\
 } while (0)
 
 #define add_page_to_inactive_list(page)		\
 do {						\
 	DEBUG_LRU_PAGE(page);			\
 	list_add(&(page)->lru, &inactive_list);	\
-	nr_inactive_pages++;			\
+	inc_page_state(nr_inactive);		\
 } while (0)
 
 #define del_page_from_active_list(page)		\
 do {						\
 	list_del(&(page)->lru);			\
 	ClearPageActive(page);			\
-	nr_active_pages--;			\
+	dec_page_state(nr_active);		\
 } while (0)
 
 #define del_page_from_inactive_list(page)	\
 do {						\
 	list_del(&(page)->lru);			\
-	nr_inactive_pages--;			\
+	dec_page_state(nr_inactive);		\
 } while (0)
 
 extern spinlock_t swaplock;
diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h	Wed May 29 11:43:01 2002
+++ b/include/linux/sysctl.h	Wed May 29 11:43:01 2002
@@ -544,7 +544,19 @@
 	FS_LEASES=13,	/* int: leases enabled */
 	FS_DIR_NOTIFY=14,	/* int: directory notification enabled */
 	FS_LEASE_TIME=15,	/* int: maximum time to wait for a lease break */
-	FS_DQSTATS=16,	/* int: disc quota suage statistics */
+	FS_DQSTATS=16,	/* disc quota usage statistics */
+};
+
+/* /proc/sys/fs/quota/ */
+enum {
+	FS_DQ_LOOKUPS = 1,
+	FS_DQ_DROPS = 2,
+	FS_DQ_READS = 3,
+	FS_DQ_WRITES = 4,
+	FS_DQ_CACHE_HITS = 5,
+	FS_DQ_ALLOCATED = 6,
+	FS_DQ_FREE = 7,
+	FS_DQ_SYNCS = 8,
 };
 
 /* CTL_DEBUG names: */
diff -Nru a/include/linux/tqueue.h b/include/linux/tqueue.h
--- a/include/linux/tqueue.h	Wed May 29 11:43:01 2002
+++ b/include/linux/tqueue.h	Wed May 29 11:43:01 2002
@@ -66,7 +66,7 @@
 #define DECLARE_TASK_QUEUE(q)	LIST_HEAD(q)
 #define TQ_ACTIVE(q)		(!list_empty(&q))
 
-extern task_queue tq_timer, tq_immediate, tq_disk, tq_bdflush;
+extern task_queue tq_timer, tq_immediate;
 
 /*
  * To implement your own list of active bottom halfs, use the following
diff -Nru a/include/linux/writeback.h b/include/linux/writeback.h
--- a/include/linux/writeback.h	Wed May 29 11:43:01 2002
+++ b/include/linux/writeback.h	Wed May 29 11:43:01 2002
@@ -47,6 +47,6 @@
 void balance_dirty_pages(struct address_space *mapping);
 void balance_dirty_pages_ratelimited(struct address_space *mapping);
 int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
-int writeback_mapping(struct address_space *mapping, int *nr_to_write);
+int do_writepages(struct address_space *mapping, int *nr_to_write);
 
 #endif		/* WRITEBACK_H */
diff -Nru a/include/video/tdfx.h b/include/video/tdfx.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/video/tdfx.h	Wed May 29 11:43:03 2002
@@ -0,0 +1,191 @@
+#ifndef _TDFX_H
+#define _TDFX_H
+
+/* membase0 register offsets */
+#define STATUS          0x00
+#define PCIINIT0        0x04
+#define SIPMONITOR      0x08
+#define LFBMEMORYCONFIG 0x0c
+#define MISCINIT0       0x10
+#define MISCINIT1       0x14
+#define DRAMINIT0       0x18
+#define DRAMINIT1       0x1c
+#define AGPINIT         0x20
+#define TMUGBEINIT      0x24
+#define VGAINIT0        0x28
+#define VGAINIT1        0x2c
+#define DRAMCOMMAND     0x30
+#define DRAMDATA        0x34
+/* reserved             0x38 */
+/* reserved             0x3c */
+#define PLLCTRL0        0x40
+#define PLLCTRL1        0x44
+#define PLLCTRL2        0x48
+#define DACMODE         0x4c
+#define DACADDR         0x50
+#define DACDATA         0x54
+#define RGBMAXDELTA     0x58
+#define VIDPROCCFG      0x5c
+#define HWCURPATADDR    0x60
+#define HWCURLOC        0x64
+#define HWCURC0         0x68
+#define HWCURC1         0x6c
+#define VIDINFORMAT     0x70
+#define VIDINSTATUS     0x74
+#define VIDSERPARPORT   0x78
+#define VIDINXDELTA     0x7c
+#define VIDININITERR    0x80
+#define VIDINYDELTA     0x84
+#define VIDPIXBUFTHOLD  0x88
+#define VIDCHRMIN       0x8c
+#define VIDCHRMAX       0x90
+#define VIDCURLIN       0x94
+#define VIDSCREENSIZE   0x98
+#define VIDOVRSTARTCRD  0x9c
+#define VIDOVRENDCRD    0xa0
+#define VIDOVRDUDX      0xa4
+#define VIDOVRDUDXOFF   0xa8
+#define VIDOVRDVDY      0xac
+/*  ... */
+#define VIDOVRDVDYOFF   0xe0
+#define VIDDESKSTART    0xe4
+#define VIDDESKSTRIDE   0xe8
+#define VIDINADDR0      0xec
+#define VIDINADDR1      0xf0
+#define VIDINADDR2      0xf4
+#define VIDINSTRIDE     0xf8
+#define VIDCUROVRSTART  0xfc
+
+#define INTCTRL         (0x00100000 + 0x04)
+#define CLIP0MIN        (0x00100000 + 0x08)
+#define CLIP0MAX        (0x00100000 + 0x0c)
+#define DSTBASE         (0x00100000 + 0x10)
+#define DSTFORMAT       (0x00100000 + 0x14)
+#define SRCBASE         (0x00100000 + 0x34)
+#define COMMANDEXTRA_2D (0x00100000 + 0x38)
+#define CLIP1MIN        (0x00100000 + 0x4c)
+#define CLIP1MAX        (0x00100000 + 0x50)
+#define SRCFORMAT       (0x00100000 + 0x54)
+#define SRCSIZE         (0x00100000 + 0x58)
+#define SRCXY           (0x00100000 + 0x5c)
+#define COLORBACK       (0x00100000 + 0x60)
+#define COLORFORE       (0x00100000 + 0x64)
+#define DSTSIZE         (0x00100000 + 0x68)
+#define DSTXY           (0x00100000 + 0x6c)
+#define COMMAND_2D      (0x00100000 + 0x70)
+#define LAUNCH_2D       (0x00100000 + 0x80)
+
+#define COMMAND_3D      (0x00200000 + 0x120)
+
+/* register bitfields (not all, only as needed) */
+
+#define BIT(x) (1UL << (x))
+
+/* COMMAND_2D reg. values */
+#define TDFX_ROP_COPY        0xcc     // src
+#define TDFX_ROP_INVERT      0x55     // NOT dst
+#define TDFX_ROP_XOR         0x66     // src XOR dst
+
+#define AUTOINC_DSTX                    BIT(10)
+#define AUTOINC_DSTY                    BIT(11)
+#define COMMAND_2D_FILLRECT             0x05
+#define COMMAND_2D_S2S_BITBLT           0x01      // screen to screen
+#define COMMAND_2D_H2S_BITBLT           0x03       // host to screen
+
+#define COMMAND_3D_NOP                  0x00
+#define STATUS_RETRACE                  BIT(6)
+#define STATUS_BUSY                     BIT(9)
+#define MISCINIT1_CLUT_INV              BIT(0)
+#define MISCINIT1_2DBLOCK_DIS           BIT(15)
+#define DRAMINIT0_SGRAM_NUM             BIT(26)
+#define DRAMINIT0_SGRAM_TYPE            BIT(27)
+#define DRAMINIT1_MEM_SDRAM             BIT(30)
+#define VGAINIT0_VGA_DISABLE            BIT(0)
+#define VGAINIT0_EXT_TIMING             BIT(1)
+#define VGAINIT0_8BIT_DAC               BIT(2)
+#define VGAINIT0_EXT_ENABLE             BIT(6)
+#define VGAINIT0_WAKEUP_3C3             BIT(8)
+#define VGAINIT0_LEGACY_DISABLE         BIT(9)
+#define VGAINIT0_ALT_READBACK           BIT(10)
+#define VGAINIT0_FAST_BLINK             BIT(11)
+#define VGAINIT0_EXTSHIFTOUT            BIT(12)
+#define VGAINIT0_DECODE_3C6             BIT(13)
+#define VGAINIT0_SGRAM_HBLANK_DISABLE   BIT(22)
+#define VGAINIT1_MASK                   0x1fffff
+#define VIDCFG_VIDPROC_ENABLE           BIT(0)
+#define VIDCFG_CURS_X11                 BIT(1)
+#define VIDCFG_HALF_MODE                BIT(4)
+#define VIDCFG_DESK_ENABLE              BIT(7)
+#define VIDCFG_CLUT_BYPASS              BIT(10)
+#define VIDCFG_2X                       BIT(26)
+#define VIDCFG_HWCURSOR_ENABLE          BIT(27)
+#define VIDCFG_PIXFMT_SHIFT             18
+#define DACMODE_2X                      BIT(0)
+
+/* VGA rubbish, need to change this for multihead support */
+#define MISC_W  0x3c2
+#define MISC_R  0x3cc
+#define SEQ_I   0x3c4
+#define SEQ_D   0x3c5
+#define CRT_I   0x3d4
+#define CRT_D   0x3d5
+#define ATT_IW  0x3c0
+#define IS1_R   0x3da
+#define GRA_I   0x3ce
+#define GRA_D   0x3cf
+
+#ifdef __KERNEL__
+
+struct banshee_reg {
+  /* VGA rubbish */
+  unsigned char att[21];
+  unsigned char crt[25];
+  unsigned char gra[ 9];
+  unsigned char misc[1];
+  unsigned char seq[ 5];
+
+  /* Banshee extensions */
+  unsigned char ext[2];
+  unsigned long vidcfg;
+  unsigned long vidpll;
+  unsigned long mempll;
+  unsigned long gfxpll;
+  unsigned long dacmode;
+  unsigned long vgainit0;
+  unsigned long vgainit1;
+  unsigned long screensize;
+  unsigned long stride;
+  unsigned long cursloc;
+  unsigned long curspataddr;
+  unsigned long cursc0;
+  unsigned long cursc1;
+  unsigned long startaddr;
+  unsigned long clip0min;
+  unsigned long clip0max;
+  unsigned long clip1min;
+  unsigned long clip1max;
+  unsigned long srcbase;
+  unsigned long dstbase;
+  unsigned long miscinit0;	
+};
+
+struct tdfx_par {
+  u32 max_pixclock;
+
+  void *regbase_virt;
+  unsigned long iobase;
+  u32 baseline;
+
+  struct {
+     int w,u,d;
+     unsigned long enable,disable;
+     struct timer_list timer;
+  } hwcursor; 
+
+  spinlock_t DAClock;
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _TDFX_H */
+
diff -Nru a/init/Makefile b/init/Makefile
--- a/init/Makefile	Wed May 29 11:43:02 2002
+++ b/init/Makefile	Wed May 29 11:43:02 2002
@@ -12,11 +12,15 @@
 
 version.o: ../include/linux/compile.h
 
+# 'make dep' may add a dependency on $(TOPDIR)/include/linux/compile.h
+
+$(TOPDIR)/include/linux/compile.h: ../include/linux/compile.h ;
+
 # compile.h changes depending on hostname, generation number, etc,
 # so we regenerate it always.
 # mkcompile_h will make sure to only update the
-# actualy file if its content has changed.
+# actual file if its content has changed.
 
-../include/linux/compile.h: ../include/linux/version.h dummy
+../include/linux/compile.h: FORCE
 	@echo Generating $@
 	@. ../scripts/mkcompile_h $@ "$(ARCH)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
diff -Nru a/init/do_mounts.c b/init/do_mounts.c
--- a/init/do_mounts.c	Wed May 29 11:43:02 2002
+++ b/init/do_mounts.c	Wed May 29 11:43:02 2002
@@ -365,6 +365,7 @@
 	return sys_symlink(path + n + 5, name);
 }
 
+#if defined(BLOCK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD)
 static void __init change_floppy(char *fmt, ...)
 {
 	struct termios termios;
@@ -392,6 +393,7 @@
 		close(fd);
 	}
 }
+#endif
 
 #ifdef CONFIG_BLK_DEV_RAM
 
diff -Nru a/ipc/sem.c b/ipc/sem.c
--- a/ipc/sem.c	Wed May 29 11:43:02 2002
+++ b/ipc/sem.c	Wed May 29 11:43:02 2002
@@ -644,6 +644,7 @@
 		for (un = sma->undo; un; un = un->id_next)
 			un->semadj[semnum] = 0;
 		curr->semval = val;
+		curr->sempid = current->pid;
 		sma->sem_ctime = CURRENT_TIME;
 		/* maybe some queued-up processes were waiting for this */
 		update_queue(sma);
diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Wed May 29 11:43:02 2002
+++ b/kernel/exit.c	Wed May 29 11:43:02 2002
@@ -532,7 +532,7 @@
 	del_timer_sync(&tsk->real_timer);
 
 	if (unlikely(preempt_get_count()))
-		printk(KERN_ERR "error: %s[%d] exited with preempt_count %d\n",
+		printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n",
 				current->comm, current->pid,
 				preempt_get_count());
 
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Wed May 29 11:43:01 2002
+++ b/kernel/ksyms.c	Wed May 29 11:43:01 2002
@@ -337,7 +337,6 @@
 EXPORT_SYMBOL(grok_partitions);
 EXPORT_SYMBOL(register_disk);
 EXPORT_SYMBOL(read_dev_sector);
-EXPORT_SYMBOL(tq_disk);
 EXPORT_SYMBOL(init_buffer);
 EXPORT_SYMBOL(wipe_partitions);
 
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Wed May 29 11:43:02 2002
+++ b/kernel/sched.c	Wed May 29 11:43:02 2002
@@ -1,15 +1,19 @@
 /*
- *  linux/kernel/sched.c
+ *  kernel/sched.c
  *
  *  Kernel scheduler and related syscalls
  *
- *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1991-2002  Linus Torvalds
  *
  *  1996-12-23  Modified by Dave Grothe to fix bugs in semaphores and
  *              make semaphores SMP safe
  *  1998-11-19	Implemented schedule_timeout() and related stuff
  *		by Andrea Arcangeli
- *  1998-12-28  Implemented better SMP scheduling by Ingo Molnar
+ *  2002-01-04	New ultra-scalable O(1) scheduler by Ingo Molnar:
+ *  		hybrid priority-list and round-robin design with
+ *  		an array-switch method of distributing timeslices
+ *  		and per-CPU runqueues.  Additional code by Davide
+ *  		Libenzi, Robert Love, and Rusty Russell.
  */
 
 #include <linux/mm.h>
@@ -133,6 +137,7 @@
 	spinlock_t lock;
 	spinlock_t frozen;
 	unsigned long nr_running, nr_switches, expired_timestamp;
+	signed long nr_uninterruptible;
 	task_t *curr, *idle;
 	prio_array_t *active, *expired, arrays[2];
 	int prev_nr_running[NR_CPUS];
@@ -240,6 +245,8 @@
 static inline void deactivate_task(struct task_struct *p, runqueue_t *rq)
 {
 	rq->nr_running--;
+	if (p->state == TASK_UNINTERRUPTIBLE)
+		rq->nr_uninterruptible++;
 	dequeue_task(p, p->array);
 	p->array = NULL;
 }
@@ -319,11 +326,15 @@
 {
 	unsigned long flags;
 	int success = 0;
+	long old_state;
 	runqueue_t *rq;
 
 	rq = task_rq_lock(p, &flags);
+	old_state = p->state;
 	p->state = TASK_RUNNING;
 	if (!p->array) {
+		if (old_state == TASK_UNINTERRUPTIBLE)
+			rq->nr_uninterruptible--;
 		activate_task(p, rq);
 		if (p->prio < rq->curr->prio)
 			resched_task(rq->curr);
@@ -429,6 +440,16 @@
 	return sum;
 }
 
+unsigned long nr_uninterruptible(void)
+{
+	unsigned long i, sum = 0;
+
+	for (i = 0; i < smp_num_cpus; i++)
+		sum += cpu_rq(cpu_logical_map(i))->nr_uninterruptible;
+
+	return sum;
+}
+
 unsigned long nr_context_switches(void)
 {
 	unsigned long i, sum = 0;
@@ -1660,6 +1681,16 @@
 	 * migrate the process off to a proper CPU.
 	 */
 	if (new_mask & (1UL << p->thread_info->cpu)) {
+		task_rq_unlock(rq, &flags);
+		goto out;
+	}
+
+	/*
+	 * If the task is not on a runqueue, then it is sufficient
+	 * to simply update the task's cpu field.
+	 */
+	if (!p->array) {
+		p->thread_info->cpu = __ffs(p->cpus_allowed);
 		task_rq_unlock(rq, &flags);
 		goto out;
 	}
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Wed May 29 11:43:02 2002
+++ b/kernel/signal.c	Wed May 29 11:43:02 2002
@@ -14,8 +14,11 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
+#include <linux/tty.h>
+#include <linux/binfmts.h>
 
 #include <asm/uaccess.h>
+#include <asm/siginfo.h>
 
 /*
  * SLAB caches for signal bits.
@@ -824,6 +827,110 @@
 	read_unlock(&tasklist_lock);
 }
 
+#ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER
+
+int get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs)
+{
+	for (;;) {
+		unsigned long signr;
+		struct k_sigaction *ka;
+
+		spin_lock_irq(&current->sigmask_lock);
+		signr = dequeue_signal(&current->blocked, info);
+		spin_unlock_irq(&current->sigmask_lock);
+
+		if (!signr)
+			break;
+
+		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+			/* Let the debugger run.  */
+			current->exit_code = signr;
+			set_current_state(TASK_STOPPED);
+			notify_parent(current, SIGCHLD);
+			schedule();
+
+			/* We're back.  Did the debugger cancel the sig?  */
+			signr = current->exit_code;
+			if (signr == 0)
+				continue;
+			current->exit_code = 0;
+
+			/* The debugger continued.  Ignore SIGSTOP.  */
+			if (signr == SIGSTOP)
+				continue;
+
+			/* Update the siginfo structure.  Is this good?  */
+			if (signr != info->si_signo) {
+				info->si_signo = signr;
+				info->si_errno = 0;
+				info->si_code = SI_USER;
+				info->si_pid = current->parent->pid;
+				info->si_uid = current->parent->uid;
+			}
+
+			/* If the (new) signal is now blocked, requeue it.  */
+			if (sigismember(&current->blocked, signr)) {
+				send_sig_info(signr, info, current);
+				continue;
+			}
+		}
+
+		ka = &current->sig->action[signr-1];
+		if (ka->sa.sa_handler == SIG_IGN) {
+			if (signr != SIGCHLD)
+				continue;
+			/* Check for SIGCHLD: it's special.  */
+			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+				/* nothing */;
+			continue;
+		}
+
+		if (ka->sa.sa_handler == SIG_DFL) {
+			int exit_code = signr;
+
+			/* Init gets no signals it doesn't want.  */
+			if (current->pid == 1)
+				continue;
+
+			switch (signr) {
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
+				continue;
+
+			case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (is_orphaned_pgrp(current->pgrp))
+					continue;
+				/* FALLTHRU */
+
+			case SIGSTOP: {
+				struct signal_struct *sig;
+				set_current_state(TASK_STOPPED);
+				current->exit_code = signr;
+				sig = current->parent->sig;
+				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+					notify_parent(current, SIGCHLD);
+				schedule();
+				continue;
+			}
+
+			case SIGQUIT: case SIGILL: case SIGTRAP:
+			case SIGABRT: case SIGFPE: case SIGSEGV:
+			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
+				if (do_coredump(signr, regs))
+					exit_code |= 0x80;
+				/* FALLTHRU */
+
+			default:
+				sig_exit(signr, exit_code, info);
+				/* NOTREACHED */
+			}
+		}
+		return signr;
+	}
+	return 0;
+}
+
+#endif
+
 EXPORT_SYMBOL(dequeue_signal);
 EXPORT_SYMBOL(flush_signals);
 EXPORT_SYMBOL(force_sig);
@@ -931,6 +1038,45 @@
 {
 	return do_sigpending(set, sigsetsize);
 }
+
+#ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER
+
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+		return -EFAULT;
+	if (from->si_code < 0)
+		return __copy_to_user(to, from, sizeof(siginfo_t));
+	else {
+		int err;
+
+		/* If you change siginfo_t structure, please be sure
+		   this code is fixed accordingly.
+		   It should never copy any pad contained in the structure
+		   to avoid security leaks, but must copy the generic
+		   3 ints plus the relevant union member.  */
+		err = __put_user(from->si_signo, &to->si_signo);
+		err |= __put_user(from->si_errno, &to->si_errno);
+		err |= __put_user((short)from->si_code, &to->si_code);
+		/* First 32bits of unions are always present.  */
+		err |= __put_user(from->si_pid, &to->si_pid);
+		switch (from->si_code >> 16) {
+		case __SI_FAULT >> 16:
+			break;
+		case __SI_CHLD >> 16:
+			err |= __put_user(from->si_utime, &to->si_utime);
+			err |= __put_user(from->si_stime, &to->si_stime);
+			err |= __put_user(from->si_status, &to->si_status);
+		default:
+			err |= __put_user(from->si_uid, &to->si_uid);
+			break;
+		/* case __SI_RT: This is not generated by the kernel as of now.  */
+		}
+		return err;
+	}
+}
+
+#endif
 
 asmlinkage long
 sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo,
diff -Nru a/kernel/suspend.c b/kernel/suspend.c
--- a/kernel/suspend.c	Wed May 29 11:43:02 2002
+++ b/kernel/suspend.c	Wed May 29 11:43:02 2002
@@ -1,5 +1,5 @@
 /*
- * linux/kernel/swsusp.c
+ * linux/kernel/suspend.c
  *
  * This file is to realize architecture-independent
  * machine suspend feature using pretty near only high-level routines
@@ -34,13 +34,6 @@
  * For TODOs,FIXMEs also look in Documentation/swsusp.txt
  */
 
-/*
- * TODO:
- *
- * - we should launch a kernel_thread to process suspend request, cleaning up
- * bdflush from this task. (check apm.c for something similar).
- */
-
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/swapctl.h>
@@ -49,7 +42,6 @@
 #include <linux/file.h>
 #include <linux/utsname.h>
 #include <linux/version.h>
-#include <linux/compile.h>
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
@@ -66,6 +58,7 @@
 #include <linux/swap.h>
 #include <linux/pm.h>
 #include <linux/device.h>
+#include <linux/buffer_head.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -79,7 +72,7 @@
    we probably do not take enough locks for switching consoles, etc,
    so bad things might happen.
 */
-#ifndef CONFIG_VT
+#if !defined(CONFIG_VT) || !defined(CONFIG_VT_CONSOLE)
 #undef SUSPEND_CONSOLE
 #endif
 
@@ -153,7 +146,7 @@
 #define	DEBUG_DEFAULT	1
 #undef	DEBUG_PROCESS
 #undef	DEBUG_SLOW
-#define TEST_SWSUSP 0		/* Set to 1 to reboot instead of halt machine after suspension */
+#define TEST_SWSUSP 1		/* Set to 1 to reboot instead of halt machine after suspension */
 
 #ifdef DEBUG_DEFAULT
 #define PRINTD(func, f, a...)	\
@@ -776,7 +769,10 @@
 		machine_restart(NULL);
 	else
 #endif
+	{
+		device_shutdown();
 		machine_power_off();
+	}
 
 	printk(KERN_EMERG "%sProbably not capable for powerdown. System halted.\n", name_suspend);
 	machine_halt();
@@ -784,9 +780,6 @@
 	/* NOTREACHED */
 }
 
-/* forward decl */
-void do_software_suspend(void);
-
 /*
  * Magic happens here
  */
@@ -823,7 +816,6 @@
 #ifdef SUSPEND_CONSOLE
 	update_screen(fg_console);	/* Hmm, is this the problem? */
 #endif
-	suspend_tq.routine = (void *)do_software_suspend;
 }
 
 static void do_magic_suspend_1(void)
@@ -852,7 +844,6 @@
 	drivers_resume(RESUME_PHASE1);
 	spin_unlock_irq(&suspend_pagedir_lock);
 	mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
-	suspend_tq.routine = (void *)do_software_suspend;
 	printk(KERN_WARNING "%sLeaving do_magic_suspend_2...\n", name_suspend);	
 }
 
@@ -860,43 +851,38 @@
 #include <asm/suspend.h>
 
 /*
- * This function is triggered using process bdflush. We try to swap out as
- * much as we can then make a copy of the occupied pages in memory so we can
- * make a copy of kernel state atomically, the I/O needed by saving won't
- * bother us anymore.
+ * We try to swap out as much as we can then make a copy of the
+ * occupied pages in memory so we can make a copy of kernel state
+ * atomically, the I/O needed by saving won't bother us anymore. 
  */
 void do_software_suspend(void)
 {
 	arch_prepare_suspend();
-	if (!prepare_suspend_console()) {
-		if (!prepare_suspend_processes()) {
-			free_some_memory();
-
-			/* No need to invalidate any vfsmnt list -- they will be valid after resume, anyway.
-			 *
-			 * We sync here -- so you have consistent filesystem state when things go wrong.
-			 * -- so that noone writes to disk after we do atomic copy of data.
-			 */
-			PRINTS("Syncing disks before copy\n");
-			do_suspend_sync();
-			if(drivers_suspend()==0)
-				do_magic(0);			/* This function returns after machine woken up from resume */
-			PRINTR("Restarting processes...\n");
-			thaw_processes();
-		}
+	if (prepare_suspend_console())
+		printk( "Can't allocate a console... proceeding\n");
+	if (!prepare_suspend_processes()) {
+		free_some_memory();
+		
+		/* No need to invalidate any vfsmnt list -- they will be valid after resume, anyway.
+		 *
+		 * We sync here -- so you have consistent filesystem state when things go wrong.
+		 * -- so that noone writes to disk after we do atomic copy of data.
+		 */
+		PRINTS("Syncing disks before copy\n");
+		do_suspend_sync();
+		if(drivers_suspend()==0)
+			do_magic(0);			/* This function returns after machine woken up from resume */
+		PRINTR("Restarting processes...\n");
+		thaw_processes();
 	}
 	software_suspend_enabled = 1;
 	MDELAY(1000);
 	restore_console ();
 }
 
-struct tq_struct suspend_tq =
-	{ routine: (void *)(void *)do_software_suspend, 
-	  data: 0 };
-
 /*
- * This is the trigger function, we must queue ourself since we
- * can be called from interrupt && bdflush context is needed
+ * This is main interface to the outside world. It needs to be
+ * called from process context.
  */
 void software_suspend(void)
 {
@@ -904,8 +890,8 @@
 		return;
 
 	software_suspend_enabled = 0;
-	queue_task(&suspend_tq, &tq_bdflush);
-	wakeup_bdflush();
+	BUG_ON(in_interrupt());
+	do_software_suspend();
 }
 
 /* More restore stuff */
@@ -1124,6 +1110,7 @@
 	pagedir_order = get_bitmask_order(nr_pgdir_pages);
 
 	error = -ENOMEM;
+	free_page((unsigned long) cur);
 	pagedir_nosave = (suspend_pagedir_t *)__get_free_pages(GFP_ATOMIC, pagedir_order);
 	if(!pagedir_nosave)
 		goto resume_read_error;
diff -Nru a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c	Wed May 29 11:43:02 2002
+++ b/kernel/timer.c	Wed May 29 11:43:02 2002
@@ -597,17 +597,7 @@
  */
 static unsigned long count_active_tasks(void)
 {
-	struct task_struct *p;
-	unsigned long nr = 0;
-
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if ((p->state == TASK_RUNNING ||
-		     (p->state & TASK_UNINTERRUPTIBLE)))
-			nr += FIXED_1;
-	}
-	read_unlock(&tasklist_lock);
-	return nr;
+	return (nr_running() + nr_uninterruptible()) * FIXED_1;
 }
 
 /*
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Wed May 29 11:43:02 2002
+++ b/mm/filemap.c	Wed May 29 11:43:02 2002
@@ -463,7 +463,7 @@
  */
 int filemap_fdatawrite(struct address_space *mapping)
 {
-	return writeback_mapping(mapping, NULL);
+	return do_writepages(mapping, NULL);
 }
 
 /**
@@ -1415,16 +1415,19 @@
 	return ret;
 }
 
-static ssize_t do_readahead(struct file *file, unsigned long index, unsigned long nr)
+static ssize_t
+do_readahead(struct file *file, unsigned long index, unsigned long nr)
 {
 	struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
 	unsigned long max;
+	struct page_state ps;
 
 	if (!mapping || !mapping->a_ops || !mapping->a_ops->readpage)
 		return -EINVAL;
 
 	/* Limit it to a sane percentage of the inactive list.. */
-	max = nr_inactive_pages / 2;
+	get_page_state(&ps);
+	max = ps.nr_inactive / 2;
 	if (nr > max)
 		nr = max;
 
@@ -2074,48 +2077,43 @@
 /*
  * Write to a file through the page cache. 
  *
- * We currently put everything into the page cache prior to writing it.
- * This is not a problem when writing full pages. With partial pages,
- * however, we first have to read the data into the cache, then
- * dirty the page, and finally schedule it for writing. Alternatively, we
- * could write-through just the portion of data that would go into that
- * page, but that would kill performance for applications that write data
- * line by line, and it's prone to race conditions.
- *
- * Note that this routine doesn't try to keep track of dirty pages. Each
- * file system has to do this all by itself, unfortunately.
+ * We put everything into the page cache prior to writing it. This is not a
+ * problem when writing full pages. With partial pages, however, we first have
+ * to read the data into the cache, then dirty the page, and finally schedule
+ * it for writing by marking it dirty.
  *							okir@monad.swb.de
  */
 ssize_t
-generic_file_write(struct file *file,const char *buf,size_t count, loff_t *ppos)
+generic_file_write(struct file *file, const char *buf,
+		size_t count, loff_t *ppos)
 {
-	struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
-	struct inode	*inode = mapping->host;
+	struct address_space * mapping = file->f_dentry->d_inode->i_mapping;
+	struct address_space_operations *a_ops = mapping->a_ops;
+	struct inode 	*inode = mapping->host;
 	unsigned long	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+	long		status = 0;
 	loff_t		pos;
-	struct page	*page, *cached_page;
+	struct page	*page;
+	struct page	*cached_page = NULL;
 	ssize_t		written;
-	long		status = 0;
 	int		err;
 	unsigned	bytes;
 
-	if ((ssize_t) count < 0)
+	if (unlikely((ssize_t) count < 0))
 		return -EINVAL;
 
-	if (!access_ok(VERIFY_READ, buf, count))
+	if (unlikely(!access_ok(VERIFY_READ, buf, count)))
 		return -EFAULT;
 
-	cached_page = NULL;
-
 	down(&inode->i_sem);
-
 	pos = *ppos;
-	err = -EINVAL;
-	if (pos < 0)
+	if (unlikely(pos < 0)) {
+		err = -EINVAL;
 		goto out;
+	}
 
-	err = file->f_error;
-	if (err) {
+	if (unlikely(file->f_error)) {
+		err = file->f_error;
 		file->f_error = 0;
 		goto out;
 	}
@@ -2129,11 +2127,10 @@
 	/*
 	 * Check whether we've reached the file size limit.
 	 */
-	err = -EFBIG;
-	
-	if (limit != RLIM_INFINITY) {
+	if (unlikely(limit != RLIM_INFINITY)) {
 		if (pos >= limit) {
 			send_sig(SIGXFSZ, current, 0);
+			err = -EFBIG;
 			goto out;
 		}
 		if (pos > 0xFFFFFFFFULL || count > limit - (u32)pos) {
@@ -2143,11 +2140,13 @@
 	}
 
 	/*
-	 *	LFS rule 
+	 * LFS rule
 	 */
-	if ( pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
+	if (unlikely(pos + count > MAX_NON_LFS &&
+				!(file->f_flags & O_LARGEFILE))) {
 		if (pos >= MAX_NON_LFS) {
 			send_sig(SIGXFSZ, current, 0);
+			err = -EFBIG;
 			goto out;
 		}
 		if (count > MAX_NON_LFS - (u32)pos) {
@@ -2157,18 +2156,14 @@
 	}
 
 	/*
-	 *	Are we about to exceed the fs block limit ?
+	 * Are we about to exceed the fs block limit ?
 	 *
-	 *	If we have written data it becomes a short write
-	 *	If we have exceeded without writing data we send
-	 *	a signal and give them an EFBIG.
-	 *
-	 *	Linus frestrict idea will clean these up nicely..
+	 * If we have written data it becomes a short write.  If we have
+	 * exceeded without writing data we send a signal and return EFBIG.
+	 * Linus frestrict idea will clean these up nicely..
 	 */
-	 
-	if (!S_ISBLK(inode->i_mode)) {
-		if (pos >= inode->i_sb->s_maxbytes)
-		{
+	if (likely(!S_ISBLK(inode->i_mode))) {
+		if (unlikely(pos >= inode->i_sb->s_maxbytes)) {
 			if (count || pos > inode->i_sb->s_maxbytes) {
 				send_sig(SIGXFSZ, current, 0);
 				err = -EFBIG;
@@ -2177,7 +2172,7 @@
 			/* zero-length writes at ->s_maxbytes are OK */
 		}
 
-		if (pos + count > inode->i_sb->s_maxbytes)
+		if (unlikely(pos + count > inode->i_sb->s_maxbytes))
 			count = inode->i_sb->s_maxbytes - pos;
 	} else {
 		if (is_read_only(inode->i_rdev)) {
@@ -2200,21 +2195,37 @@
 		goto out;
 
 	remove_suid(file->f_dentry);
-	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+	inode->i_ctime = CURRENT_TIME;
+	inode->i_mtime = CURRENT_TIME;
 	mark_inode_dirty_sync(inode);
 
-	if (file->f_flags & O_DIRECT)
-		goto o_direct;
+	if (unlikely(file->f_flags & O_DIRECT)) {
+		written = generic_file_direct_IO(WRITE, file,
+						(char *) buf, count, pos);
+		if (written > 0) {
+			loff_t end = pos + written;
+			if (end > inode->i_size && !S_ISBLK(inode->i_mode)) {
+				inode->i_size = end;
+				mark_inode_dirty(inode);
+			}
+			*ppos = end;
+			invalidate_inode_pages2(mapping);
+		}
+		/*
+		 * Sync the fs metadata but not the minor inode changes and
+		 * of course not the data as we did direct DMA for the IO.
+		 */
+		if (written >= 0 && file->f_flags & O_SYNC)
+			status = generic_osync_inode(inode, OSYNC_METADATA);
+		goto out_status;
+	}
 
 	do {
-		unsigned long index, offset;
+		unsigned long index;
+		unsigned long offset;
 		long page_fault;
 		char *kaddr;
 
-		/*
-		 * Try to find the page in the cache. If it isn't there,
-		 * allocate a free page.
-		 */
 		offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
 		index = pos >> PAGE_CACHE_SHIFT;
 		bytes = PAGE_CACHE_SIZE - offset;
@@ -2232,96 +2243,67 @@
 			__get_user(dummy, buf+bytes-1);
 		}
 
-		status = -ENOMEM;	/* we'll assign it later anyway */
 		page = __grab_cache_page(mapping, index, &cached_page);
-		if (!page)
+		if (!page) {
+			status = -ENOMEM;
 			break;
-
-		/* We have exclusive IO access to the page.. */
-		if (!PageLocked(page)) {
-			PAGE_BUG(page);
 		}
 
 		kaddr = kmap(page);
-		status = mapping->a_ops->prepare_write(file, page, offset, offset+bytes);
-		if (status)
-			goto sync_failure;
-		page_fault = __copy_from_user(kaddr+offset, buf, bytes);
+		status = a_ops->prepare_write(file, page, offset, offset+bytes);
+		if (unlikely(status)) {
+			/*
+			 * prepare_write() may have instantiated a few blocks
+			 * outside i_size.  Trim these off again.
+			 */
+			kunmap(page);
+			unlock_page(page);
+			page_cache_release(page);
+			if (pos + bytes > inode->i_size)
+				vmtruncate(inode, inode->i_size);
+			break;
+		}
+		page_fault = __copy_from_user(kaddr + offset, buf, bytes);
 		flush_dcache_page(page);
-		status = mapping->a_ops->commit_write(file, page, offset, offset+bytes);
-		if (page_fault)
-			goto fail_write;
-		if (!status)
-			status = bytes;
-
-		if (status >= 0) {
-			written += status;
-			count -= status;
-			pos += status;
-			buf += status;
+		status = a_ops->commit_write(file, page, offset, offset+bytes);
+		if (unlikely(page_fault)) {
+			status = -EFAULT;
+		} else {
+			if (!status)
+				status = bytes;
+
+			if (status >= 0) {
+				written += status;
+				count -= status;
+				pos += status;
+				buf += status;
+			}
 		}
-unlock:
 		kunmap(page);
-		/* Mark it unlocked again and drop the page.. */
 		SetPageReferenced(page);
 		unlock_page(page);
 		page_cache_release(page);
-
 		if (status < 0)
 			break;
 		balance_dirty_pages_ratelimited(mapping);
 	} while (count);
-done:
 	*ppos = pos;
 
 	if (cached_page)
 		page_cache_release(cached_page);
 
-	/* For now, when the user asks for O_SYNC, we'll actually
-	 * provide O_DSYNC. */
+	/*
+	 * For now, when the user asks for O_SYNC, we'll actually give O_DSYNC
+	 */
 	if (status >= 0) {
 		if ((file->f_flags & O_SYNC) || IS_SYNC(inode))
-			status = generic_osync_inode(inode, OSYNC_METADATA|OSYNC_DATA);
+			status = generic_osync_inode(inode,
+					OSYNC_METADATA|OSYNC_DATA);
 	}
 	
 out_status:	
 	err = written ? written : status;
 out:
-
 	up(&inode->i_sem);
 	return err;
-fail_write:
-	status = -EFAULT;
-	goto unlock;
-
-sync_failure:
-	/*
-	 * If blocksize < pagesize, prepare_write() may have instantiated a
-	 * few blocks outside i_size.  Trim these off again.
-	 */
-	kunmap(page);
-	unlock_page(page);
-	page_cache_release(page);
-	if (pos + bytes > inode->i_size)
-		vmtruncate(inode, inode->i_size);
-	goto done;
-
-o_direct:
-	written = generic_file_direct_IO(WRITE, file, (char *) buf, count, pos);
-	if (written > 0) {
-		loff_t end = pos + written;
-		if (end > inode->i_size && !S_ISBLK(inode->i_mode)) {
-			inode->i_size = end;
-			mark_inode_dirty(inode);
-		}
-		*ppos = end;
-		invalidate_inode_pages2(mapping);
-	}
-	/*
-	 * Sync the fs metadata but not the minor inode changes and
-	 * of course not the data as we did direct DMA for the IO.
-	 */
-	if (written >= 0 && file->f_flags & O_SYNC)
-		status = generic_osync_inode(inode, OSYNC_METADATA);
-	goto out_status;
 }
diff -Nru a/mm/memory.c b/mm/memory.c
--- a/mm/memory.c	Wed May 29 11:43:02 2002
+++ b/mm/memory.c	Wed May 29 11:43:03 2002
@@ -69,7 +69,7 @@
 	copy_user_highpage(to, from, address);
 }
 
-mem_map_t * mem_map;
+struct page *mem_map;
 
 /*
  * Note: this doesn't free the actual pages themselves. That
diff -Nru a/mm/mempool.c b/mm/mempool.c
--- a/mm/mempool.c	Wed May 29 11:43:01 2002
+++ b/mm/mempool.c	Wed May 29 11:43:01 2002
@@ -220,7 +220,7 @@
 	if (gfp_mask == gfp_nowait)
 		return NULL;
 
-	run_task_queue(&tq_disk);
+	blk_run_queues();
 
 	add_wait_queue_exclusive(&pool->wait, &wait);
 	set_task_state(current, TASK_UNINTERRUPTIBLE);
diff -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c	Wed May 29 11:43:01 2002
+++ b/mm/mmap.c	Wed May 29 11:43:01 2002
@@ -398,11 +398,13 @@
 	if (file && (!file->f_op || !file->f_op->mmap))
 		return -ENODEV;
 
-	if ((len = PAGE_ALIGN(len)) == 0)
+	if (!len)
 		return addr;
 
 	if (len > TASK_SIZE)
 		return -EINVAL;
+
+	len = PAGE_ALIGN(len);
 
 	/* offset overflow? */
 	if ((pgoff + (len >> PAGE_SHIFT)) < pgoff)
diff -Nru a/mm/numa.c b/mm/numa.c
--- a/mm/numa.c	Wed May 29 11:43:02 2002
+++ b/mm/numa.c	Wed May 29 11:43:02 2002
@@ -65,8 +65,8 @@
 	int i, size = 0;
 	struct page *discard;
 
-	if (mem_map == (mem_map_t *)NULL)
-		mem_map = (mem_map_t *)PAGE_OFFSET;
+	if (mem_map == NULL)
+		mem_map = (struct page *)PAGE_OFFSET;
 
 	free_area_init_core(nid, pgdat, &discard, zones_size, zone_start_paddr,
 					zholes_size, pmap);
diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c
--- a/mm/page-writeback.c	Wed May 29 11:43:01 2002
+++ b/mm/page-writeback.c	Wed May 29 11:43:01 2002
@@ -50,7 +50,7 @@
  */
 static int dirty_sync_ratio = 60;
 
-static void background_writeout(unsigned long unused);
+static void background_writeout(unsigned long _min_pages);
 
 /*
  * balance_dirty_pages() must be called by processes which are
@@ -148,7 +148,7 @@
 		writeback_unlocked_inodes(&nr_to_write, WB_SYNC_NONE, NULL);
 		min_pages -= MAX_WRITEBACK_PAGES - nr_to_write;
 	} while (nr_to_write <= 0);
-	run_task_queue(&tq_disk);
+	blk_run_queues();
 }
 
 /*
@@ -206,7 +206,7 @@
 	next_jif = start_jif + wb_writeback_jifs;
 	nr_to_write = ps.nr_dirty;
 	writeback_unlocked_inodes(&nr_to_write, WB_SYNC_NONE, &oldest_jif);
-	run_task_queue(&tq_disk);
+	blk_run_queues();
 	yield();
 
 	if (time_before(next_jif, jiffies + HZ))
@@ -267,7 +267,7 @@
 	unlock_page(page);
 
 	if (inode) {
-		writeback_mapping(inode->i_mapping, nr_to_write);
+		do_writepages(inode->i_mapping, nr_to_write);
 
 		/*
 		 * This iput() will internally call ext2_discard_prealloc(),
@@ -292,13 +292,13 @@
 EXPORT_SYMBOL(generic_vm_writeback);
 
 /**
- * generic_writeback_mapping - walk the list of dirty pages of the given
+ * generic_writepages - walk the list of dirty pages of the given
  * address space and writepage() all of them.
  * 
  * @mapping: address space structure to write
  * @nr_to_write: subtract the number of written pages from *@nr_to_write
  *
- * This is a library function, which implements the writeback_mapping()
+ * This is a library function, which implements the writepages()
  * address_space_operation.
  *
  * (The next two paragraphs refer to code which isn't here yet, but they
@@ -307,7 +307,7 @@
  * Pages can be moved from clean_pages or locked_pages onto dirty_pages
  * at any time - it's not possible to lock against that.  So pages which
  * have already been added to a BIO may magically reappear on the dirty_pages
- * list.  And generic_writeback_mapping() will again try to lock those pages.
+ * list.  And generic_writepages() will again try to lock those pages.
  * But I/O has not yet been started against the page.  Thus deadlock.
  *
  * To avoid this, the entire contents of the dirty_pages list are moved
@@ -317,7 +317,7 @@
  * This has the added benefit of preventing a livelock which would otherwise
  * occur if pages are being dirtied faster than we can write them out.
  *
- * If a page is already under I/O, generic_writeback_mapping() skips it, even
+ * If a page is already under I/O, generic_writepages() skips it, even
  * if it's dirty.  This is desirable behaviour for memory-cleaning writeback,
  * but it is INCORRECT for data-integrity system calls such as fsync().  fsync()
  * and msync() need to guarentee that all the data which was dirty at the time
@@ -327,7 +327,7 @@
  * It's fairly rare for PageWriteback pages to be on ->dirty_pages.  It
  * means that someone redirtied the page while it was under I/O.
  */
-int generic_writeback_mapping(struct address_space *mapping, int *nr_to_write)
+int generic_writepages(struct address_space *mapping, int *nr_to_write)
 {
 	int (*writepage)(struct page *) = mapping->a_ops->writepage;
 	int ret = 0;
@@ -394,13 +394,13 @@
 	write_unlock(&mapping->page_lock);
 	return ret;
 }
-EXPORT_SYMBOL(generic_writeback_mapping);
+EXPORT_SYMBOL(generic_writepages);
 
-int writeback_mapping(struct address_space *mapping, int *nr_to_write)
+int do_writepages(struct address_space *mapping, int *nr_to_write)
 {
-	if (mapping->a_ops->writeback_mapping)
-		return mapping->a_ops->writeback_mapping(mapping, nr_to_write);
-	return generic_writeback_mapping(mapping, nr_to_write);
+	if (mapping->a_ops->writepages)
+		return mapping->a_ops->writepages(mapping, nr_to_write);
+	return generic_writepages(mapping, nr_to_write);
 }
 
 /**
@@ -491,6 +491,9 @@
 		SetPageDirty(page);
 		goto out;
 	}
+
+	if (!PageUptodate(page))
+		buffer_error();
 
 	spin_lock(&mapping->private_lock);
 
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Wed May 29 11:43:01 2002
+++ b/mm/page_alloc.c	Wed May 29 11:43:01 2002
@@ -27,8 +27,6 @@
 unsigned long totalram_pages;
 unsigned long totalhigh_pages;
 int nr_swap_pages;
-int nr_active_pages;
-int nr_inactive_pages;
 struct list_head inactive_list;
 struct list_head active_list;
 pg_data_t *pgdat_list;
@@ -249,42 +247,26 @@
 }
 
 #ifdef CONFIG_SOFTWARE_SUSPEND
-int is_head_of_free_region(struct page *p)
+int is_head_of_free_region(struct page *page)
 {
-	pg_data_t *pgdat = pgdat_list;
-	unsigned type;
-	unsigned long flags;
-
-	for (type=0;type < MAX_NR_ZONES; type++) {
-		zone_t *zone = pgdat->node_zones + type;
-		int order = MAX_ORDER - 1;
-		free_area_t *area;
-		struct list_head *head, *curr;
-		spin_lock_irqsave(&zone->lock, flags);	/* Should not matter as we need quiescent system for suspend anyway, but... */
-
-		do {
-			area = zone->free_area + order;
-			head = &area->free_list;
-			curr = head;
-
-			for(;;) {
-				if(!curr) {
-//					printk("FIXME: this should not happen but it does!!!");
-					break;
-				}
-				if(p != memlist_entry(curr, struct page, list)) {
-					curr = memlist_next(curr);
-					if (curr == head)
-						break;
-					continue;
-				}
+        zone_t *zone = page_zone(page);
+        unsigned long flags;
+	int order;
+	list_t *curr;
+
+	/*
+	 * Should not matter as we need quiescent system for
+	 * suspend anyway, but...
+	 */
+	spin_lock_irqsave(&zone->lock, flags);
+	for (order = MAX_ORDER - 1; order >= 0; --order)
+		list_for_each(curr, &zone->free_area[order].free_list)
+			if (page == list_entry(curr, struct page, list)) {
+				spin_unlock_irqrestore(&zone->lock, flags);
 				return 1 << order;
 			}
-		} while(order--);
-		spin_unlock_irqrestore(&zone->lock, flags);
-
-	}
-	return 0;
+	spin_unlock_irqrestore(&zone->lock, flags);
+        return 0;
 }
 #endif /* CONFIG_SOFTWARE_SUSPEND */
 
@@ -528,7 +510,7 @@
 /*
  * Total amount of free (allocatable) RAM:
  */
-unsigned int nr_free_pages (void)
+unsigned int nr_free_pages(void)
 {
 	unsigned int sum;
 	zone_t *zone;
@@ -543,16 +525,13 @@
 	return sum;
 }
 
-/*
- * Amount of free RAM allocatable as buffer memory:
- */
-unsigned int nr_free_buffer_pages (void)
+static unsigned int nr_free_zone_pages(int offset)
 {
 	pg_data_t *pgdat = pgdat_list;
 	unsigned int sum = 0;
 
 	do {
-		zonelist_t *zonelist = pgdat->node_zonelists + (GFP_USER & GFP_ZONEMASK);
+		zonelist_t *zonelist = pgdat->node_zonelists + offset;
 		zone_t **zonep = zonelist->zones;
 		zone_t *zone;
 
@@ -570,30 +549,19 @@
 }
 
 /*
- * Amount of free RAM allocatable as pagecache memory:
+ * Amount of free RAM allocatable within ZONE_DMA and ZONE_NORMAL
  */
-unsigned int nr_free_pagecache_pages(void)
+unsigned int nr_free_buffer_pages(void)
 {
-	pg_data_t *pgdat = pgdat_list;
-	unsigned int sum = 0;
-
-	do {
-		zonelist_t *zonelist = pgdat->node_zonelists +
-				(GFP_HIGHUSER & GFP_ZONEMASK);
-		zone_t **zonep = zonelist->zones;
-		zone_t *zone;
-
-		for (zone = *zonep++; zone; zone = *zonep++) {
-			unsigned long size = zone->size;
-			unsigned long high = zone->pages_high;
-			if (size > high)
-				sum += size - high;
-		}
-
-		pgdat = pgdat->node_next;
-	} while (pgdat);
+	return nr_free_zone_pages(GFP_USER & GFP_ZONEMASK);
+}
 
-	return sum;
+/*
+ * Amount of free RAM allocatable within all zones
+ */
+unsigned int nr_free_pagecache_pages(void)
+{
+	return nr_free_zone_pages(GFP_HIGHUSER & GFP_ZONEMASK);
 }
 
 #if CONFIG_HIGHMEM
@@ -622,10 +590,7 @@
 {
 	int pcpu;
 
-	ret->nr_dirty = 0;
-	ret->nr_writeback = 0;
-	ret->nr_pagecache = 0;
-
+	memset(ret, 0, sizeof(*ret));
 	for (pcpu = 0; pcpu < smp_num_cpus; pcpu++) {
 		struct page_state *ps;
 
@@ -633,6 +598,8 @@
 		ret->nr_dirty += ps->nr_dirty;
 		ret->nr_writeback += ps->nr_writeback;
 		ret->nr_pagecache += ps->nr_pagecache;
+		ret->nr_active += ps->nr_active;
+		ret->nr_inactive += ps->nr_inactive;
 	}
 }
 
@@ -672,6 +639,9 @@
  	unsigned int order;
 	unsigned type;
 	pg_data_t *tmpdat = pgdat;
+	struct page_state ps;
+
+	get_page_state(&ps);
 
 	printk("Free pages:      %6dkB (%6dkB HighMem)\n",
 		K(nr_free_pages()),
@@ -692,10 +662,12 @@
 		tmpdat = tmpdat->node_next;
 	}
 
-	printk("( Active: %d, inactive: %d, free: %d )\n",
-	       nr_active_pages,
-	       nr_inactive_pages,
-	       nr_free_pages());
+	printk("( Active:%lu inactive:%lu dirty:%lu writeback:%lu free:%u )\n",
+		ps.nr_active,
+		ps.nr_inactive,
+		ps.nr_dirty,
+		ps.nr_writeback,
+		nr_free_pages());
 
 	for (type = 0; type < MAX_NR_ZONES; type++) {
 		struct list_head *head, *curr;
diff -Nru a/mm/pdflush.c b/mm/pdflush.c
--- a/mm/pdflush.c	Wed May 29 11:43:03 2002
+++ b/mm/pdflush.c	Wed May 29 11:43:03 2002
@@ -91,7 +91,7 @@
 	recalc_sigpending();
 	spin_unlock_irq(&current->sigmask_lock);
 
-	current->flags |= PF_FLUSHER | PF_KERNTHREAD;
+	current->flags |= PF_FLUSHER;
 	my_work->fn = NULL;
 	my_work->who = current;
 
@@ -106,11 +106,8 @@
 		set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irq(&pdflush_lock);
 
-#ifdef CONFIG_SOFTWARE_SUSPEND
-		run_task_queue(&tq_bdflush);
 		if (current->flags & PF_FREEZE)
 			refrigerator(PF_IOTHREAD);
-#endif
 		schedule();
 
 		if (my_work->fn)
diff -Nru a/mm/readahead.c b/mm/readahead.c
--- a/mm/readahead.c	Wed May 29 11:43:01 2002
+++ b/mm/readahead.c	Wed May 29 11:43:01 2002
@@ -31,6 +31,25 @@
 	return (VM_MIN_READAHEAD * 1024) / PAGE_CACHE_SIZE;
 }
 
+static int
+read_pages(struct address_space *mapping,
+		struct list_head *pages, unsigned nr_pages)
+{
+	unsigned page_idx;
+
+	if (mapping->a_ops->readpages)
+		return mapping->a_ops->readpages(mapping, pages, nr_pages);
+
+	for (page_idx = 0; page_idx < nr_pages; page_idx++) {
+		struct page *page = list_entry(pages->prev, struct page, list);
+		list_del(&page->list);
+		if (!add_to_page_cache_unique(page, mapping, page->index))
+			mapping->a_ops->readpage(NULL, page);
+		page_cache_release(page);
+	}
+	return 0;
+}
+
 /*
  * Readahead design.
  *
@@ -148,24 +167,9 @@
 	 * uptodate then the caller will launch readpage again, and
 	 * will then handle the error.
 	 */
-	for (page_idx = 0; page_idx < nr_to_really_read; page_idx++) {
-		if (list_empty(&page_pool))
-			BUG();
-		page = list_entry(page_pool.prev, struct page, list);
-		list_del(&page->list);
-		if (!add_to_page_cache_unique(page, mapping, page->index))
-			mapping->a_ops->readpage(file, page);
-		page_cache_release(page);
-	}
-
-	/*
-	 * Do this now, rather than at the next wait_on_page_locked().
-	 */
-	run_task_queue(&tq_disk);
-
-	if (!list_empty(&page_pool))
-		BUG();
-
+	read_pages(mapping, &page_pool, nr_to_really_read);
+	blk_run_queues();
+	BUG_ON(!list_empty(&page_pool));
 	return;
 }
 
diff -Nru a/mm/swap_state.c b/mm/swap_state.c
--- a/mm/swap_state.c	Wed May 29 11:43:02 2002
+++ b/mm/swap_state.c	Wed May 29 11:43:02 2002
@@ -36,17 +36,15 @@
  * swapper_space doesn't have a real inode, so it gets a special vm_writeback()
  * so we don't need swap special cases in generic_vm_writeback().
  *
- * FIXME: swap pages are locked, but not PageWriteback while under writeout.
- * This will confuse throttling in shrink_cache().  It may be advantageous to
- * set PG_writeback against swap pages while they're also locked.  Either that,
- * or special-case swap pages in shrink_cache().
+ * Swap pages are PageLocked and PageWriteback while under writeout so that
+ * memory allocators will throttle against them.
  */
 static int swap_vm_writeback(struct page *page, int *nr_to_write)
 {
 	struct address_space *mapping = page->mapping;
 
 	unlock_page(page);
-	return generic_writeback_mapping(mapping, nr_to_write);
+	return generic_writepages(mapping, nr_to_write);
 }
 
 static struct address_space_operations swap_aops = {
diff -Nru a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c	Wed May 29 11:43:01 2002
+++ b/mm/vmscan.c	Wed May 29 11:43:01 2002
@@ -380,16 +380,17 @@
 	return 0;
 }
 
-static int FASTCALL(shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int priority));
-static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int priority)
+static int
+shrink_cache(int nr_pages, zone_t *classzone,
+		unsigned int gfp_mask, int priority, int max_scan)
 {
 	struct list_head * entry;
 	struct address_space *mapping;
-	int max_scan = nr_inactive_pages / priority;
 	int max_mapped = nr_pages << (9 - priority);
 
 	spin_lock(&pagemap_lru_lock);
-	while (--max_scan >= 0 && (entry = inactive_list.prev) != &inactive_list) {
+	while (--max_scan >= 0 &&
+			(entry = inactive_list.prev) != &inactive_list) {
 		struct page * page;
 
 		if (need_resched()) {
@@ -619,17 +620,25 @@
 {
 	int chunk_size = nr_pages;
 	unsigned long ratio;
+	struct page_state ps;
+	int max_scan;
 
 	nr_pages -= kmem_cache_reap(gfp_mask);
 	if (nr_pages <= 0)
 		return 0;
 
 	nr_pages = chunk_size;
-	/* try to keep the active list 2/3 of the size of the cache */
-	ratio = (unsigned long) nr_pages * nr_active_pages / ((nr_inactive_pages + 1) * 2);
-	refill_inactive(ratio);
 
-	nr_pages = shrink_cache(nr_pages, classzone, gfp_mask, priority);
+	/*
+	 * Try to keep the active list 2/3 of the size of the cache
+	 */
+	get_page_state(&ps);
+	ratio = (unsigned long)nr_pages * ps.nr_active /
+				((ps.nr_inactive | 1) * 2);
+	refill_inactive(ratio);
+	max_scan = ps.nr_inactive / priority;
+	nr_pages = shrink_cache(nr_pages, classzone,
+				gfp_mask, priority, max_scan);
 	if (nr_pages <= 0)
 		return 0;
 
@@ -782,7 +791,7 @@
 	 * us from recursively trying to free more memory as we're
 	 * trying to free the first piece of memory in the first place).
 	 */
-	tsk->flags |= PF_MEMALLOC | PF_KERNTHREAD;
+	tsk->flags |= PF_MEMALLOC;
 
 	/*
 	 * Kswapd main loop.
@@ -794,10 +803,8 @@
 		add_wait_queue(&kswapd_wait, &wait);
 
 		mb();
-		if (kswapd_can_sleep()) {
+		if (kswapd_can_sleep())
 			schedule();
-		}
-		
 
 		__set_current_state(TASK_RUNNING);
 		remove_wait_queue(&kswapd_wait, &wait);
@@ -808,7 +815,7 @@
 		 * up on a more timely basis.
 		 */
 		kswapd_balance();
-		run_task_queue(&tq_disk);
+		blk_run_queues();
 	}
 }
 
diff -Nru a/net/atm/pppoatm.c b/net/atm/pppoatm.c
--- a/net/atm/pppoatm.c	Wed May 29 11:43:01 2002
+++ b/net/atm/pppoatm.c	Wed May 29 11:43:01 2002
@@ -125,7 +125,7 @@
 	pvcc = atmvcc_to_pvcc(atmvcc);
 	atmvcc->push = pvcc->old_push;
 	atmvcc->pop = pvcc->old_pop;
-	tasklet_disable(&pvcc->wakeup_tasklet);
+	tasklet_kill(&pvcc->wakeup_tasklet);
 	ppp_unregister_channel(&pvcc->chan);
 	atmvcc->user_back = NULL;
 	kfree(pvcc);
diff -Nru a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c	Wed May 29 11:43:03 2002
+++ b/net/core/dev.c	Wed May 29 11:43:03 2002
@@ -1047,9 +1047,15 @@
 		int cpu = smp_processor_id();
 
 		if (dev->xmit_lock_owner != cpu) {
+			/*
+			 * The spin_lock effectivly does a preempt lock, but 
+			 * we are about to drop that...
+			 */
+			preempt_disable();
 			spin_unlock(&dev->queue_lock);
 			spin_lock(&dev->xmit_lock);
 			dev->xmit_lock_owner = cpu;
+			preempt_enable();
 
 			if (!netif_queue_stopped(dev)) {
 				if (netdev_nit)
diff -Nru a/net/core/skbuff.c b/net/core/skbuff.c
--- a/net/core/skbuff.c	Wed May 29 11:43:02 2002
+++ b/net/core/skbuff.c	Wed May 29 11:43:02 2002
@@ -111,33 +111,37 @@
 
 static __inline__ struct sk_buff *skb_head_from_pool(void)
 {
-	struct sk_buff_head *list = &skb_head_pool[smp_processor_id()].list;
+	struct sk_buff_head *list;
+	struct sk_buff *skb = NULL;
+	unsigned long flags;
 
-	if (skb_queue_len(list)) {
-		struct sk_buff *skb;
-		unsigned long flags;
+	local_irq_save(flags);
 
-		local_irq_save(flags);
+	list = &skb_head_pool[smp_processor_id()].list;
+
+	if (skb_queue_len(list))
 		skb = __skb_dequeue(list);
-		local_irq_restore(flags);
-		return skb;
-	}
-	return NULL;
+
+	local_irq_restore(flags);
+	return skb;
 }
 
 static __inline__ void skb_head_to_pool(struct sk_buff *skb)
 {
-	struct sk_buff_head *list = &skb_head_pool[smp_processor_id()].list;
+	struct sk_buff_head *list;
+	unsigned long flags;
 
-	if (skb_queue_len(list) < sysctl_hot_list_len) {
-		unsigned long flags;
+	local_irq_save(flags);
+	list = &skb_head_pool[smp_processor_id()].list;
 
-		local_irq_save(flags);
+	if (skb_queue_len(list) < sysctl_hot_list_len) {
 		__skb_queue_head(list, skb);
 		local_irq_restore(flags);
 
 		return;
 	}
+
+	local_irq_restore(flags);
 	kmem_cache_free(skbuff_head_cache, skb);
 }
 
diff -Nru a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
--- a/net/ipv4/ipconfig.c	Wed May 29 11:43:01 2002
+++ b/net/ipv4/ipconfig.c	Wed May 29 11:43:01 2002
@@ -1110,7 +1110,6 @@
 
 static int __init ip_auto_config(void)
 {
-	int retries = CONF_OPEN_RETRIES;
 	unsigned long jiff;
 
 #ifdef CONFIG_PROC_FS
@@ -1121,8 +1120,9 @@
 		return 0;
 
 	DBG(("IP-Config: Entered.\n"));
-
+#ifdef IPCONFIG_DYNAMIC
  try_try_again:
+#endif
 	/* Give hardware a chance to settle */
 	jiff = jiffies + CONF_PRE_OPEN;
 	while (time_before(jiffies, jiff))
@@ -1151,6 +1151,8 @@
 #endif
 	    ic_first_dev->next) {
 #ifdef IPCONFIG_DYNAMIC
+	
+		int retries = CONF_OPEN_RETRIES;
 
 		if (ic_dynamic() < 0) {
 			ic_close_devs();
diff -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
--- a/net/sunrpc/clnt.c	Wed May 29 11:43:02 2002
+++ b/net/sunrpc/clnt.c	Wed May 29 11:43:02 2002
@@ -461,6 +461,8 @@
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct rpc_rqst	*req = task->tk_rqstp;
+	struct xdr_buf *sndbuf = &req->rq_snd_buf;
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	unsigned int	bufsiz;
 	kxdrproc_t	encode;
 	int		status;
@@ -473,14 +475,16 @@
 
 	/* Default buffer setup */
 	bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc)+RPC_SLACK_SPACE;
-	req->rq_svec[0].iov_base = (void *)task->tk_buffer;
-	req->rq_svec[0].iov_len  = bufsiz;
-	req->rq_slen		 = 0;
-	req->rq_snr		 = 1;
-	req->rq_rvec[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz);
-	req->rq_rvec[0].iov_len  = bufsiz;
-	req->rq_rlen		 = bufsiz;
-	req->rq_rnr		 = 1;
+	sndbuf->head[0].iov_base = (void *)task->tk_buffer;
+	sndbuf->head[0].iov_len  = bufsiz;
+	sndbuf->tail[0].iov_len  = 0;
+	sndbuf->page_len	 = 0;
+	sndbuf->len		 = 0;
+	rcvbuf->head[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz);
+	rcvbuf->head[0].iov_len  = bufsiz;
+	rcvbuf->tail[0].iov_len  = 0;
+	rcvbuf->page_len	 = 0;
+	rcvbuf->len		 = bufsiz;
 
 	/* Zero buffer so we have automatic zero-padding of opaque & string */
 	memset(task->tk_buffer, 0, bufsiz);
diff -Nru a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
--- a/net/sunrpc/sunrpc_syms.c	Wed May 29 11:43:03 2002
+++ b/net/sunrpc/sunrpc_syms.c	Wed May 29 11:43:03 2002
@@ -96,8 +96,9 @@
 EXPORT_SYMBOL(xdr_decode_string_inplace);
 EXPORT_SYMBOL(xdr_decode_netobj);
 EXPORT_SYMBOL(xdr_encode_netobj);
-EXPORT_SYMBOL(xdr_shift_iovec);
-EXPORT_SYMBOL(xdr_zero_iovec);
+EXPORT_SYMBOL(xdr_encode_pages);
+EXPORT_SYMBOL(xdr_inline_pages);
+EXPORT_SYMBOL(xdr_shift_buf);
 
 /* Debugging symbols */
 #ifdef RPC_DEBUG
diff -Nru a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
--- a/net/sunrpc/xdr.c	Wed May 29 11:43:03 2002
+++ b/net/sunrpc/xdr.c	Wed May 29 11:43:03 2002
@@ -10,6 +10,8 @@
 #include <linux/socket.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/pagemap.h>
+#include <linux/errno.h>
 #include <linux/in.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/msg_prot.h>
@@ -99,6 +101,46 @@
 	return p + XDR_QUADLEN(len);
 }
 
+void
+xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
+		 unsigned int len)
+{
+	xdr->pages = pages;
+	xdr->page_base = base;
+	xdr->page_len = len;
+
+	if (len & 3) {
+		struct iovec *iov = xdr->tail;
+		unsigned int pad = 4 - (len & 3);
+
+		iov->iov_base = (void *) "\0\0\0";
+		iov->iov_len  = pad;
+		len += pad;
+	}
+	xdr->len += len;
+}
+
+void
+xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
+		 struct page **pages, unsigned int base, unsigned int len)
+{
+	struct iovec *head = xdr->head;
+	struct iovec *tail = xdr->tail;
+	char *buf = (char *)head->iov_base;
+	unsigned int buflen = head->iov_len;
+
+	head->iov_len  = offset;
+
+	xdr->pages = pages;
+	xdr->page_base = base;
+	xdr->page_len = len;
+
+	tail->iov_base = buf + offset;
+	tail->iov_len = buflen - offset;
+
+	xdr->len += len;
+}
+
 
 /*
  * Realign the iovec if the server missed out some reply elements
@@ -132,19 +174,152 @@
 }
 
 /*
- * Zero the last n bytes in an iovec array of 'nr' elements
+ * Map a struct xdr_buf into an iovec array.
  */
-void xdr_zero_iovec(struct iovec *iov, int nr, size_t n)
+int xdr_kmap(struct iovec *iov_base, struct xdr_buf *xdr, unsigned int base)
 {
-	struct iovec *pvec;
+	struct iovec	*iov = iov_base;
+	struct page	**ppage = xdr->pages;
+	unsigned int	len, pglen = xdr->page_len;
+
+	len = xdr->head[0].iov_len;
+	if (base < len) {
+		iov->iov_len = len - base;
+		iov->iov_base = (char *)xdr->head[0].iov_base + base;
+		iov++;
+		base = 0;
+	} else
+		base -= len;
+
+	if (pglen == 0)
+		goto map_tail;
+	if (base >= pglen) {
+		base -= pglen;
+		goto map_tail;
+	}
+	if (base || xdr->page_base) {
+		pglen -= base;
+		base  += xdr->page_base;
+		ppage += base >> PAGE_CACHE_SHIFT;
+		base &= ~PAGE_CACHE_MASK;
+	}
+	do {
+		len = PAGE_CACHE_SIZE;
+		iov->iov_base = kmap(*ppage);
+		if (base) {
+			iov->iov_base += base;
+			len -= base;
+			base = 0;
+		}
+		if (pglen < len)
+			len = pglen;
+		iov->iov_len = len;
+		iov++;
+		ppage++;
+	} while ((pglen -= len) != 0);
+map_tail:
+	if (xdr->tail[0].iov_len) {
+		iov->iov_len = xdr->tail[0].iov_len - base;
+		iov->iov_base = (char *)xdr->tail[0].iov_base + base;
+		iov++;
+	}
+	return (iov - iov_base);
+}
 
-	for (pvec = iov + nr - 1; n && nr > 0; nr--, pvec--) {
-		if (n < pvec->iov_len) {
-			memset((char *)pvec->iov_base + pvec->iov_len - n, 0, n);
-			n = 0;
+void xdr_kunmap(struct xdr_buf *xdr, unsigned int base)
+{
+	struct page	**ppage = xdr->pages;
+	unsigned int	pglen = xdr->page_len;
+
+	if (!pglen)
+		return;
+	if (base > xdr->head[0].iov_len)
+		base -= xdr->head[0].iov_len;
+	else
+		base = 0;
+
+	if (base >= pglen)
+		return;
+	if (base || xdr->page_base) {
+		pglen -= base;
+		ppage += base >> PAGE_CACHE_SHIFT;
+	}
+	for (;;) {
+		flush_dcache_page(*ppage);
+		flush_page_to_ram(*ppage);
+		kunmap(*ppage);
+		if (pglen <= PAGE_CACHE_SIZE)
+			break;
+		pglen -= PAGE_CACHE_SIZE;
+		ppage++;
+	}
+}
+
+void
+xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base,
+			  skb_reader_t *desc,
+			  skb_read_actor_t copy_actor)
+{
+	struct page	**ppage = xdr->pages;
+	unsigned int	len, pglen = xdr->page_len;
+	int		ret;
+
+	len = xdr->head[0].iov_len;
+	if (base < len) {
+		len -= base;
+		ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len);
+		if (ret != len || !desc->count)
+			return;
+		base = 0;
+	} else
+		base -= len;
+
+	if (pglen == 0)
+		goto copy_tail;
+	if (base >= pglen) {
+		base -= pglen;
+		goto copy_tail;
+	}
+	if (base || xdr->page_base) {
+		pglen -= base;
+		base  += xdr->page_base;
+		ppage += base >> PAGE_CACHE_SHIFT;
+		base &= ~PAGE_CACHE_MASK;
+	}
+	do {
+		char *kaddr;
+
+		len = PAGE_CACHE_SIZE;
+		kaddr = kmap_atomic(*ppage, KM_USER0);
+		if (base) {
+			len -= base;
+			if (pglen < len)
+				len = pglen;
+			ret = copy_actor(desc, kaddr + base, len);
+			base = 0;
 		} else {
-			memset(pvec->iov_base, 0, pvec->iov_len);
-			n -= pvec->iov_len;
+			if (pglen < len)
+				len = pglen;
+			ret = copy_actor(desc, kaddr, len);
 		}
-	}
+		kunmap_atomic(kaddr, KM_USER0);
+		if (ret != len || !desc->count)
+			return;
+		ppage++;
+	} while ((pglen -= len) != 0);
+copy_tail:
+	len = xdr->tail[0].iov_len;
+	if (len)
+		copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len);
+}
+
+void
+xdr_shift_buf(struct xdr_buf *xdr, size_t len)
+{
+	struct iovec iov[MAX_IOVEC];
+	unsigned int nr;
+
+	nr = xdr_kmap(iov, xdr, 0);
+	xdr_shift_iovec(iov, nr, len);
+	xdr_kunmap(xdr, 0);
 }
diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
--- a/net/sunrpc/xprt.c	Wed May 29 11:43:01 2002
+++ b/net/sunrpc/xprt.c	Wed May 29 11:43:01 2002
@@ -131,41 +131,6 @@
 }
 
 /*
- *	Adjust the iovec to move on 'n' bytes
- */
- 
-extern inline void
-xprt_move_iov(struct msghdr *msg, struct iovec *niv, unsigned amount)
-{
-	struct iovec *iv=msg->msg_iov;
-	int i;
-	
-	/*
-	 *	Eat any sent iovecs
-	 */
-	while (iv->iov_len <= amount) {
-		amount -= iv->iov_len;
-		iv++;
-		msg->msg_iovlen--;
-	}
-
-	/*
-	 *	And chew down the partial one
-	 */
-	niv[0].iov_len = iv->iov_len-amount;
-	niv[0].iov_base =((unsigned char *)iv->iov_base)+amount;
-	iv++;
-
-	/*
-	 *	And copy any others
-	 */
-	for(i = 1; i < msg->msg_iovlen; i++)
-		niv[i]=*iv++;
-
-	msg->msg_iov=niv;
-}
-
-/*
  * Serialize write access to sockets, in order to prevent different
  * requests from interfering with each other.
  * Also prevents TCP socket reconnections from colliding with writes.
@@ -211,13 +176,11 @@
 {
 	struct socket	*sock = xprt->sock;
 	struct msghdr	msg;
+	struct xdr_buf	*xdr = &req->rq_snd_buf;
+	struct iovec	niv[MAX_IOVEC];
+	unsigned int	niov, slen, skip;
 	mm_segment_t	oldfs;
 	int		result;
-	int		slen = req->rq_slen - req->rq_bytes_sent;
-	struct iovec	niv[MAX_IOVEC];
-
-	if (slen <= 0)
-		return 0;
 
 	if (!sock)
 		return -ENOTCONN;
@@ -226,22 +189,25 @@
 				req->rq_svec->iov_base,
 				req->rq_svec->iov_len);
 
+	/* Dont repeat bytes */
+	skip = req->rq_bytes_sent;
+	slen = xdr->len - skip;
+	niov = xdr_kmap(niv, xdr, skip);
+
 	msg.msg_flags   = MSG_DONTWAIT|MSG_NOSIGNAL;
-	msg.msg_iov	= req->rq_svec;
-	msg.msg_iovlen	= req->rq_snr;
+	msg.msg_iov	= niv;
+	msg.msg_iovlen	= niov;
 	msg.msg_name	= (struct sockaddr *) &xprt->addr;
 	msg.msg_namelen = sizeof(xprt->addr);
 	msg.msg_control = NULL;
 	msg.msg_controllen = 0;
 
-	/* Dont repeat bytes */
-	if (req->rq_bytes_sent)
-		xprt_move_iov(&msg, niv, req->rq_bytes_sent);
-
 	oldfs = get_fs(); set_fs(get_ds());
 	result = sock_sendmsg(sock, &msg, slen);
 	set_fs(oldfs);
 
+	xdr_kunmap(xdr, skip);
+
 	dprintk("RPC:      xprt_sendmsg(%d) = %d\n", slen, result);
 
 	if (result >= 0)
@@ -556,58 +522,60 @@
 	return;
 }
 
+static size_t
+skb_read_bits(skb_reader_t *desc, void *to, size_t len)
+{
+	if (len > desc->count)
+		len = desc->count;
+	skb_copy_bits(desc->skb, desc->offset, to, len);
+	desc->count -= len;
+	desc->offset += len;
+	return len;
+}
+
+static size_t
+skb_read_and_csum_bits(skb_reader_t *desc, void *to, size_t len)
+{
+	unsigned int csum2, pos;
+
+	if (len > desc->count)
+		len = desc->count;
+	pos = desc->offset;
+	csum2 = skb_copy_and_csum_bits(desc->skb, pos, to, len, 0);
+	desc->csum = csum_block_add(desc->csum, csum2, pos);
+	desc->count -= len;
+	desc->offset += len;
+	return len;
+}
+
 /*
  * We have set things up such that we perform the checksum of the UDP
  * packet in parallel with the copies into the RPC client iovec.  -DaveM
  */
-static int csum_partial_copy_to_page_cache(struct iovec *iov,
-					   struct sk_buff *skb,
-					   int copied)
-{
-	int offset = sizeof(struct udphdr);
-	__u8 *cur_ptr = iov->iov_base;
-	__kernel_size_t cur_len = iov->iov_len;
-	unsigned int csum = skb->csum;
-	int need_csum = (skb->ip_summed != CHECKSUM_UNNECESSARY);
-	int slack = skb->len - copied - sizeof(struct udphdr);
-
-	if (need_csum)
-		csum = csum_partial(skb->data, sizeof(struct udphdr), csum);
-	while (copied > 0) {
-		if (cur_len) {
-			int to_move = cur_len;
-			if (to_move > copied)
-				to_move = copied;
-			if (need_csum) {
-				unsigned int csum2;
-
-				csum2 = skb_copy_and_csum_bits(skb, offset,
-							       cur_ptr,
-							       to_move, 0);
-				csum = csum_block_add(csum, csum2, offset);
-			} else
-				skb_copy_bits(skb, offset, cur_ptr, to_move);
-			offset += to_move;
-			copied -= to_move;
-			cur_ptr += to_move;
-			cur_len -= to_move;
-		}
-		if (cur_len <= 0) {
-			iov++;
-			cur_len = iov->iov_len;
-			cur_ptr = iov->iov_base;
-		}
-	}
-	if (need_csum) {
-		if (slack > 0) {
-			unsigned int csum2;
+static int
+csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
+{
+	skb_reader_t desc;
 
-			csum2 = skb_checksum(skb, offset, slack, 0);
-			csum = csum_block_add(csum, csum2, offset);
-		}
-		if ((unsigned short)csum_fold(csum))
-			return -1;
+	desc.skb = skb;
+	desc.offset = sizeof(struct udphdr);
+	desc.count = skb->len - desc.offset;
+
+	if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+		goto no_checksum;
+
+	desc.csum = csum_partial(skb->data, desc.offset, skb->csum);
+	xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits);
+	if (desc.offset != skb->len) {
+		unsigned int csum2;
+		csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0);
+		desc.csum = csum_block_add(desc.csum, csum2, desc.offset);
 	}
+	if ((unsigned short)csum_fold(desc.csum))
+		return -1;
+	return 0;
+no_checksum:
+	xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits);
 	return 0;
 }
 
@@ -658,7 +626,7 @@
 		copied = repsize;
 
 	/* Suck it into the iovec, verify checksum if not done by hw. */
-	if (csum_partial_copy_to_page_cache(rovr->rq_rvec, skb, copied))
+	if (csum_partial_copy_to_xdr(&rovr->rq_rcv_buf, skb))
 		goto out_unlock;
 
 	/* Something worked... */
@@ -676,12 +644,6 @@
 		wake_up_interruptible(sk->sleep);
 }
 
-typedef struct {
-	struct sk_buff *skb;
-	unsigned offset;
-	size_t count;
-} skb_reader_t;
-
 /*
  * Copy from an skb into memory and shrink the skb.
  */
@@ -772,11 +734,8 @@
 tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc)
 {
 	struct rpc_rqst *req;
-	struct iovec *iov;
-	char *p;
-	unsigned long skip;
-	size_t len, used;
-	int n;
+	struct xdr_buf *rcvbuf;
+	size_t len;
 
 	/* Find and lock the request corresponding to this xid */
 	req = xprt_lookup_rqst(xprt, xprt->tcp_xid);
@@ -786,36 +745,30 @@
 				xprt->tcp_xid);
 		return;
 	}
-	skip = xprt->tcp_copied;
-	iov = req->rq_rvec;
-	for (n = req->rq_rnr; n != 0; n--, iov++) {
-		if (skip >= iov->iov_len) {
-			skip -= iov->iov_len;
-			continue;
-		}
-		p = iov->iov_base;
-		len = iov->iov_len;
-		if (skip) {
-			p += skip;
-			len -= skip;
-			skip = 0;
-		}
-		if (xprt->tcp_offset + len > xprt->tcp_reclen)
-			len = xprt->tcp_reclen - xprt->tcp_offset;
-		used = tcp_copy_data(desc, p, len);
-		xprt->tcp_copied += used;
-		xprt->tcp_offset += used;
-		if (used != len)
-			break;
-		if (xprt->tcp_copied == req->rq_rlen) {
+
+	rcvbuf = &req->rq_rcv_buf;
+	len = desc->count;
+	if (len > xprt->tcp_reclen - xprt->tcp_offset) {
+		skb_reader_t my_desc;
+
+		len = xprt->tcp_reclen - xprt->tcp_offset;
+		memcpy(&my_desc, desc, sizeof(my_desc));
+		my_desc.count = len;
+		xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,
+					  &my_desc, tcp_copy_data);
+		desc->count -= len;
+		desc->offset += len;
+	} else
+		xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,
+					  desc, tcp_copy_data);
+	xprt->tcp_copied += len;
+	xprt->tcp_offset += len;
+
+	if (xprt->tcp_copied == req->rq_rlen)
+		xprt->tcp_flags &= ~XPRT_COPY_DATA;
+	else if (xprt->tcp_offset == xprt->tcp_reclen) {
+		if (xprt->tcp_flags & XPRT_LAST_FRAG)
 			xprt->tcp_flags &= ~XPRT_COPY_DATA;
-			break;
-		}
-		if (xprt->tcp_offset == xprt->tcp_reclen) {
-			if (xprt->tcp_flags & XPRT_LAST_FRAG)
-				xprt->tcp_flags &= ~XPRT_COPY_DATA;
-			break;
-		}
 	}
 
 	if (!(xprt->tcp_flags & XPRT_COPY_DATA)) {
diff -Nru a/scripts/Makefile b/scripts/Makefile
--- a/scripts/Makefile	Wed May 29 11:43:03 2002
+++ b/scripts/Makefile	Wed May 29 11:43:03 2002
@@ -1,45 +1,61 @@
+
+# always needed
+# ---------------------------------------------------------------------------
+
+all: mkdep split-include
+
+mkdep: mkdep.c
+	$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
+
+split-include: split-include.c
+	$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
+
+# xconfig
+# ---------------------------------------------------------------------------
+
 HEADER=header.tk
 TAIL=tail.tk
-
 # Previous versions always remade kconfig.tk because they always depended
 # on soundscript.  This runs fairly fast, and I can't find all the
 # Config.in files to depend on anyways.  So I'll force it to remake.
 
-kconfig.tk: dummy
-
-kconfig.tk: ${TOPDIR}/Makefile ${TOPDIR}/arch/${ARCH}/config.in \
-		tkparse ${HEADER} ${TAIL}
-	@if [ -f /usr/local/bin/wish ];	then \
-		echo '#!'"/usr/local/bin/wish -f" > kconfig.tk; \
-	else \
-		echo '#!'"/usr/bin/wish -f" > kconfig.tk; \
-	fi
-	cat ${HEADER} >> ./kconfig.tk
-	./tkparse < ../arch/${ARCH}/config.in >> kconfig.tk
-	echo "set defaults \"arch/${ARCH}/defconfig\"" >> kconfig.tk
-	echo "set ARCH \"${ARCH}\"" >> kconfig.tk
-	cat ${TAIL} >> kconfig.tk
-	chmod 755 kconfig.tk
+kconfig.tk: $(TOPDIR)/arch/$(ARCH)/config.in tkparse $(HEADER) $(TAIL) FORCE
+	@echo Generating $@
+	@(                                                      \
+	  if [ -f /usr/local/bin/wish ];	then            \
+		echo '#!'"/usr/local/bin/wish -f";              \
+	  else                                                  \
+		echo '#!'"/usr/bin/wish -f";                    \
+	  fi;                                                   \
+	  cat $(HEADER);                                        \
+	  ./tkparse < $<;                                       \
+	  echo "set defaults \"arch/${ARCH}/defconfig\"";       \
+	  echo "set ARCH \"${ARCH}\"";                          \
+	  cat $(TAIL)                                           \
+	) > $@
+	chmod 755 $@
 
 tkparse: tkparse.o tkcond.o tkgen.o
-	${HOSTCC} -o tkparse tkparse.o tkcond.o tkgen.o
-
-tkparse.o: tkparse.c tkparse.h
+	$(HOSTCC) -o $@ $^
 
-tkcond.o: tkcond.c tkparse.h
+tkparse.o tkcond.o tkgen.o: %.o: %.c
+	$(HOSTCC) $(HOSTCFLAGS) -c -o $@ $<
 
-tkgen.o: tkgen.c tkparse.h
+# DocBook stuff
+# ---------------------------------------------------------------------------
 
-tkparse.o tkcond.o tkgen.o:
-	$(HOSTCC) $(HOSTCFLAGS) -c -o $@ $(@:.o=.c)
+doc-progs: docproc docgen gen-all-syms kernel-doc
 
-docproc.o: docproc.c
-	$(HOSTCC) $(HOSTCFLAGS) -c -o $@ $(@:.o=.c)
+docproc: docproc.c
+	$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
 
-docproc: docproc.o
-	${HOSTCC} -o docproc docproc.o
+docgen gen-all-syms kernel-doc: FORCE
+	chmod 755 $@
 
-clean:
-	rm -f *~ kconfig.tk *.o tkparse mkdep split-include docproc
 
 include $(TOPDIR)/Rules.make
+
+# we don't have automatic deps for host programs
+
+tkparse.o tkcond.o tkgen.o: tkparse.h
+
diff -Nru a/scripts/pathdown.sh b/scripts/pathdown.sh
--- a/scripts/pathdown.sh	Wed May 29 11:43:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-#!/bin/sh
-UP=
-DN=${PWD:?}
-TP=${TOPDIR:?}
-
-while [ ! $TP/$UP/. -ef $DN ] ;do
-	UP=`basename $PWD`/$UP
-	cd ..
-	if [ "$PWD" = "/" ]; then echo "Lost"; exit 1; fi
-done
-
-echo $UP
-exit 0
diff -Nru a/sound/core/memory.c b/sound/core/memory.c
--- a/sound/core/memory.c	Wed May 29 11:43:01 2002
+++ b/sound/core/memory.c	Wed May 29 11:43:01 2002
@@ -272,8 +272,8 @@
 	snd_assert(dma_flags != 0, return NULL);
 	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
 	if ((res = (void *) __get_free_pages(dma_flags, pg)) != NULL) {
-		mem_map_t *page = virt_to_page(res);
-		mem_map_t *last_page = page + (1 << pg);
+		struct page *page = virt_to_page(res);
+		struct page *last_page = page + (1 << pg);
 		while (page < last_page)
 			SetPageReserved(page++);
 #ifdef CONFIG_SND_DEBUG_MEMORY
@@ -302,7 +302,7 @@
 void snd_free_pages(void *ptr, unsigned long size)
 {
 	int pg;
-	mem_map_t *page, *last_page;
+	struct page *page, *last_page;
 
 	if (ptr == NULL)
 		return;
@@ -338,8 +338,8 @@
 		for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
 		dma_area = pci_alloc_consistent(NULL, size, dma_addr);
 		if (dma_area != NULL) {
-			mem_map_t *page = virt_to_page(dma_area);
-			mem_map_t *last_page = page + (1 << pg);
+			struct page *page = virt_to_page(dma_area);
+			struct page *last_page = page + (1 << pg);
 			while (page < last_page)
 				SetPageReserved(page++);
 #ifdef CONFIG_SND_DEBUG_MEMORY
@@ -391,8 +391,8 @@
 	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
 	res = pci_alloc_consistent(pci, PAGE_SIZE * (1 << pg), dma_addr);
 	if (res != NULL) {
-		mem_map_t *page = virt_to_page(res);
-		mem_map_t *last_page = page + (1 << pg);
+		struct page *page = virt_to_page(res);
+		struct page *last_page = page + (1 << pg);
 		while (page < last_page)
 			SetPageReserved(page++);
 #ifdef CONFIG_SND_DEBUG_MEMORY
@@ -426,7 +426,7 @@
 			dma_addr_t dma_addr)
 {
 	int pg;
-	mem_map_t *page, *last_page;
+	struct page *page, *last_page;
 
 	if (ptr == NULL)
 		return;
diff -Nru a/sound/oss/Makefile b/sound/oss/Makefile
--- a/sound/oss/Makefile	Wed May 29 11:43:02 2002
+++ b/sound/oss/Makefile	Wed May 29 11:43:02 2002
@@ -239,5 +239,5 @@
 	maui_boot.h pss_boot.h trix_boot.h))
 
 ifneq ($(FILES_BOOT_CHANGED),)
-$(FILES_BOOT_CHANGED): dummy
+$(FILES_BOOT_CHANGED): FORCE
 endif
diff -Nru a/sound/pci/rme9652/rme9652_mem.c b/sound/pci/rme9652/rme9652_mem.c
--- a/sound/pci/rme9652/rme9652_mem.c	Wed May 29 11:43:01 2002
+++ b/sound/pci/rme9652/rme9652_mem.c	Wed May 29 11:43:01 2002
@@ -111,8 +111,8 @@
 		*dmaaddr = virt_to_bus(res);
 #endif
 	if (res != NULL) {
-		mem_map_t *page = virt_to_page(res);
-		mem_map_t *last_page = page + (size + PAGE_SIZE - 1) / PAGE_SIZE;
+		struct page *page = virt_to_page(res);
+		struct page *last_page = page + (size + PAGE_SIZE - 1) / PAGE_SIZE;
 		while (page < last_page)
 			set_bit(PG_reserved, &(page++)->flags);
 	}
@@ -122,7 +122,7 @@
 static void rme9652_free_pages(struct pci_dev *pci, unsigned long size,
 			       void *ptr, dma_addr_t dmaaddr)
 {
-	mem_map_t *page, *last_page;
+	struct page *page, *last_page;
 
 	if (ptr == NULL)
 		return;
