diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	Thu May  2 17:22:16 2002
+++ b/CREDITS	Thu May  2 17:22:16 2002
@@ -63,10 +63,9 @@
 S: Belgium
 
 N: Anton Altaparmakov
-E: aia21@cus.cam.ac.uk
+E: aia21@cantab.net
 W: http://www-stu.christs.cam.ac.uk/~aia21/
-D: NTFS driver maintainer. NTFS fixes and cleanup.
-D: Tiny fixes in linear md device and emu10k1 driver.
+D: Author of new NTFS driver, various other kernel hacks.
 S: Christ's College
 S: Cambridge CB2 3BU
 S: United Kingdom
diff -Nru a/Documentation/BK-usage/bk-kernel-howto.txt b/Documentation/BK-usage/bk-kernel-howto.txt
--- a/Documentation/BK-usage/bk-kernel-howto.txt	Thu May  2 17:22:15 2002
+++ b/Documentation/BK-usage/bk-kernel-howto.txt	Thu May  2 17:22:15 2002
@@ -33,7 +33,7 @@
 Let's start with this progression:
 Each BitKeeper source tree on disk is a repository unto itself.
 Each repository has a parent.
-Each repository contains a set of a changsets ("csets").
+Each repository contains a set of a changesets ("csets").
 Each cset is one or more changed files, bundled together.
 
 Each tree is a repository, so all changes are checked into the local
@@ -44,7 +44,7 @@
 the BK system.
 
 After the concept of changesets, the next thing you need to get used
-to having multiple copies of source trees lying around.  This -really-
+to is having multiple copies of source trees lying around.  This -really-
 takes some getting used to, for some people.  Separate source trees
 are the means in BitKeeper by which you delineate parallel lines
 of development, both minor and major.  What would be branches in
@@ -155,7 +155,7 @@
 
 While long-term branches will parallel a tree (or trees), with period
 merge points.  In this first example, we pull from a tree (pulls,
-"\") periodically, such a what occurs when tracking changes in a
+"\") periodically, such as what occurs when tracking changes in a
 vendor tree, never pushing changes back up the line:
 
 	-------- A --------- B --------- C --------- D -------
@@ -187,7 +187,7 @@
 
 0) Make sure your tree was originally cloned from the linux-2.5 tree
 created by Linus.  If your tree does not have this as its ancestor, it
-is impossible to reliably exchanges changesets.
+is impossible to reliably exchange changesets.
 
 
 
@@ -232,7 +232,7 @@
 4) Split up your changes.  Each maintainer<->Linus situation is likely
 to be slightly different here, so take this just as general advice.  The
 author splits up changes according to "themes" when merging with Linus.
-Simultaneous pushes from local development to goes special trees which
+Simultaneous pushes from local development go to special trees which
 exist solely to house changes "queued" for Linus.  Example of the trees:
 
 	net-drivers-2.5 -- on-going net driver maintenance
diff -Nru a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
--- a/Documentation/kbuild/makefiles.txt	Thu May  2 17:22:17 2002
+++ b/Documentation/kbuild/makefiles.txt	Thu May  2 17:22:17 2002
@@ -34,8 +34,7 @@
   8  New-style variables
      8.1  New variables
      8.2  Converting to old-style
-  9  Compatibility with Linux Kernel 2.2
- 10  Credits
+  9  Credits
 
 
 === 1 Overview
@@ -466,7 +465,7 @@
 
 === 6 The structure of a subdirectory Makefile
 
-A subdirectory Makefile has five sections.
+A subdirectory Makefile has four sections.
 
 
 
@@ -488,20 +487,7 @@
 entered.  The declarations in these lines depend heavily on the kernel
 configuration variables (CONFIG_* symbols).
 
-In some Makefiles ("old-style Makefiles"), the second section looks
-like this:
-
-	# drivers/parport/Makefile
-	ifeq ($(CONFIG_PARPORT_PC),y)
-	  LX_OBJS += parport_pc.o
-	else
-	  ifeq ($(CONFIG_PARPORT_PC),m)
-	    MX_OBJS += parport_pc.o
-	  endif
-	endif
-
-In most Makefiles ("new-style Makefiles"), the second section looks
-like this:
+The second section looks like this:
 
 	# drivers/block/Makefile
 	obj-$(CONFIG_MAC_FLOPPY)	+= swim3.o
@@ -509,27 +495,10 @@
 	obj-$(CONFIG_AMIGA_FLOPPY)	+= amiflop.o
 	obj-$(CONFIG_ATARI_FLOPPY)	+= ataflop.o
 
-The new-style Makefiles are more compact and easier to get correct
-for certain features (such as CONFIG_* options that enable more than
-one file).  If you have a choice, please write a new-style Makefile.
-
-
-
---- 6.3 Adapter section
-
-The third section is an adapter section.  In old-style Makefiles, this
-third section is not present.  In new-style Makefiles, the third section
-contains boilerplate code which converts from new-style variables to
-old-style variables.  This is because Rules.make processes only the
-old-style variables.
-
-See section 8.2 ("Converting to old-style") for examples.
-
-
 
 --- 6.4 Rules.make section
 
-The fourth section is the single line:
+The third section is the single line:
 
 	include $(TOPDIR)/Rules.make
 
@@ -537,7 +506,7 @@
 
 --- 6.5 Special rules
 
-The fifth section contains any special Makefile rules needed that are
+The fourth section contains any special Makefile rules needed that are
 not available through the common rules in Rules.make.
 
 
@@ -550,352 +519,166 @@
 
 --- 7.1 Subdirectories
 
-    ALL_SUB_DIRS, SUB_DIRS, MOD_IN_SUB_DIRS, MOD_SUB_DIRS
+A Makefile is only responsible for building objects in its own
+directory. Files in subdirectories should be taken care of by
+Makefiles in the these subdirs. The build system will automatically
+invoke make recursively in subdirectories, provided you let it know of
+them.
 
-	$(ALL_SUB_DIRS) is an unconditional list of *all* the
-	subdirectories in a given directory.  This list should not depend
-	on the kernel configuration.
-
-	$(SUB_DIRS) is a list of subdirectories which may contribute code
-	to vmlinux.  This list may depend on the kernel configuration.
-
-	$(MOD_SUB_DIRS) and $(MOD_IN_SUB_DIRS) are lists of subdirectories
-	which may build kernel modules.  Both names have exactly the
-	same meaning.  (In version 2.2 and earlier kernels, these
-	variables had different meanings -- hence the different names).
+To do so, use the subdir-{y,m,n,} variables:
 
-	For new code, $(MOD_SUB_DIRS) is recommended and $(MOD_IN_SUB_DIRS)
-	is deprecated.
+	subdir-$(CONFIG_ISDN)                   += i4l
+	subdir-$(CONFIG_ISDN_CAPI)              += capi
 
-	Example:
+When building the actual kernel, i.e. vmlinux ("make
+{vmlinux,bzImage,...}"), make will recursively descend into
+directories listed in $(subdir-y).
 
-		# fs/Makefile
-		ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs \
-			       umsdos ntfs hpfs sysv smbfs ncpfs ufs efs affs \
-			       romfs autofs hfs lockd nfsd nls devpts devfs \
-			       adfs partitions qnx4 udf bfs cramfs openpromfs \
-			       autofs4 ramfs jffs
-		SUB_DIRS :=
+When building modules ("make modules"), make will recursively descend
+into directories listed in $(subdir-m).
 
-		...
+When building the dependencies ("make dep") make needs to visit every
+subdir, so it'll descend into every directory listed in 
+$(subdir-y), $(subdir-m), $(subdir-n), $(subdir-).
 
-		ifeq ($(CONFIG_EXT2_FS),y)
-		SUB_DIRS += ext2
-		else
-		  ifeq ($(CONFIG_EXT2_FS),m)
-		  MOD_SUB_DIRS += ext2
-		  endif
-		endif
+You may encounter the case where a config option may be set to "y", but
+you still want to possibly build modules in that subdirectory.
 
-		ifeq ($(CONFIG_CRAMFS),y)
-		SUB_DIRS += cramfs
-		else
-		  ifeq ($(CONFIG_CRAMFS),m)
-		  MOD_SUB_DIRS += cramfs
-		  endif
-		endif
-
-	Example:
+For example, drivers/isdn/capi/Makefile has
 
-		# drivers/net/Makefile
-		SUB_DIRS     := 
-		MOD_SUB_DIRS :=
-		MOD_IN_SUB_DIRS :=
-		ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring \
-				wan sk98lin arcnet skfp tulip appletalk
+	obj-$(CONFIG_ISDN_CAPI)                 += kernelcapi.o capiutil.o
+	obj-$(CONFIG_ISDN_CAPI_CAPI20)          += capi.o
 
-		...
+where it's possible that CONFIG_ISDN_CAPI=y, but
+CONFIG_ISDN_CAPI_CAPI20=m.
 
-		ifeq ($(CONFIG_IRDA),y)
-		SUB_DIRS += irda
-		MOD_IN_SUB_DIRS += irda
-		else
-		  ifeq ($(CONFIG_IRDA),m)
-		  MOD_IN_SUB_DIRS += irda
-		  endif
-		endif
+This is expressed by the following construct in the parent Makefile
+drivers/isdn/Makefile:
 
-		ifeq ($(CONFIG_TR),y)
-		SUB_DIRS += tokenring
-		MOD_IN_SUB_DIRS += tokenring
-		else
-		  ifeq ($(CONFIG_TR),m)
-		  MOD_IN_SUB_DIRS += tokenring
-		  endif
-		endif
+	mod-subdirs                             := i4l hisax capi eicon
+	subdir-$(CONFIG_ISDN_CAPI)              += capi
 
+Having a subdir ("capi") listed in the variable $(mod-subdirs) will
+make the build system enter the specified subdirectory during "make
+modules" also, even though the subdir ("capi") is listed only in
+$(subdir-y), not $(subdir-m).
 
 
 --- 7.2 Object file goals
 
-    O_TARGET, O_OBJS, OX_OBJS
+    O_TARGET, obj-y
 
-	The subdirectory Makefile specifies object files for vmlinux in
-	the lists $(O_OBJS) and $(OX_OBJS).  These lists depend on the
-	kernel configuration.
-
-	The "X" in "OX_OBJS" stands for "eXport".  Files in $(OX_OBJS)
-	may use the EXPORT_SYMBOL macro to define public symbols which
-	loadable kernel modules can see.  Files in $(O_OBJS) may not use
-	EXPORT_SYMBOL (and you will get a funky error message if you try).
-
-	[Yes, it's kludgy to do this by hand.  Yes, you can define all
-	your objects as $(OX_OBJS) whether they define symbols or not;
-	but then you will notice a lot of extra compiles when you edit
-	any source file.  Blame CONFIG_MODVERSIONS for this.]
-
-	Data that is passed to other objects via registration functions
-	(e.g. pci_register_driver, pm_register) does not need to be marked
-	as EXPORT_SYMBOL.  The objects that pass data via registration
-	functions do not need to be marked as OX_OBJS, unless they also have
-	exported symbols.
-
-	Rules.make compiles all the $(O_OBJS) and $(OX_OBJS) files.
-	It then calls "$(LD) -r" to merge these files into one .o file
-	with the name $(O_TARGET).  This $(O_TARGET) name also appears
-	in the top Makefile.
-
-	The order of files in $(O_OBJS) and $(OX_OBJS) is significant.
-	All $(OX_OBJS) files come first, in the order listed, followed by
-	all $(O_OBJS) files, in the order listed.  Duplicates in the lists
-	are allowed: the first instance will be linked into $(O_TARGET)
-	and succeeding instances will be ignored.  (Note: Rules.make may
-	emit warning messages for duplicates, but this is harmless).
+	The subdirectory Makefile specifies object files for vmlinux
+	in the lists $(obj-y).  These lists depend on the kernel
+	configuration.
 
-	Example:
+	Rules.make compiles all the $(obj-y) files.  It then calls
+	"$(LD) -r" to merge these files into one .o file with the name
+	$(O_TARGET).  This $(O_TARGET) is later linked into vmlinux by 
+	a parent Makefile.
 
-		# arch/alpha/kernel/Makefile
-		O_TARGET := kernel.o
-		O_OBJS   := entry.o traps.o process.o osf_sys.o irq.o \
-			    irq_alpha.o signal.o setup.o ptrace.o time.o \
-			    semaphore.o
-		OX_OBJS  := alpha_ksyms.o
+	The order of files in $(obj-y) is significant.  Duplicates in
+	the lists are allowed: the first instance will be linked into
+	$(O_TARGET) and succeeding instances will be ignored.
 
-		ifdef CONFIG_SMP
-		O_OBJS   += smp.o irq_smp.o
-		endif
+	Link order is significant, because certain functions
+	(module_init() / __initcall) will be called during boot in the
+	order they appear. So keep in mind that changing the link
+	order may e.g.  change the order in which your SCSI
+	controllers are detected, and thus you disks are renumbered.
 
-		ifdef CONFIG_PCI
-		O_OBJS   += pci.o pci_iommu.o
-		endif
-
-	Even if a subdirectory Makefile has an $(O_TARGET), the .config
-	options still control whether or not its $(O_TARGET) goes into
-	vmlinux.  See the $(M_OBJS) example below.
-
-	Sometimes the ordering of all $(OX_OBJS) files before all
-	$(O_OBJS) files can be a problem, particularly if both
-	$(O_OBJS) files and $(OX_OBJS) files contain __initcall
-	declarations where order is important.   To avoid this imposed
-	ordering, the use of $(OX_OBJS) can be dropped altogether and
-	$(MIX_OBJS) used instead.
-
-	If this approach is used, then:
-	 - All objects to be linked into vmlinux should be listed in
-	   $(O_OBJS) in the desired order.
-	 - All objects to be created as modules should be listed in
-	   $(M_OBJS)
-	 - All objects that export symbols should also be listed in
-	   $(MIX_OBJS).
-
-	This has the same effect as maintaining the
-	exported/non-exported split, except that there is more control
-	over the ordering of object files in vmlinux.
-	
+	Example:
 
+	    # Makefile for the kernel ISDN subsystem and device drivers.
 
---- 7.3 Library file goals
+	    # The target object and module list name.
 
-    L_TARGET, L_OBJS, LX_OBJS
+	    O_TARGET        := vmlinux-obj.o
 
-	These names are similar to the O_* names.  Once again, $(L_OBJS)
-	and $(LX_OBJS) specify object files for the resident kernel;
-	once again, the lists depend on the current configuration; and
-	once again, the files that call EXPORT_SYMBOL go on the "X" list.
-
-	The difference is that "L" stands for "Library".  After making
-	$(L_OBJS) and $(LX_OBJS), Rules.make uses the "$(AR) rcs" command
-	to put these files into an archive file (a library) with the
-	name $(L_TARGET).  This name also appears in the top Makefile.
+	    # Each configuration option enables a list of files.
 
-	Example:
+	    obj-$(CONFIG_ISDN)                      += isdn.o
+	    obj-$(CONFIG_ISDN_PPP_BSDCOMP)          += isdn_bsdcomp.o
 
-		# arch/i386/lib/Makefile
-		L_TARGET = lib.a
-		L_OBJS  = checksum.o old-checksum.o delay.o \
-			usercopy.o getuser.o putuser.o iodebug.o
+	    # The global Rules.make.
 
-		ifdef CONFIG_X86_USE_3DNOW
-		L_OBJS += mmx.o
-		endif
+	    include $(TOPDIR)/Rules.make
 
-		ifdef CONFIG_HAVE_DEC_LOCK
-		L_OBJS += dec_and_lock.o
-		endif
+--- 7.3 Library file goals
 
-	The order of files in $(L_OBJS) and $(LX_OBJS) is not significant.
-	Duplicates in the lists are allowed.  (Note: Rules.make may emit
-	warning messages for duplicates, but this is harmless).
-
-	A subdirectory Makefile can specify either an $(O_TARGET),
-	an $(L_TARGET), or both.  Here is a discussion of the differences.
-
-	All of the files in an $(O_TARGET) are guaranteed to appear in
-	the resident vmlinux image.  In an $(L_TARGET), only the files
-	that satisfy undefined symbol references from other files will
-	appear in vmlinux.
-
-	In a conventional link process, the linker processes some
-	object files and creates a list of unresolved external symbols.
-	The linker then looks in a set of libraries to resolve these
-	symbols.  Indeed, the Linux kernel used to be linked this way,
-	with the bulk of the code stored in libraries.
-
-	But vmlinux contains two types of object files that cannot be
-	fetched out of libraries this way:
-
-	    (1) object files that are purely EXPORT_SYMBOL definitions
-	    (2) object files that use module_init or __initcall initializers
-		(instead of an initialization routine called externally)
-
-	These files contain autonomous initializer sections which provide
-	code and data without being explicitly called.	If these files
-	were stored in $(L_TARGET) libraries, the linker would fail
-	to include them in vmlinux.  Thus, most subdirectory Makefiles
-	specify an $(O_TARGET) and do not use $(L_TARGET).
-
-	Other considerations: $(O_TARGET) leads to faster re-link times
-	during development activity, but $(L_TARGET) gives better error
-	messages for unresolved symbols.
+    L_TARGET
 
+        Instead of building an O_TARGET object file, you may also
+	build an archive which again contains objects listed in
+	$(obj-y). This is normally not necessary and only used in
+	the lib, arch/$(ARCH)/lib directories.
 
 
 --- 7.4 Loadable module goals
 
-    M_OBJS, MX_OBJS
+    obj-m
 
-	$(M_OBJS) and $(MX_OBJS) specify object files which are built
-	as loadable kernel modules.  As usual, the "X" in $(MX_OBJS)
-	stands for "eXport"; source files that use EXPORT_SYMBOL must
-	appear on an $(MX_OBJS) list.
+	$(obj-m) specify object files which are built as loadable
+	kernel modules.
 
 	A module may be built from one source file or several source
-	files.	In the case of one source file, the subdirectory
-	Makefile simply adds the file to either $(M_OBJS) or $(MX_OBJS),
-	as appropriate.
+	files. In the case of one source file, the subdirectory
+	Makefile simply adds the file to $(obj-m)
 
 	Example:
 
-		# drivers/net/irda/Makefile
-		ifeq ($(CONFIG_IRTTY_SIR),y)
-		L_OBJS += irtty.o
-		else
-		  ifeq ($(CONFIG_IRTTY_SIR),m)
-		  M_OBJS += irtty.o
-		  endif
-		endif
+	    obj-$(CONFIG_ISDN_PPP_BSDCOMP)          += isdn_bsdcomp.o
 
-		ifeq ($(CONFIG_IRPORT_SIR),y)
-		LX_OBJS += irport.o
-		else
-		  ifeq ($(CONFIG_IRPORT_SIR),m)
-		  MX_OBJS += irport.o
-		  endif
-		endif
+	If a kernel module is built from several source files, you specify
+	that you want to build a module in the same way as above.
 
-	If a kernel module is built from several source files, there
-	are two ways to specify the set of source files.  One way is to
-	build a single module for the entire subdirectory.  This way is
-	popular in the file system and network protocol stacks.
+	However, the build system of course needs to know which the parts
+	are that you want to build your module of, so you have to tell it
+	by setting an $(<module_name>-objs) variable.
 
 	Example:
 
-		# fs/ext2/Makefile
-		O_TARGET := ext2.o
-		O_OBJS   := acl.o balloc.o bitmap.o dir.o file.o fsync.o \
-			    ialloc.o inode.o ioctl.o namei.o super.o symlink.o \
-			    truncate.o
-		M_OBJS   := $(O_TARGET)
-
-	In this example, the module name will be ext2.o.  Because this
-	file has the same name has $(O_TARGET), Rules.make will use
-	the $(O_TARGET) rule to build ext2.o: it will run "$(LD) -r"
-	on the list of $(O_OBJS) files.
-
-	Note that this subdirectory Makefile defines both an $(O_TARGET)
-	and an $(M_OBJS).  The control code, up in fs/Makefile, will
-	select between these two.  If CONFIG_EXT2_FS=y, then fs/Makefile
-	will build $(O_TARGET); and if CONFIG_EXT_FS=m, then fs/Makefile
-	will build $(M_OBJS) instead.  (Yes, this is a little delicate
-	and a little confusing).
+	    obj-$(CONFIG_ISDN)                      += isdn.o
+
+	    isdn-objs := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
+
+	In this example, the module name will be isdn.o. Rules.make
+	will compile the objects listed in $(isdn-objs) and then run
+	"$(LD) -r" on the list of these files to generate isdn.o
+
+	Note: Of course, when you are building objects into the kernel,
+	the syntax above will also work. So, if you have CONFIG_ISDN=y,
+	the build system will build an isdn.o for you out of the individual
+	parts and then link this into the $(O_TARGET), as you'd expect.
+
 
+--- 7.5 Objects which export symbols
 
+    export-objs
+
+	When using loadable modules, not every global symbol in the
+	kernel / other modules is automatically available for your
+	module, only those explicitly exported are.
 
---- 7.5 Multi-part modules
-
-    MI_OBJS, MIX_OBJS
-
-	Some kernel modules are composed of several object files
-	linked together, but do not include every object file in their
-	subdirectory.  $(MI_OBJS) and $(MIX_OBJS) are for this case.
-
-	"M" stands for Module.
-	"I" stands for Intermediate.
-	"X", as usual, stands for "eXport symbol".
+	To make a symbol available for use in modules, to "export" it,
+	use the EXPORT_SYMBOL(<symbol>) directive in your source. In
+	addition, you need to list all object files which export symbols
+	(i.e. their source contains an EXPORT_SYMBOL() directive) in the
+	Makefile variable $(export-objs).
 
 	Example:
 
-		# drivers/sound/Makefile
-		gus-objs  := gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
-		pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
-		sb-objs	  := sb_card.o
-
-		gus.o: $(gus-objs)
-			$(LD) -r -o $@ $(gus-objs)
-
-		pas2.o: $(pas2-objs)
-			$(LD) -r -o $@ $(pas2-objs)
-
-		sb.o: $(sb-objs)
-			$(LD) -r -o $@ $(sb-objs)
-
-	The kernel modules gus.o, pas2.o, and sb.o are the *composite
-	files*.  The object files gus_card.o, gus_midi.o, gus_vol.o,
-	gus_wave.o, ics2101.o, pas2_card.o, pas2_midi.o, pas2_mixer.o,
-	pas2_pcm.o, and sb_card.o are *component files*.  The component
-	files are also called *intermediate files*.
-
-	In another part of drivers/sound/Makefile (not shown), all of
-	the component files are split out.  For the resident drivers:
-	the component object files go onto $(O_OBJS) and $(OX_OBJS)
-	lists, depending on whether they export symbols or not; and the
-	composite files are never built.  For the kernel modules: the
-	component object files go onto $(MI_OBJS) and $(MIX_OBJS);
-	the composite files go onto $(M_OBJS).
-
-	The subdirectory Makefile must also specify the linking rule
-	for a multi-object-file module:
-
-		# drivers/sound/Makefile
-
-		gus.o: $(gus-objs)
-			$(LD) -r -o $@ $(gus-objs)
-
-		pas2.o: $(pas2-objs)
-			$(LD) -r -o $@ $(pas2-objs)
-
-		sb.o: $(sb-objs)
-			$(LD) -r -o $@ $(sb-objs)
-
-
-	As is mentioned in section 7.2 ("Object file goals"),
-	$(MIX_OBJS) can also be used simply to list all objects that
-	export any symbols.  If this approach is taken, then
-	$(O_OBJS), $(L_OBJS), $(M_OBJS) and $(MI_OBJS) should simply
-	lists all of the vmlinux object files, library object files,
-	module object files and intermediate module files
-	respectively.  Duplication between $(MI_OBJS) and $(MIX_OBJS)
-	is not a problem.
+	    # Objects that export symbols.
+
+	    export-objs     := isdn_common.o
+
+        since isdn_common.c contains
+
+	    EXPORT_SYMBOL(register_isdn);
+
+	which makes the function register_isdn available to
+	low-level ISDN drivers.
+	    
 
 --- 7.6 Compilation flags
 
@@ -1013,6 +796,10 @@
 
 === 8 New-style variables
 
+[ This sections dates back from a time where the way to write Makefiles
+  described above was "new-style". I'm leaving it in as it describes the
+  same thing in other words, so it may be of some use ]
+
 The "new-style variables" are simpler and more powerful than the
 "old-style variables".  As a result, many subdirectory Makefiles shrank
 more than 60%.  This author hopes that, in time, all arch Makefiles and
@@ -1099,16 +886,14 @@
 	$(export-objs) list in a new-style Makefile is simpler and easier
 	to audit.
 
-    list-multi
     $(foo)-objs
 
 	Some kernel modules are composed of multiple object files linked
-	together.  $(list-multi) is a list of such kernel modules.
-	This is a static list; it does not depend on the configuration.
+	together.
 
-	For each kernel module in $(list-multi) there is another list
-	of all the object files which make up that module.  For a kernel
-	module named foo.o, its object file list is foo-objs.
+	For each multi-part kernel modul there is a list of all the
+	object files which make up that module.  For a kernel module
+	named foo.o, its object file list is foo-objs.
 
 	Example:
 
@@ -1135,44 +920,16 @@
 		obj-$(CONFIG_SCSI_INIA100)	+= a100u2w.o
 
 	Suppose that CONFIG_SCSI=y.  Then vmlinux needs to link in all
-	14 components of scsi_mod.o, so these components will go onto
-	$(O_OBJS) and $(OX_OBJS).  The composite file scsi_mod.o will
-	never be created.  The boilerplate conversion code produces this
-	result with a few lines of list processing commands.
+	14 components of scsi_mod.o.
 
 	Suppose that CONFIG_BLK_DEV_SR=m.  Then the 3 components
-	of sr_mod.o will linked together with "$(LD) -r" to make the
-	kernel module sr_mod.o, so these 3 components need to go onto
-	the $(MI_OBJS) and $(MIX_OBJS) lists; the composite file sr_mod.o
-	goes onto $(M_OBJS).  The boilerplate conversion code takes care
-	of this, too.
+	of sr_mod.o will be linked together with "$(LD) -r" to make the
+	kernel module sr_mod.o.
 
 	And suppose CONFIG_SCSI_INITIO=n.  Then initio.o goes onto the
 	$(obj-n) list and that's the end of it.  Its component files
 	are not compiled, and the composite file is not created.
 
-	Finally, the subdirectory Makefile needs to define rules to
-	build each multi-object kernel module from its component list.
-	Example:
-
-		# drivers/scsi/Makefile
-
-		scsi_mod.o: $(scsi_mod-objs)
-			$(LD) -r -o $@ $(scsi_mod-objs)
-
-		sr_mod.o: $(sr_mod-objs)
-			$(LD) -r -o $@ $(sr_mod-objs)
-
-		initio.o: $(initio-objs)
-			$(LD) -r -o $@ $(initio-objs)
-
-		a100u2w.o: $(a100u2w-objs)
-			$(LD) -r -o $@ $(a100u2w-objs)
-
-	These rules are very regular; it would be nice for the boilerplate
-	code or Rules.make to synthesize these rules automatically.
-	But until that happens, the subdirectory Makefile needs to define
-	these rules explicitly.
 
     subdir-y subdir-m subdir-n subdir-
 
@@ -1217,72 +974,7 @@
 	This means nls should be added to (subdir-y) and $(subdir-m) if
 	CONFIG_NFS = y.
 
---- 8.2 Converting to old-style
-
-	The following example is taken from drivers/usb/Makefile.
-	Note that this uses MIX_OBJS to avoid the need for OX_OBJS and
-	MX_OBJS and thus to maintain the ordering of objects in $(obj-y)
-
-		# Translate to Rules.make lists.
-		multi-used	:= $(filter $(list-multi), $(obj-y) $(obj-m))
-		multi-objs	:= $(foreach m, $(multi-used), $($(basename $(m))-objs))
-		active-objs	:= $(sort $(multi-objs) $(obj-y) $(obj-m))
-
-		O_OBJS		:= $(obj-y)
-		M_OBJS		:= $(obj-m)
-		MIX_OBJS	:= $(filter $(export-objs), $(active-objs))
-
-	An example for libraries from drivers/acorn/scsi/Makefile:
-
-		# Translate to Rules.make lists.
-
-		L_OBJS		:= $(filter-out $(export-objs), $(obj-y))
-		LX_OBJS		:= $(filter     $(export-objs), $(obj-y))
-		M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
-		MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
-
-	As ordering is not so important in libraries, this still uses
-	LX_OBJS and MX_OBJS, though (presumably) it could be changed to
-	use MIX_OBJS as follows:
-
-		active-objs	:= $(sort $(obj-y) $(obj-m))
-		L_OBJS		:= $(obj-y)
-		M_OBJS		:= $(obj-m)
-		MIX_OBJS	:= $(filter $(export-objs), $(active-objs))
-		
-
-	which is clearly shorted and arguably clearer.
-
-=== 9 Compatibility with Linux Kernel 2.2
-
-Most of the information in this document also applies to 2.2, although
-there is no indication of which things have changed when.  Here are some
-hints for writing subdirectory Makefiles that are compatible with Linux
-kernel 2.2.
-
-You can write either an old-style Makefile or a new-style Makefile
-with a boilerplate adapter section.  See the 2.2 version of
-drivers/sound/Makefile for a copy of the boilerplate code.
-
-In 2.2, Rules.make makes a distinction between $(MOD_SUB_DIRS)
-and $(MOD_IN_SUB_DIRS).  If you have a single directory with no
-subdirectories, this will not matter to you.  If you have a whole
-tree, then you need to know the difference between $(MOD_SUB_DIRS)
-and $(MOD_IN_SUB_DIRS).  For example code: $(MOD_SUB_DIRS) is used
-extensively in fs/Makefile; $(MOD_IN_SUB_DIRS) is used extensively in
-drivers/net/Makefile.
-
-If you are already using MOD_LIST_NAME, go ahead and keep using it.
-If you don't already have a MOD_LIST_NAME, go ahead and keep not using
-one; your module will be a 'misc' module in 2.2.
-
-Assembly language rules were a mess in 2.2.  If you have assembly language
-files, this author recommends that you write your own explicit rules
-for each file by name.
-
-
-
-=== 10 Credits
+=== 9 Credits
 
 Thanks to the members of the linux-kbuild mailing list for reviewing
 drafts of this document, with particular thanks to Peter Samuelson
diff -Nru a/Documentation/networking/3c509.txt b/Documentation/networking/3c509.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/networking/3c509.txt	Thu May  2 17:22:17 2002
@@ -0,0 +1,210 @@
+Linux and the 3Com EtherLink III Series Ethercards (driver v1.18c and higher)
+----------------------------------------------------------------------------
+
+This file contains the instructions and caveats for v1.18c and higher versions
+of the 3c509 driver. You should not use the driver without reading this file.
+
+release 1.0
+28 February 2002
+Current maintainer (corrections to):
+  David Ruggiero <jdr@farfalle.com>
+
+----------------------------------------------------------------------------
+
+(0) Introduction
+
+The following are notes and information on using the 3Com EtherLink III series
+ethercards in Linux. These cards are commonly known by the most widely-used
+card's 3Com model number, 3c509. They are all 10mb/s ISA-bus cards and shouldn't
+be (but sometimes are) confused with the similarly-numbered PCI-bus "3c905"
+(aka "Vortex" or "Boomerang") series.  Kernel support for the 3c509 family is
+provided by the module 3c509.c, which has code to support all of the following
+models:
+
+  3c509 (original ISA card)
+  3c509B (later revision of the ISA card; supports full-duplex)
+  3c589 (PCMCIA)
+  3c589B (later revision of the 3c589; supports full-duplex)
+  3c529 (MCA)
+  3c579 (EISA)
+
+Large portions of this documentation were heavily borrowed from the guide
+written the original author of the 3c509 driver, Donald Becker. The master
+copy of that document, which contains notes on older versions of the driver,
+currently resides on Scyld web server: http://www.scyld.com/network/3c509.html.
+
+
+(1) Special Driver Features
+
+Overriding card settings
+
+The driver allows boot- or load-time overriding of the card's detected IOADDR,
+IRQ, and transceiver settings, although this capability shouldn't generally be
+needed except to enable full-duplex mode (see below). An example of the syntax
+for LILO parameters for doing this:
+
+    ether=10,0x310,3,0x3c509,eth0 
+
+This configures the first found 3c509 card for IRQ 10, base I/O 0x310, and
+transceiver type 3 (10base2). The flag "0x3c509" must be set to avoid conflicts
+with other card types when overriding the I/O address. When the driver is
+loaded as a module, only the IRQ and transceiver setting may be overridden.
+For example, setting two cards to 10base2/IRQ10 and AUI/IRQ11 is done by using
+the xcvr and irq module options:
+
+   options 3c509 xcvr=3,3 irq=10,11
+
+
+(2) Full-duplex mode
+
+The v1.18c driver added support for the 3c509B's full-duplex capabilities.
+In order to enable and successfully use full-duplex mode, three conditions
+must be met: 
+
+(a) You must have a Etherlink III card model whose hardware supports full-
+duplex operations. Currently, the only members of the 3c509 family that are
+positively known to support full-duplex are the 3c509B (ISA bus) and 3c589B
+(PCMCIA) cards. Cards without the "B" model designation do *not* support
+full-duplex mode; these include the original 3c509 (no "B"), the original
+3c589, the 3c529 (MCA bus), and the 3c579 (EISA bus).
+
+(b) You must be using your card's 10baseT transceiver (i.e., the RJ-45
+connector), not its AUI (thick-net) or 10base2 (thin-net/coax) interfaces.
+AUI and 10base2 network cabling is physically incapable of full-duplex
+operation.
+
+(c) Most importantly, your 3c509B must be connected to a link partner that is
+itself full-duplex capable. This is almost certainly one of two things: a full-
+duplex-capable  Ethernet switch (*not* a hub), or a full-duplex-capable NIC on
+another system that's connected directly to the 3c509B via a crossover cable.
+ 
+/////Extremely important caution concerning full-duplex mode/////
+Understand that the 3c509B's hardware's full-duplex support is much more
+limited than that provide by more modern network interface cards. Although
+at the physical layer of the network it fully supports full-duplex operation,
+the card was designed before the current Ethernet auto-negotiation (N-way)
+spec was written. This means that the 3c509B family ***cannot and will not
+auto-negotiate a full-duplex connection with its link partner under any
+circumstances, no matter how it is initialized***. If the full-duplex mode
+of the 3c509B is enabled, its link partner will very likely need to be
+independently _forced_ into full-duplex mode as well; otherwise various nasty
+failures will occur - at the very least, you'll see massive numbers of packet
+collisions. This is one of very rare circumstances where disabling auto-
+negotiation and forcing the duplex mode of a network interface card or switch
+would ever be necessary or desirable.
+
+
+(3) Available Transceiver Types
+
+For versions of the driver v1.18c and above, the available transceiver types are:
+ 
+0  transceiver type from EEPROM config (normally 10baseT); force half-duplex
+1  AUI (thick-net / DB15 connector)
+2  (undefined)
+3  10base2 (thin-net == coax / BNC connector)
+4  10baseT (RJ-45 connector); force half-duplex mode
+8  transceiver type and duplex mode taken from card's EEPROM config settings
+12 10baseT (RJ-45 connector); force full-duplex mode
+
+Prior to driver version 1.18c, only tranceiver codes 0-4 were supported. Note
+that the new transceiver codes 8 and 12 are the *only* ones that will enable
+full-duplex mode, no matter what the card's detected EEPROM settings might be.
+This insured that merely upgrading the driver from an earlier version would
+never automatically enable full-duplex mode in an existing installation;
+it must always be explicitly enabled via one of these code in order to be
+activated.
+  
+
+(4a) Interpretation of error messages and common problems
+
+Error Messages
+
+eth0: Infinite loop in interrupt, status 2011. 
+These are "mostly harmless" message indicating that the driver had too much
+work during that interrupt cycle. With a status of 0x2011 you are receiving
+packets faster than they can be removed from the card. This should be rare
+or impossible in normal operation. Possible causes of this error report are:
+ 
+   - a "green" mode enabled that slows the processor down when there is no
+     keyboard activitiy. 
+
+   - some other device or device driver hogging the bus or disabling interrupts.
+     Check /proc/interrupts for excessive interrupt counts. The timer tick
+     interrupt should always be incrementing faster than the others. 
+
+No received packets 
+If a 3c509, 3c562 or 3c589 can successfully transmit packets, but never
+receives packets (as reported by /proc/net/dev or 'ifconfig') you likely
+have an interrupt line problem. Check /proc/interrupts to verify that the
+card is actually generating interrupts. If the interrupt count is not
+increasing you likely have a physical conflict with two devices trying to
+use the same ISA IRQ line. The common conflict is with a sound card on IRQ10
+or IRQ5, and the easiest solution is to move the 3c509 to a different
+interrupt line. If the device is receiving packets but 'ping' doesn't work,
+you have a routing problem.
+
+Tx Carrier Errors Reported in /proc/net/dev 
+If an EtherLink III appears to transmit packets, but the "Tx carrier errors"
+field in /proc/net/dev increments as quickly as the Tx packet count, you
+likely have an unterminated network or the incorrect media tranceiver selected. 
+
+3c509B card is not detected on machines with an ISA PnP BIOS. 
+While the updated driver works with most PnP BIOS programs, it does not work
+with all. This can be fixed by disabling PnP support using the 3Com-supplied
+setup program. 
+
+3c509 card is not detected on overclocked machines 
+Increase the delay time in id_read_eeprom() from the current value, 500,
+to an absurdly high value, such as 5000. 
+
+
+(4b) Decoding Status and Error Messages
+
+The bits in the main status register are: 
+
+value 	description
+0x01 	Interrupt latch
+0x02 	Tx overrun, or Rx underrun
+0x04 	Tx complete
+0x08 	Tx FIFO room available
+0x10 	A complete Rx packet has arrived
+0x20 	A Rx packet has started to arrive
+0x40 	The driver has requested an interrupt
+0x80 	Statistics counter nearly full
+
+The bits in the transmit (Tx) status word are: 
+
+value 	description
+0x02 	Out-of-window collision.
+0x04 	Status stack overflow (normally impossible).
+0x08 	16 collisions.
+0x10 	Tx underrun (not enough PCI bus bandwidth).
+0x20 	Tx jabber.
+0x40 	Tx interrupt requested.
+0x80 	Status is valid (this should always be set).
+
+
+When a transmit error occurs the driver produces a status message such as 
+
+   eth0: Transmit error, Tx status register 82
+
+The two values typically seen here are:
+
+0x82 
+Out of window collision. This typically occurs when some other Ethernet
+host is incorrectly set to full duplex on a half duplex network. 
+
+0x88 
+16 collisions. This typically occurs when the network is exceptionally busy
+or when another host doesn't correctly back off after a collision. If this
+error is mixed with 0x82 errors it is the result of a host incorrectly set
+to full duplex (see above).
+
+Both of these errors are the result of network problems that should be
+corrected. They do not represent driver malfunction.
+
+
+(5) Revision history (this file)
+
+28Feb02 v1.0  DR   New; major portions based on Becker original 3c509 docs
+
diff -Nru a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
--- a/Documentation/networking/bonding.txt	Thu May  2 17:22:16 2002
+++ b/Documentation/networking/bonding.txt	Thu May  2 17:22:16 2002
@@ -271,7 +271,7 @@
 	
 	If you wish to change the MAC address, you can set it with ifconfig:
 
-	  # ifconfig bond0 ha ether 00:11:22:33:44:55
+	  # ifconfig bond0 hw ether 00:11:22:33:44:55
 
 	The MAC address can be also changed by bringing down/up the device
 	and then changing its slaves (or their order):
diff -Nru a/Documentation/networking/ifenslave.c b/Documentation/networking/ifenslave.c
--- a/Documentation/networking/ifenslave.c	Thu May  2 17:22:16 2002
+++ b/Documentation/networking/ifenslave.c	Thu May  2 17:22:16 2002
@@ -38,6 +38,9 @@
  *         take care of this itself
  *       - Try the SIOC*** versions of the bonding ioctls before using the
  *         old versions
+ *    - 2002/02/18 Erik Habbinga <erik_habbinga @ hp dot com> :
+ *       - ifr2.ifr_flags was not initialized in the hwaddr_notset case,
+ *         SIOCGIFFLAGS now called before hwaddr_notset test
  */
 
 static char *version =
@@ -288,19 +291,19 @@
 			     hwaddr from it's first slave.
 			   - if !hwaddr_notset, assign the master's hwaddr to each slave
 			*/
-	
+
+			strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ);
+			if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) {
+				int saved_errno = errno;
+				fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname,
+						strerror(saved_errno));
+				return 1;
+			}
+
 			if (hwaddr_notset) { /* we do nothing */
 
 			}
 			else {  /* we'll assign master's hwaddr to this slave */
-				strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ);
-				if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) {
-					int saved_errno = errno;
-					fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname,
-							strerror(saved_errno));
-					return 1;
-				}
-	
 				if (ifr2.ifr_flags & IFF_UP) {
 					ifr2.ifr_flags &= ~IFF_UP;
 					if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) {
diff -Nru a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
--- a/Documentation/usb/usb-serial.txt	Thu May  2 17:22:16 2002
+++ b/Documentation/usb/usb-serial.txt	Thu May  2 17:22:16 2002
@@ -95,10 +95,10 @@
   Kroah-Hartman at greg@kroah.com
 
 
-Compaq iPAQ and HP Jornada driver
+Compaq iPAQ, HP Jornada and Casio EM500 driver
 
-  This driver can be used to connect to Compaq iPAQ and HP Jornada PDAs
-  running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. It
+  This driver can be used to connect to Compaq iPAQ, HP Jornada and Casio EM500
+  PDAs running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. It
   has been tested only on the Compaq H3135, but is rumoured to work on
   with the H3600 and later models as well as the Jornada 548 and 568.
   With minor modifications, it may work for other CE based handhelds too.
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Thu May  2 17:22:15 2002
+++ b/MAINTAINERS	Thu May  2 17:22:15 2002
@@ -1146,9 +1146,10 @@
 
 NTFS FILESYSTEM
 P:	Anton Altaparmakov
-M:	aia21@cus.cam.ac.uk
+M:	aia21@cantab.net
 L:	linux-ntfs-dev@lists.sourceforge.net
 L:	linux-kernel@vger.kernel.org
+W:	http://linux-ntfs.sf.net/
 S:	Maintained
 
 NVIDIA (RIVA) FRAMEBUFFER DRIVER
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Thu May  2 17:22:16 2002
+++ b/Makefile	Thu May  2 17:22:16 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 12
+SUBLEVEL = 13
 EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -141,7 +141,7 @@
 DRIVERS-$(CONFIG_DRM) += drivers/char/drm/drm.o
 DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a
 DRIVERS-$(CONFIG_NET_FC) += drivers/net/fc/fc.o
-DRIVERS-$(CONFIG_APPLETALK) += drivers/net/appletalk/appletalk.o
+DRIVERS-$(CONFIG_DEV_APPLETALK) += drivers/net/appletalk/appletalk.o
 DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.o
 DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.o
 DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnetdrv.o
diff -Nru a/Rules.make b/Rules.make
--- a/Rules.make	Thu May  2 17:22:16 2002
+++ b/Rules.make	Thu May  2 17:22:16 2002
@@ -191,21 +191,19 @@
 MOD_DESTDIR := $(shell $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh)
 endif
 
-unexport MOD_DIRS
-MOD_DIRS := $(MOD_SUB_DIRS) $(MOD_IN_SUB_DIRS)
-ifneq "$(strip $(MOD_DIRS))" ""
-.PHONY: $(patsubst %,_modsubdir_%,$(MOD_DIRS))
-$(patsubst %,_modsubdir_%,$(MOD_DIRS)) : dummy
+ifneq "$(strip $(MOD_SUB_DIRS))" ""
+.PHONY: $(patsubst %,_modsubdir_%,$(MOD_SUB_DIRS))
+$(patsubst %,_modsubdir_%,$(MOD_SUB_DIRS)) : dummy
 	$(MAKE) -C $(patsubst _modsubdir_%,%,$@) modules
 
-.PHONY: $(patsubst %,_modinst_%,$(MOD_DIRS))
-$(patsubst %,_modinst_%,$(MOD_DIRS)) : dummy
+.PHONY: $(patsubst %,_modinst_%,$(MOD_SUB_DIRS))
+$(patsubst %,_modinst_%,$(MOD_SUB_DIRS)) : dummy
 	$(MAKE) -C $(patsubst _modinst_%,%,$@) modules_install
 endif
 
 .PHONY: modules
 modules: $(obj-m) dummy \
-	 $(patsubst %,_modsubdir_%,$(MOD_DIRS))
+	 $(patsubst %,_modsubdir_%,$(MOD_SUB_DIRS))
 
 .PHONY: _modinst__
 _modinst__: dummy
@@ -216,7 +214,7 @@
 
 .PHONY: modules_install
 modules_install: _modinst__ \
-	 $(patsubst %,_modinst_%,$(MOD_DIRS))
+	 $(patsubst %,_modinst_%,$(MOD_SUB_DIRS))
 
 #
 # A rule to do nothing
diff -Nru a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
--- a/arch/i386/kernel/microcode.c	Thu May  2 17:22:16 2002
+++ b/arch/i386/kernel/microcode.c	Thu May  2 17:22:16 2002
@@ -211,7 +211,7 @@
 	req->err = 1; /* assume update will fail on this cpu */
 
 	if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
-		test_bit(X86_FEATURE_IA64, &c->x86_capability)){
+		test_bit(X86_FEATURE_IA64, c->x86_capability)){
 		printk(KERN_ERR "microcode: CPU%d not a capable Intel processor\n", cpu_num);
 		return;
 	}
diff -Nru a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
--- a/arch/i386/kernel/msr.c	Thu May  2 17:22:16 2002
+++ b/arch/i386/kernel/msr.c	Thu May  2 17:22:16 2002
@@ -236,7 +236,7 @@
   
   if ( !(cpu_online_map & (1UL << cpu)) )
     return -ENXIO;		/* No such CPU */
-  if ( !test_bit(X86_FEATURE_MSR, &c->x86_capability) )
+  if ( !test_bit(X86_FEATURE_MSR, c->x86_capability) )
     return -EIO;		/* MSR not supported */
   
   return 0;
diff -Nru a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
--- a/arch/m68k/atari/stram.c	Thu May  2 17:22:16 2002
+++ b/arch/m68k/atari/stram.c	Thu May  2 17:22:16 2002
@@ -974,8 +974,6 @@
 /*								ST-RAM device								*/
 /* ------------------------------------------------------------------------ */
 
-static int stram_blocksizes[14] = {
-	0, 0, 0, 0, 0, 0, 0, 0,	0, 0, 0, 0, 0, 4096 };
 static int stram_sizes[14] = {
 	0, 0, 0, 0, 0, 0, 0, 0,	0, 0, 0, 0, 0, 0 };
 static int refcnt = 0;
@@ -1064,7 +1062,6 @@
     }
 
     blk_init_queue(BLK_DEFAULT_QUEUE(STRAM_MAJOR), do_stram_request);
-    blksize_size[STRAM_MAJOR] = stram_blocksizes;
 	stram_sizes[STRAM_MINOR] = (swap_end - swap_start)/1024;
     blk_size[STRAM_MAJOR] = stram_sizes;
 	register_disk(NULL, MKDEV(STRAM_MAJOR, STRAM_MINOR), 1, &stram_fops,
diff -Nru a/arch/ppc64/boot/zlib.c b/arch/ppc64/boot/zlib.c
--- a/arch/ppc64/boot/zlib.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/boot/zlib.c	Thu May  2 17:22:16 2002
@@ -671,11 +671,6 @@
 /*   load local pointers */
 #define LOAD {LOADIN LOADOUT}
 
-/*
- * The IBM 150 firmware munges the data right after _etext[].  This
- * protects it. -- Cort
- */
-local uInt protect_mask[] = {0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0};
 /* And'ing with mask[n] masks the lower n bits */
 local uInt inflate_mask[] = {
     0x0000,
diff -Nru a/arch/ppc64/config.in b/arch/ppc64/config.in
--- a/arch/ppc64/config.in	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/config.in	Thu May  2 17:22:16 2002
@@ -24,7 +24,6 @@
   bool '  Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS
   if [ "$CONFIG_PPC_PSERIES" = "y" ]; then
     bool '  Hardware multithreading' CONFIG_HMT
-    bool '  PCI Enhanced Error Handling' CONFIG_PPC_EEH
   fi
 fi
 define_bool CONFIG_PREEMPT n
diff -Nru a/arch/ppc64/kernel/ItLpQueue.c b/arch/ppc64/kernel/ItLpQueue.c
--- a/arch/ppc64/kernel/ItLpQueue.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/ItLpQueue.c	Thu May  2 17:22:16 2002
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <asm/system.h>
-#include <asm/Paca.h>
+#include <asm/paca.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvCallEvent.h>
diff -Nru a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c
--- a/arch/ppc64/kernel/LparData.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/LparData.c	Thu May  2 17:22:16 2002
@@ -14,13 +14,13 @@
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/init.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/abs_addr.h>
 #include <asm/bitops.h>
 #include <asm/iSeries/ItLpNaca.h>
 #include <asm/iSeries/ItLpPaca.h>
 #include <asm/iSeries/ItLpRegSave.h>
-#include <asm/Paca.h>
+#include <asm/paca.h>
 #include <asm/iSeries/HvReleaseData.h>
 #include <asm/iSeries/LparMap.h>
 #include <asm/iSeries/ItVpdAreas.h>
@@ -61,8 +61,8 @@
 struct HvReleaseData hvReleaseData = {
 	0xc8a5d9c4,	/* desc = "HvRD" ebcdic */
 	sizeof(struct HvReleaseData),
-	offsetof(struct Naca, xItVpdAreas),
-	(struct Naca *)(KERNELBASE+0x4000),	/* 64-bit Naca address */
+	offsetof(struct naca_struct, xItVpdAreas),
+	(struct naca_struct *)(KERNELBASE+0x4000), /* 64-bit Naca address */
 	0x6000,		/* offset of LparMap within loadarea (see head.S) */
 	0,
 	1,		/* tags inactive       */
@@ -174,7 +174,7 @@
 	0, 0,
 	26,		/* # VPD array entries */
 	10,		/* # DMA array entries */
-	maxProcessors*2, maxPhysicalProcessors,	/* Max logical, physical procs */
+	MAX_PROCESSORS*2, maxPhysicalProcessors,	/* Max logical, physical procs */
 	offsetof(struct ItVpdAreas,xPlicDmaToks),/* offset to DMA toks */
 	offsetof(struct ItVpdAreas,xSlicVpdAdrs),/* offset to VPD addrs */
 	offsetof(struct ItVpdAreas,xPlicDmaLens),/* offset to DMA lens */
@@ -186,7 +186,7 @@
 	{0},		/* DMA tokens */
 	{		/* VPD lengths */
 		0,0,0,0,		/*  0 -  3 */
-		sizeof(struct Paca),	/*       4 length of Paca  */
+		sizeof(struct paca_struct),	/*       4 length of Paca  */
 		0,			/*       5 */
 		sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */
 		26992,			/*	 7 length of MS VPD */
@@ -203,7 +203,7 @@
 		},
 	{			/* VPD addresses */
 		0,0,0,0,		/*	 0 -  3 */
-		&xPaca[0],		/*       4 first Paca */
+		&paca[0],		/*       4 first Paca */
 		0,			/*       5 */
 		&xItIplParmsReal,	/*	 6 IPL parms */
 		&xMsVpd,		/*	 7 MS Vpd */
@@ -219,10 +219,6 @@
 		0,0
 	}
 };
-
-
-/* Data area used in flush_hash_page  */
-long long flush_hash_page_hpte[2];
 
 struct msChunks msChunks = {0, 0, 0, 0, NULL};
 
diff -Nru a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
--- a/arch/ppc64/kernel/Makefile	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/Makefile	Thu May  2 17:22:17 2002
@@ -30,13 +30,12 @@
 			rtc.o init_task.o pSeries_htab.o
 
 obj-$(CONFIG_PCI) +=  pci.o pci_dn.o pci_dma.o
-obj-$(CONFIG_PPC_EEH) += eeh.o
 
 ifeq ($(CONFIG_PPC_ISERIES),y)
 obj-$(CONFIG_PCI) += iSeries_pci.o iSeries_pci_reset.o iSeries_IoMmTable.o iSeries_irq.o iSeries_VpdInfo.o XmPciLpEvent.o 
 endif
 ifeq ($(CONFIG_PPC_PSERIES),y)
-obj-$(CONFIG_PCI) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o
+obj-$(CONFIG_PCI) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o eeh.o
 
 obj-y += rtasd.o nvram.o
 endif
diff -Nru a/arch/ppc64/kernel/bitops.c b/arch/ppc64/kernel/bitops.c
--- a/arch/ppc64/kernel/bitops.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/bitops.c	Thu May  2 17:22:17 2002
@@ -6,9 +6,10 @@
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 
-unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+unsigned long find_next_zero_bit(unsigned long *addr, unsigned long size,
+				 unsigned long offset)
 {
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
+	unsigned long *p = addr + (offset >> 6);
 	unsigned long result = offset & ~63UL;
 	unsigned long tmp;
 
@@ -55,9 +56,9 @@
         return result;
 }
 
-unsigned long find_next_bit(void *addr, unsigned long size, unsigned long offset)
+unsigned long find_next_bit(unsigned long *addr, unsigned long size, unsigned long offset)
 {
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
+	unsigned long *p = addr + (offset >> 6);
 	unsigned long result = offset & ~63UL;
 	unsigned long tmp;
 
@@ -110,7 +111,7 @@
 	return tempRC;
 }
 
-unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
+unsigned long find_next_zero_le_bit(unsigned long *addr, unsigned long size, unsigned long offset)
 {
         unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
         unsigned int result = offset & ~31;
diff -Nru a/arch/ppc64/kernel/chrp_setup.c b/arch/ppc64/kernel/chrp_setup.c
--- a/arch/ppc64/kernel/chrp_setup.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/chrp_setup.c	Thu May  2 17:22:16 2002
@@ -57,7 +57,7 @@
 #include <asm/irq.h>
 #include <asm/keyboard.h>
 #include <asm/init.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/time.h>
 
 #include "local_irq.h"
@@ -67,7 +67,6 @@
 #include <asm/ppcdebug.h>
 
 extern volatile unsigned char *chrp_int_ack_special;
-extern struct Naca *naca;
 
 void chrp_setup_pci_ptrs(void);
 void chrp_progress(char *, unsigned short);
@@ -91,6 +90,9 @@
 extern void pSeries_get_rtc_time(struct rtc_time *rtc_time);
 extern int  pSeries_set_rtc_time(struct rtc_time *rtc_time);
 void pSeries_calibrate_decr(void);
+static void fwnmi_init(void);
+extern void SystemReset_FWNMI(void), MachineCheck_FWNMI(void);	/* from head.S */
+int fwnmi_active;  /* TRUE if an FWNMI handler is present */
 
 kdev_t boot_dev;
 unsigned long  virtPython0Facilities = 0;  // python0 facility area (memory mapped io) (64-bit format) VIRTUAL address.
@@ -153,6 +155,8 @@
 
 	printk("Boot arguments: %s\n", cmd_line);
 
+	fwnmi_init();
+
 	/* Find and initialize PCI host bridges */
 	/* iSeries needs to be done much later. */
  	#ifndef CONFIG_PPC_ISERIES
@@ -190,6 +194,23 @@
 	ppc_md.progress(UTS_RELEASE, 0x7777);
 }
 
+/* Initialize firmware assisted non-maskable interrupts if
+ * the firmware supports this feature.
+ *
+ */
+static void __init fwnmi_init(void)
+{
+	long ret;
+	int ibm_nmi_register = rtas_token("ibm,nmi-register");
+	if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE)
+		return;
+	ret = rtas_call(ibm_nmi_register, 2, 1, NULL,
+			__pa((unsigned long)SystemReset_FWNMI),
+			__pa((unsigned long)MachineCheck_FWNMI));
+	if (ret == 0)
+		fwnmi_active = 1;
+}
+
 
 /* Early initialization.  Relocation is on but do not reference unbolted pages */
 void __init pSeries_init_early(void)
@@ -230,7 +251,7 @@
 #endif /* CONFIG_BLK_DEV_INITRD */
 #endif
 
-	ppc_md.ppc_machine = _machine;
+	ppc_md.ppc_machine = naca->platform;
 
 	ppc_md.setup_arch     = chrp_setup_arch;
 	ppc_md.setup_residual = NULL;
@@ -238,11 +259,9 @@
 	if(naca->interrupt_controller == IC_OPEN_PIC) {
 		ppc_md.init_IRQ       = openpic_init_IRQ; 
 		ppc_md.get_irq        = openpic_get_irq;
-		ppc_md.post_irq	      = NULL;
 	} else {
 		ppc_md.init_IRQ       = xics_init_IRQ;
 		ppc_md.get_irq        = xics_get_irq;
-		ppc_md.post_irq	      = NULL;
 	}
 	ppc_md.init_ras_IRQ = init_ras_IRQ;
 
@@ -296,7 +315,7 @@
 	if (hex)
 		udbg_printf("<chrp_progress> %s\n", s);
 
-	if (!rtas.base || (_machine != _MACH_pSeries))
+	if (!rtas.base || (naca->platform != PLATFORM_PSERIES))
 		return;
 
 	if (max_width == 0) {
diff -Nru a/arch/ppc64/kernel/eeh.c b/arch/ppc64/kernel/eeh.c
--- a/arch/ppc64/kernel/eeh.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/eeh.c	Thu May  2 17:22:17 2002
@@ -26,9 +26,9 @@
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/bootmem.h>
-#include <asm/Paca.h>
+#include <asm/paca.h>
 #include <asm/processor.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/io.h>
 #include "pci.h"
 
@@ -36,7 +36,6 @@
 #define BUID_LO(buid) ((buid) & 0xffffffff)
 #define CONFIG_ADDR(busno, devfn) (((((busno) & 0xff) << 8) | ((devfn) & 0xf8)) << 8)
 
-unsigned long eeh_total_mmio_reads;
 unsigned long eeh_total_mmio_ffs;
 unsigned long eeh_false_positives;
 /* RTAS tokens */
@@ -44,11 +43,11 @@
 static int ibm_set_slot_reset;
 static int ibm_read_slot_reset_state;
 
-static int eeh_implemented;
+int eeh_implemented;
 #define EEH_MAX_OPTS 4096
 static char *eeh_opts;
 static int eeh_opts_last;
-static int eeh_check_opts_config(struct pci_dev *dev);
+static int eeh_check_opts_config(struct pci_dev *dev, int default_state);
 
 
 unsigned long eeh_token(unsigned long phb, unsigned long bus, unsigned long devfn, unsigned long offset)
@@ -86,33 +85,58 @@
 		panic("EEH: checking token %p phb index of %ld is greater than max of %d\n", token, phbidx, global_phb_number-1);
 	}
 	phb = phbtab[phbidx];
-	eeh_false_positives++;
 
 	ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
 			config_addr, BUID_HI(phb->buid), BUID_LO(phb->buid));
-	if (ret == 0 && rets[1] == 1 && rets[2] != 0) {
+	if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
 		struct pci_dev *dev;
 		int bus = ((unsigned long)token >> 40) & 0xffff; /* include PHB# in bus */
 		int devfn = (config_addr >> 8) & 0xff;
 
 		dev = pci_find_slot(bus, devfn);
-		if (dev)
+		if (dev) {
+			udbg_printf("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
+			      rets[0], dev->slot_name, dev->name);
+			printk("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
+			      rets[0], dev->slot_name, dev->name);
+			PPCDBG_ENTER_DEBUGGER();
 			panic("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
-			      rets[2], dev->slot_name, dev->name);
-		else
-			panic("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[2], phb->buid, config_addr);
+			      rets[0], dev->slot_name, dev->name);
+		} else {
+			udbg_printf("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
+			printk("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
+			PPCDBG_ENTER_DEBUGGER();
+			panic("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
+		}
 	}
+	eeh_false_positives++;
 	return val;	/* good case */
 }
 
 void eeh_init(void) {
+	extern char cmd_line[];	/* Very early cmd line parse.  Cheap, but works. */
+	char *eeh_force_off = strstr(cmd_line, "eeh-force-off");
+	char *eeh_force_on = strstr(cmd_line, "eeh-force-on");
+
 	ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");
 	ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");
 	ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
-	if (ibm_set_eeh_option != RTAS_UNKNOWN_SERVICE) {
-		printk("PCI Enhanced I/O Error Handling Enabled\n");
+	if (ibm_set_eeh_option != RTAS_UNKNOWN_SERVICE && naca->platform == PLATFORM_PSERIES_LPAR)
 		eeh_implemented = 1;
+
+	if (eeh_force_off > eeh_force_on) {
+		/* User is forcing EEH off.  Be noisy if it is implemented. */
+		if (eeh_implemented)
+			printk("EEH: WARNING: PCI Enhanced I/O Error Handling is user disabled\n");
+		eeh_implemented = 0;
+		return;
 	}
+
+	if (eeh_force_on > eeh_force_off)
+		eeh_implemented = 1;	/* User is forcing it on. */
+
+	if (eeh_implemented)
+		printk("EEH: PCI Enhanced I/O Error Handling Enabled\n");
 }
 
 
@@ -124,27 +148,35 @@
 	struct device_node *dn = pci_device_to_OF_node(dev);
 	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
 	unsigned long ret, rets[2];
+	int eeh_capable;
+	int default_state = 1;	/* default enable EEH if we can. */
 
-	if (dn == NULL || phb == NULL || phb->buid == 0 || !eeh_implemented)
+	if (dn == NULL || phb == NULL || !eeh_implemented)
 		return 0;
 
-	/* Hack: turn off eeh for display class devices.
+	/* Hack: turn off eeh for display class devices by default.
 	 * This fixes matrox accel framebuffer.
 	 */
 	if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
-		return 0;
+		default_state = 0;
 
-	if (!eeh_check_opts_config(dev))
+	/* Ignore known PHBs and EADs bridges */
+	if (dev->vendor == PCI_VENDOR_ID_IBM &&
+	    (dev->device == 0x0102 || dev->device == 0x008b))
+		default_state = 0;
+
+	if (!eeh_check_opts_config(dev, default_state)) {
+		if (default_state)
+			printk("EEH: %s %s user requested to run without EEH.\n", dev->slot_name, dev->name);
 		return 0;
+	}
 
 	ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
 			CONFIG_ADDR(dn->busno, dn->devfn),
 			BUID_HI(phb->buid), BUID_LO(phb->buid));
-	if (ret == 0 && rets[1] == 1) {
-		printk("EEH: %s %s is EEH capable.\n", dev->slot_name, dev->name);
-		return 1;
-	}
-	return 0;
+	eeh_capable = (ret == 0 && rets[1] == 1);
+	printk("EEH: %s %s is%s EEH capable.\n", dev->slot_name, dev->name, eeh_capable ? "" : " not");
+	return eeh_capable;
 }
 
 int eeh_set_option(struct pci_dev *dev, int option)
@@ -166,41 +198,41 @@
 {
 	int len;
 	len = sprintf(page, "eeh_false_positives=%ld\n"
-		      "eeh_total_mmio_ffs=%ld\n"
-		      "eeh_total_mmio_reads=%ld\n",
-		      eeh_false_positives, eeh_total_mmio_ffs, eeh_total_mmio_reads);
+		      "eeh_total_mmio_ffs=%ld\n",
+		      eeh_false_positives, eeh_total_mmio_ffs);
 	return len;
 }
 
 /* Implementation of /proc/ppc64/eeh
  * For now it is one file showing false positives.
  */
-void eeh_init_proc(struct proc_dir_entry *top)
+static int __init eeh_init_proc(void)
 {
-	struct proc_dir_entry *ent = create_proc_entry("eeh", S_IRUGO, top);
+	struct proc_dir_entry *ent = create_proc_entry("ppc64/eeh", S_IRUGO, 0);
 	if (ent) {
 		ent->nlink = 1;
 		ent->data = NULL;
 		ent->read_proc = (void *)eeh_proc_falsepositive_read;
 	}
+	return 0;
 }
 
 /*
  * Test if "dev" should be configured on or off.
- * This processes the options literally from right to left.
+ * This processes the options literally from left to right.
  * This lets the user specify stupid combinations of options,
  * but at least the result should be very predictable.
  */
-static int eeh_check_opts_config(struct pci_dev *dev)
+static int eeh_check_opts_config(struct pci_dev *dev, int default_state)
 {
 	struct device_node *dn = pci_device_to_OF_node(dev);
 	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
 	char devname[32], classname[32], phbname[32];
 	char *strs[8], *s;
 	int nstrs, i;
-	int ret = 0;
+	int ret = default_state;
 
-	if (dn == NULL || phb == NULL || phb->buid == 0 || !eeh_implemented)
+	if (dn == NULL || phb == NULL)
 		return 0;
 	/* Build list of strings to match */
 	nstrs = 0;
@@ -221,7 +253,7 @@
 	for (s = eeh_opts; s && (s < (eeh_opts + eeh_opts_last)); s += strlen(s)+1) {
 		for (i = 0; i < nstrs; i++) {
 			if (strcasecmp(strs[i], s+1) == 0) {
-				ret = (strs[0] == '+') ? 1 : 0;
+				ret = (strs[i][0] == '+') ? 1 : 0;
 			}
 		}
 	}
@@ -234,7 +266,7 @@
  *	eeh-off=loc1,loc2,loc3...
  *
  * and this option can be repeated so
- *      eeh-off=loc1,loc2 eeh=loc3
+ *      eeh-off=loc1,loc2 eeh-off=loc3
  * is the same as eeh-off=loc1,loc2,loc3
  *
  * loc is an IBM location code that can be found in a manual or
@@ -285,7 +317,6 @@
 			curend = cur + strlen(cur);
 		if (*cur) {
 			int curlen = curend-cur;
-			char *sym = eeh_opts+eeh_opts_last;
 			if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) {
 				printk("EEH: sorry...too many eeh cmd line options\n");
 				return 1;
@@ -308,6 +339,6 @@
 	return eeh_parm(str, 1);
 }
 
-
+__initcall(eeh_init_proc);
 __setup("eeh-off", eehoff_parm);
 __setup("eeh-on", eehon_parm);
diff -Nru a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S
--- a/arch/ppc64/kernel/entry.S	Thu May  2 17:22:15 2002
+++ b/arch/ppc64/kernel/entry.S	Thu May  2 17:22:15 2002
@@ -1,5 +1,5 @@
 /*
- *  arch/ppc/kernel/entry.S
+ *  arch/ppc64/kernel/entry.S
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -290,7 +290,7 @@
 	std	r23,_CCR(r1)
 	std	r1,KSP(r3)	/* Set old stack pointer */
 
-	mfspr	r5,SPRG3	/* Get Paca */
+	mfspr	r5,SPRG3	/* Get paca */
 	addi	r13,r4,-THREAD	/* Convert THREAD to 'current' */
 	std	r13,PACACURRENT(r5)	/* Set new 'current' */
 
diff -Nru a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
--- a/arch/ppc64/kernel/head.S	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/head.S	Thu May  2 17:22:17 2002
@@ -54,7 +54,7 @@
  *   SPRG0             reserved for hypervisor
  *   SPRG1             temp - used to save gpr
  *   SPRG2             temp - used to save gpr
- *   SPRG3             virt addr of Paca
+ *   SPRG3             virt addr of paca
  */
 
 /*
@@ -163,14 +163,18 @@
 #define EX_R23		40
 #define EX_DAR		48
 #define EX_DSISR	56
+#define EX_CCR   	60
+#define EX_TRAP   	60
 
-#define EXCEPTION_PROLOG_PSERIES(label)                                  \
+#define EXCEPTION_PROLOG_PSERIES(n,label)                                \
 	mtspr   SPRG2,r20;              /* use SPRG2 as scratch reg   */ \
 	mtspr   SPRG1,r21;              /* save r21                   */ \
-	mfspr   r20,SPRG3;              /* get Paca virt addr         */ \
+	mfspr   r20,SPRG3;              /* get paca virt addr         */ \
 	ld      r21,PACAEXCSP(r20);     /* get exception stack ptr    */ \
 	addi    r21,r21,EXC_FRAME_SIZE; /* make exception frame       */ \
 	std	r22,EX_R22(r21);	/* Save r22 in exc. frame     */ \
+	li	r22,n;                  /* Save the ex # in exc. frame*/ \
+	stw	r22,EX_TRAP(r21);	/*                            */ \
 	std	r23,EX_R23(r21);	/* Save r23 in exc. frame     */ \
 	mfspr   r22,SRR0;               /* EA of interrupted instr    */ \
 	std	r22,EX_SRR0(r21);	/* Save SRR0 in exc. frame    */ \
@@ -192,19 +196,21 @@
  * This is the start of the interrupt handlers for i_series
  * This code runs with relocation on.
  */
-#define EXCEPTION_PROLOG_ISERIES	\
-	mtspr	SPRG2,r20;		    /* use SPRG2 as scratch reg */\
-	mtspr   SPRG1,r21;                  /* save r21 */\
-	mfspr	r20,SPRG3;		    /* get Paca */\
-	ld      r21,PACAEXCSP(r20);         /* get exception stack ptr */\
-	addi    r21,r21,EXC_FRAME_SIZE;     /* make exception frame */\
-	std	r22,EX_R22(r21);	    /* save r22 on exception frame */\
-	std	r23,EX_R23(r21);	    /* Save r23 in exc. frame */\
-	ld      r22,LPPACA+LPPACASRR0(r20); /* Get SRR0 from ItLpPaca */\
-	std	r22,EX_SRR0(r21);	    /* save SRR0 in exc. frame */\
-	ld      r23,LPPACA+LPPACASRR1(r20); /* Get SRR1 from ItLpPaca */\
-	std	r23,EX_SRR1(r21);	    /* save SRR1 in exc. frame */\
-	mfcr    r23;                        /* save CR in r23 */
+#define EXCEPTION_PROLOG_ISERIES(n)	                                      \
+	mtspr	SPRG2,r20;		    /* use SPRG2 as scratch reg    */ \
+	mtspr   SPRG1,r21;                  /* save r21                    */ \
+	mfspr	r20,SPRG3;		    /* get paca                    */ \
+	ld      r21,PACAEXCSP(r20);         /* get exception stack ptr     */ \
+	addi    r21,r21,EXC_FRAME_SIZE;     /* make exception frame        */ \
+	std	r22,EX_R22(r21);	    /* save r22 on exception frame */ \
+	li	r22,n;                      /* Save the ex # in exc. frame */ \
+	stw	r22,EX_TRAP(r21);	    /*                             */ \
+	std	r23,EX_R23(r21);	    /* Save r23 in exc. frame      */ \
+	ld      r22,LPPACA+LPPACASRR0(r20); /* Get SRR0 from ItLpPaca      */ \
+	std	r22,EX_SRR0(r21);	    /* save SRR0 in exc. frame     */ \
+	ld      r23,LPPACA+LPPACASRR1(r20); /* Get SRR1 from ItLpPaca      */ \
+	std	r23,EX_SRR1(r21);	    /* save SRR1 in exc. frame     */ \
+	mfcr    r23;                        /* save CR in r23              */
 
 /*
  * The common exception prolog is used for all except a few exceptions
@@ -215,54 +221,54 @@
  * On entry r20 points to the paca and r21 points to the exception
  * frame on entry, r23 contains the saved CR, and relocation is on.
  */
-#define EXCEPTION_PROLOG_COMMON                                             \
-	mfspr	r22,SPRG2;		/* Save r20 in exc. frame */ \
-	std	r22,EX_R20(r21);	\
-	mfspr	r22,SPRG1;		/* Save r21 in exc. frame */ \
-	std	r22,EX_R21(r21);	\
-	mfspr   r22,DAR;                /* Save DAR in exc. frame        */ \
-	std	r22,EX_DAR(r21);	\
-	std     r21,PACAEXCSP(r20);     /* update exception stack ptr    */ \
-		                        /*   iff no protection flt       */ \
-	mfspr	r22,DSISR;		/* Save DSISR in exc. frame */ \
-	std	r22,EX_DSISR(r21);	\
-	ld	r22,EX_SRR1(r21);	/* Get SRR1 from exc. frame */ \
-	andi.   r22,r22,MSR_PR;         /* Set CR for later branch       */ \
-	mr      r22,r1;                 /* Save r1                       */ \
-	subi    r1,r1,INT_FRAME_SIZE;    /* alloc frame on kernel stack  */ \
-	beq-    1f;                     \
-	ld      r1,PACAKSAVE(r20);      /* kernel stack to use */ \
-1:      std     r22,GPR1(r1);           /* save r1 in stackframe */ \
-	std     r22,0(r1);              /* make stack chain pointer */ \
-	std     r23,_CCR(r1);           /* save CR in stackframe */ \
-	ld	r22,EX_R20(r21);	/* move r20 to stackframe */ \
-	std	r22,GPR20(r1);		\
-	ld	r23,EX_R21(r21);	/* move r21 to stackframe */ \
-	std	r23,GPR21(r1);		\
-	ld	r22,EX_R22(r21);	/* move r22 to stackframe */ \
-	std	r22,GPR22(r1);		\
-	ld	r23,EX_R23(r21);	/* move r23 to stackframe */ \
-	std	r23,GPR23(r1);		\
-	mflr    r22;                    /* save LR in stackframe */ \
-	std     r22,_LINK(r1);          \
-	mfctr   r23;                    /* save CTR in stackframe */ \
-	std     r23,_CTR(r1);           \
-	mfspr   r22,XER;                /* save XER in stackframe */ \
-	std     r22,_XER(r1);           \
-	ld	r23,EX_DAR(r21);	/* move DAR to stackframe */ \
-	std	r23,_DAR(r1);		\
-	ld	r22,EX_DSISR(r21);	/* move DSISR to stackframe */ \
-	std	r22,_DSISR(r1);		\
-	lbz	r22,PACAPROCENABLED(r20); \
-	std	r22,SOFTE(r1);		\
-	ld	r22,EX_SRR0(r21);	/* get SRR0 from exc. frame */ \
-	ld	r23,EX_SRR1(r21);	/* get SRR1 from exc. frame */ \
-	addi    r21,r21,-EXC_FRAME_SIZE;/* pop off exception frame */ \
-	std     r21,PACAEXCSP(r20);     \
-	SAVE_GPR(0, r1);                /* save r0 in stackframe */ \
+#define EXCEPTION_PROLOG_COMMON                                           \
+	mfspr	r22,SPRG2;		/* Save r20 in exc. frame      */ \
+	std	r22,EX_R20(r21);	                                  \
+	mfspr	r22,SPRG1;		/* Save r21 in exc. frame      */ \
+	std	r22,EX_R21(r21);	                                  \
+	mfspr   r22,DAR;                /* Save DAR in exc. frame      */ \
+	std	r22,EX_DAR(r21);	                                  \
+	std     r21,PACAEXCSP(r20);     /* update exception stack ptr  */ \
+		                        /*   iff no protection flt     */ \
+	mfspr	r22,DSISR;		/* Save DSISR in exc. frame    */ \
+	stw	r22,EX_DSISR(r21);	                                  \
+	ld	r22,EX_SRR1(r21);	/* Get SRR1 from exc. frame    */ \
+	andi.   r22,r22,MSR_PR;         /* Set CR for later branch     */ \
+	mr      r22,r1;                 /* Save r1                     */ \
+	subi    r1,r1,INT_FRAME_SIZE;   /* alloc frame on kernel stack */ \
+	beq-    1f;                                                       \
+	ld      r1,PACAKSAVE(r20);      /* kernel stack to use         */ \
+1:      std     r22,GPR1(r1);           /* save r1 in stackframe       */ \
+	std     r22,0(r1);              /* make stack chain pointer    */ \
+	std     r23,_CCR(r1);           /* save CR in stackframe       */ \
+	ld	r22,EX_R20(r21);	/* move r20 to stackframe      */ \
+	std	r22,GPR20(r1);		                                  \
+	ld	r23,EX_R21(r21);	/* move r21 to stackframe      */ \
+	std	r23,GPR21(r1);		                                  \
+	ld	r22,EX_R22(r21);	/* move r22 to stackframe      */ \
+	std	r22,GPR22(r1);		                                  \
+	ld	r23,EX_R23(r21);	/* move r23 to stackframe      */ \
+	std	r23,GPR23(r1);		                                  \
+	mflr    r22;                    /* save LR in stackframe       */ \
+	std     r22,_LINK(r1);                                            \
+	mfctr   r23;                    /* save CTR in stackframe      */ \
+	std     r23,_CTR(r1);                                             \
+	mfspr   r22,XER;                /* save XER in stackframe      */ \
+	std     r22,_XER(r1);                                             \
+	ld	r23,EX_DAR(r21);	/* move DAR to stackframe      */ \
+	std	r23,_DAR(r1);		                                  \
+	lwz     r22,EX_DSISR(r21);	/* move DSISR to stackframe    */ \
+	std	r22,_DSISR(r1);		                                  \
+	lbz	r22,PACAPROCENABLED(r20);                                 \
+	std	r22,SOFTE(r1);		                                  \
+	ld	r22,EX_SRR0(r21);	/* get SRR0 from exc. frame    */ \
+	ld	r23,EX_SRR1(r21);	/* get SRR1 from exc. frame    */ \
+	addi    r21,r21,-EXC_FRAME_SIZE;/* pop off exception frame     */ \
+	std     r21,PACAEXCSP(r20);                                       \
+	SAVE_GPR(0, r1);                /* save r0 in stackframe       */ \
 	SAVE_8GPRS(2, r1);              /* save r2 - r13 in stackframe */ \
-	SAVE_4GPRS(10, r1);             \
-	ld      r2,PACATOC(r20);	\
+	SAVE_4GPRS(10, r1);                                               \
+	ld      r2,PACATOC(r20);	                                  \
 	ld      r13,PACACURRENT(r20)
 
 /*
@@ -277,18 +283,18 @@
 	. = n;					\
 	.globl label##_Pseries;			\
 label##_Pseries:				\
-	EXCEPTION_PROLOG_PSERIES( label##_common )
+	EXCEPTION_PROLOG_PSERIES( n, label##_common )
 
-#define STD_EXCEPTION_ISERIES( label )		\
+#define STD_EXCEPTION_ISERIES( n, label )	\
 	.globl label##_Iseries;			\
 label##_Iseries:				\
-	EXCEPTION_PROLOG_ISERIES;		\
+	EXCEPTION_PROLOG_ISERIES( n );          \
 	b	label##_common
 
-#define MASKABLE_EXCEPTION_ISERIES( label )	\
+#define MASKABLE_EXCEPTION_ISERIES( n, label )	\
 	.globl label##_Iseries;			\
 label##_Iseries:				\
-	EXCEPTION_PROLOG_ISERIES;		\
+	EXCEPTION_PROLOG_ISERIES( n );		\
 	lbz	r22,PACAPROFENABLED(r20);	\
 	cmpi	0,r22,0;			\
 	bne-	label##_Iseries_profile;	\
@@ -344,26 +350,26 @@
 	STD_EXCEPTION_PSERIES( 0xf00, PerformanceMonitor )
 	STD_EXCEPTION_PSERIES( 0x1300, InstructionBreakpoint )
 
+	/* Space for the naca.  Architected to be located at real address
+	 * 0x4000.  Various tools rely on this location being fixed.
+	 * The first dword of the naca is required by iSeries LPAR to
+	 * point to itVpdAreas.  On pSeries native, this value is not used.
+	 */
 	. = 0x4000
 	.globl __end_interupts
 	.globl __start_naca
 __end_interupts:
 __start_naca:
-	/* Save space for naca.
-	 * The first dword of the Naca is required by iSeries LPAR to
-	 * point to itVpdAreas.  On pSeries native, this value is not used.
-	 */
 	.llong itVpdAreas
 	.llong 0x0
 	.llong 0x0
-	.llong xPaca
+	.llong paca
 
 	/*
 	 * Space for the initial segment table
 	 * For LPAR, the hypervisor must fill in at least one entry
 	 * before we get control (with relocate on)
 	 */
-
 	. = 0x5000
 	.globl __end_naca
 	.globl __start_stab
@@ -402,26 +408,26 @@
 
 /***  ISeries-LPAR interrupt handlers ***/
 
-	STD_EXCEPTION_ISERIES( MachineCheck )
-	STD_EXCEPTION_ISERIES( DataAccess )
-	STD_EXCEPTION_ISERIES( DataAccessSLB )
-	STD_EXCEPTION_ISERIES( InstructionAccess )
-	STD_EXCEPTION_ISERIES( InstructionAccessSLB )
-	MASKABLE_EXCEPTION_ISERIES( HardwareInterrupt )
-	STD_EXCEPTION_ISERIES( Alignment )
-	STD_EXCEPTION_ISERIES( ProgramCheck )
-	STD_EXCEPTION_ISERIES( FPUnavailable )
-	MASKABLE_EXCEPTION_ISERIES( Decrementer )
-	STD_EXCEPTION_ISERIES( Trap_0a )
-	STD_EXCEPTION_ISERIES( Trap_0b )
-	STD_EXCEPTION_ISERIES( SystemCall )
-	STD_EXCEPTION_ISERIES( SingleStep )
-	STD_EXCEPTION_ISERIES( Trap_0e )
-	STD_EXCEPTION_ISERIES( PerformanceMonitor )
+	STD_EXCEPTION_ISERIES( 0x200, MachineCheck )
+	STD_EXCEPTION_ISERIES( 0x300, DataAccess )
+	STD_EXCEPTION_ISERIES( 0x380, DataAccessSLB )
+	STD_EXCEPTION_ISERIES( 0x400, InstructionAccess )
+	STD_EXCEPTION_ISERIES( 0x480, InstructionAccessSLB )
+	MASKABLE_EXCEPTION_ISERIES( 0x500, HardwareInterrupt )
+	STD_EXCEPTION_ISERIES( 0x600, Alignment )
+	STD_EXCEPTION_ISERIES( 0x700, ProgramCheck )
+	STD_EXCEPTION_ISERIES( 0x800, FPUnavailable )
+	MASKABLE_EXCEPTION_ISERIES( 0x900, Decrementer )
+	STD_EXCEPTION_ISERIES( 0xa00, Trap_0a )
+	STD_EXCEPTION_ISERIES( 0xb00, Trap_0b )
+	STD_EXCEPTION_ISERIES( 0xc00, SystemCall )
+	STD_EXCEPTION_ISERIES( 0xd00, SingleStep )
+	STD_EXCEPTION_ISERIES( 0xe00, Trap_0e )
+	STD_EXCEPTION_ISERIES( 0xf00, PerformanceMonitor )
 
 	.globl SystemReset_Iseries
 SystemReset_Iseries:
-	mfspr	25,SPRG3		/* Get Paca address */
+	mfspr	25,SPRG3		/* Get paca address */
 	lhz	r24,PACAPACAINDEX(r25)	/* Get processor # */
 	cmpi	0,r24,0			/* Are we processor 0? */
 	beq	.__start_initialization_iSeries	/* Start up the first processor */
@@ -489,6 +495,24 @@
 	mfspr	r20,SPRG2
 	rfid
 
+/*
+ * Data area reserved for FWNMI option.
+ */
+        .= 0x7000
+	.globl fwnmi_data_area
+fwnmi_data_area:
+
+/*
+ * Vectors for the FWNMI option.  Share common code.
+ */
+	. = 0x8000
+	.globl SystemReset_FWNMI
+SystemReset_FWNMI:
+	EXCEPTION_PROLOG_PSERIES(0x100, SystemReset_common)
+	.globl MachineCheck_FWNMI
+MachineCheck_FWNMI:
+	EXCEPTION_PROLOG_PSERIES(0x200, MachineCheck_common)
+
 /*** Common interrupt handlers ***/
 
 	STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException )
@@ -658,7 +682,7 @@
 	/*                                                                */
 	/*  The call to do_irq will preserve the value of r14 - r31       */
 	/*                                                                */
-	mfspr	r20,SPRG3 		    /* get Paca                   */
+	mfspr	r20,SPRG3 		    /* get paca                   */
 	lbz     r21,PACAHRDWINTCOUNT(r20)    /* get hardware interrupt cnt */
 	cmpi    0,r21,1                     /*                            */
 	addi    r21,r21,1                   /* incr hardware interrupt cnt*/
@@ -820,7 +844,7 @@
  * We assume we aren't going to take any exceptions during this procedure.
  */
 _GLOBAL(do_stab_bolted)
-	std	r23,EX_DAR(r21)	/* save CR in exc. frame */
+	stw	r23,EX_CCR(r21)	/* save CR in exc. frame */
 
 	mfspr   r22,DSISR
 	andis.  r22,r22,0x0020
@@ -926,7 +950,7 @@
 	mfsprg  r20,3                   /* Load the PACA pointer  */
 	ld      r21,PACAEXCSP(r20)      /* Get the exception frame pointer */
 	addi    r21,r21,EXC_FRAME_SIZE
-	ld	r23,EX_DAR(r21)		/* get saved CR */
+	lwz	r23,EX_CCR(r21)		/* get saved CR */
 	/* note that this is almost identical to maskable_exception_exit */
 	mtcr    r23                     /* restore CR */
 	ld	r22,EX_SRR0(r21)	/* Get SRR0 from exc. frame */
@@ -947,7 +971,7 @@
  * We assume we aren't going to take any exceptions during this procedure.
  */
 _GLOBAL(do_slb_bolted)
-	std     r23,48(r21)     /* save CR in exc. frame */
+	stw     r23,EX_CCR(r21) /* save CR in exc. frame */
 
 	/* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */
 	mfspr	r21,DAR
@@ -1014,7 +1038,7 @@
 	mfsprg  r20,3                   /* Load the PACA pointer  */
 	ld      r21,PACAEXCSP(r20)      /* Get the exception frame pointer */
 	addi    r21,r21,EXC_FRAME_SIZE
-	ld	r23,EX_DAR(r21)		/* get saved CR */
+	lwz	r23,EX_CCR(r21)		/* get saved CR */
 	/* note that this is almost identical to maskable_exception_exit */
 	mtcr    r23                     /* restore CR */
 	ld	r22,EX_SRR0(r21)	/* Get SRR0 from exc. frame */
@@ -1073,7 +1097,7 @@
 
 	/*
 	 * Indicate that r1 contains the kernel stack and
-	 * get the Kernel TOC and CURRENT pointers from the Paca
+	 * get the Kernel TOC and CURRENT pointers from the paca
 	 */
 	mfspr	r23,SPRG3		/* Get PACA */
 	std	r22,PACAKSAVE(r23)	/* r1 is now kernel sp */
@@ -1132,12 +1156,12 @@
 	bl	.enable_64b_mode
 	isync
 
-	/* Set up a Paca value for this processor. */
-	LOADADDR(r24, xPaca) 		 /* Get base vaddr of Paca array  */
-	mulli	r25,r3,PACA_SIZE	 /* Calculate vaddr of right Paca */
+	/* Set up a paca value for this processor. */
+	LOADADDR(r24, paca) 		 /* Get base vaddr of paca array  */
+	mulli	r25,r3,PACA_SIZE	 /* Calculate vaddr of right paca */
 	add	r25,r25,r24              /* for this processor.           */
 
-	mtspr	SPRG3,r25		 /* Save vaddr of Paca in SPRG3   */
+	mtspr	SPRG3,r25		 /* Save vaddr of paca in SPRG3   */
 	mr	r24,r3			 /* __secondary_start needs cpu#  */
 
 1:
@@ -1177,7 +1201,7 @@
 	std	r4,0(r9)		/* set the naca pointer */
 
 	/* Get the pointer to the segment table */
-	ld	r6,PACA(r4)             /* Get the base Paca pointer       */
+	ld	r6,PACA(r4)             /* Get the base paca pointer       */
 	ld	r4,PACASTABVIRT(r6)
 
 	bl      .iSeries_fixup_klimit
@@ -1284,7 +1308,7 @@
 					/* this includes the code being   */
 					/* executed here.                 */
 
-	li	r0,4f@l			/* Jump to the copy of this code  */
+        LOADADDR(r0, 4f)                /* Jump to the copy of this code  */
 	mtctr	r0			/* that we just made              */
 	bctr
 
@@ -1439,15 +1463,15 @@
 /*
  * This function is called after the master CPU has released the
  * secondary processors.  The execution environment is relocation off.
- * The Paca for this processor has the following fields initialized at
+ * The paca for this processor has the following fields initialized at
  * this point:
  *   1. Processor number
  *   2. Segment table pointer (virtual address)
  * On entry the following are set:
  *   r1    = stack pointer.  vaddr for iSeries, raddr (temp stack) for pSeries
  *   r24   = cpu# (in Linux terms)
- *   r25   = Paca virtual address
- *   SPRG3 = Paca virtual address
+ *   r25   = paca virtual address
+ *   SPRG3 = paca virtual address
  */
 _GLOBAL(__secondary_start)
 
@@ -1581,7 +1605,7 @@
 #ifdef CONFIG_SMP
 	/* All secondary cpus are now spinning on a common
 	 * spinloop, release them all now so they can start
-	 * to spin on their individual Paca spinloops.
+	 * to spin on their individual paca spinloops.
 	 * For non SMP kernels, the secondary cpus never
 	 * get out of the common spinloop.
 	 */
@@ -1617,7 +1641,7 @@
 	/* Get the pointer to the segment table which is used by           */
 	/* stab_initialize                                                 */
 	li	r27,0x4000
-	ld	r6,PACA(r27)            /* Get the base Paca pointer       */
+	ld	r6,PACA(r27)            /* Get the base paca pointer       */
 	sub	r6,r6,r26		/* convert to physical addr         */
 	mtspr	SPRG3,r6		/* PPPBBB: Temp... -Peter */
 	ld	r3,PACASTABREAL(r6)
@@ -1681,9 +1705,9 @@
 	addi	r8,r8,0x4000
 	std	r8,0(r9)		/* set the value of the naca ptr  */
 
-	LOADADDR(r4,naca)               /* Get Naca ptr address           */
+	LOADADDR(r4,naca)               /* Get naca ptr address           */
 	ld	r4,0(r4)                /* Get the location of the naca   */
-	ld	r4,PACA(r4)             /* Get the base Paca pointer      */
+	ld	r4,PACA(r4)             /* Get the base paca pointer      */
 	mtspr	SPRG3,r4
 
 	/* ptr to current */
@@ -1828,7 +1852,7 @@
 /* 1 page segment table per cpu (max 48, cpu0 allocated at 0x5000) */
 	.globl	stab_array
 stab_array:
-	.space	4096 * 47
+        .space	4096 * (48 - 1)
 	
 /*
  * This space gets a copy of optional info passed to us by the bootstrap
diff -Nru a/arch/ppc64/kernel/htab.c b/arch/ppc64/kernel/htab.c
--- a/arch/ppc64/kernel/htab.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/htab.c	Thu May  2 17:22:17 2002
@@ -38,7 +38,7 @@
 #include <asm/init.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/system.h>
 #include <asm/pmc.h>
 #include <asm/machdep.h>
@@ -83,7 +83,7 @@
 	for (addr = start; addr < end; addr += step) {
 		unsigned long vsid = get_kernel_vsid(addr);
 		unsigned long va = (vsid << 28) | (addr & 0xfffffff);
-		if (_machine == _MACH_pSeriesLP)
+		if (naca->platform == PLATFORM_PSERIES_LPAR)
 			pSeries_lpar_make_pte(htab, va,
 				(unsigned long)__v2a(addr), mode, mask, large);
 		else
@@ -99,7 +99,7 @@
 	unsigned long pteg_count;
 	unsigned long mode_rw, mask;
 	unsigned long offset = reloc_offset();
-	struct Naca *_naca = RELOC(naca);
+	struct naca_struct *_naca = RELOC(naca);
 	HTAB *_htab_data = PTRRELOC(&htab_data);
 
 	/*
@@ -118,7 +118,7 @@
 	_htab_data->htab_num_ptegs = pteg_count;
 	_htab_data->htab_hash_mask = pteg_count - 1;
 
-	if (_machine == _MACH_pSeries) {
+	if (naca->platform == PLATFORM_PSERIES) {
 		/* Find storage for the HPT.  Must be contiguous in
 		 * the absolute address space.
 		 */
diff -Nru a/arch/ppc64/kernel/iSeries_VpdInfo.c b/arch/ppc64/kernel/iSeries_VpdInfo.c
--- a/arch/ppc64/kernel/iSeries_VpdInfo.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/iSeries_VpdInfo.c	Thu May  2 17:22:16 2002
@@ -146,7 +146,7 @@
 int   device_Location(struct pci_dev* PciDev,char* BufPtr)
 {
 	struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)PciDev->sysdata;
-	return sprintf(BufPtr,"PCI: Bus%3d, Device%3d, Vendor %04X, Location %s",
+	return sprintf(BufPtr,"PCI: Bus%3d, AgentId%3d, Vendor %04X, Location %s",
 		       DevNode->DsaAddr.busNumber,
 		       DevNode->AgentId,
 		       DevNode->Vendor,
diff -Nru a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c
--- a/arch/ppc64/kernel/iSeries_pci.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/iSeries_pci.c	Thu May  2 17:22:17 2002
@@ -35,7 +35,7 @@
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
 #include <asm/ppcdebug.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/flight_recorder.h>
 #include <asm/pci_dma.h>
 
@@ -55,7 +55,6 @@
 extern int    global_phb_number;
 extern int    panic_timeout;
 
-extern struct Naca *naca;
 extern struct device_node *allnodes;
 extern unsigned long phb_tce_table_init(struct pci_controller *phb);
 extern unsigned long iSeries_Base_Io_Memory;    
@@ -449,7 +448,7 @@
 	HvSubBusNumber SubBus = BridgeInfo->subBusNumber;
 	u16       VendorId    = 0;
 	int       HvRc        = 0;
-	int       Irq         = 0;
+	u8        Irq         = 0;
 	int       IdSel       = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus);
 	int       Function    = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus);
 	HvAgentId AgentId     = ISERIES_PCI_AGENTID(IdSel, Function);
@@ -476,9 +475,14 @@
 					/**********************************************************/
 					/* FoundDevice: 0x18.28.10 = 0x12AE                       */
 					/**********************************************************/
-					HvCallPci_configStore8(Bus, SubBus, AgentId, PCI_INTERRUPT_LINE, Irq);  
 					PPCDBG(PPCDBG_BUSWALK,"PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X\n",
 					                                       Bus, SubBus, AgentId, VendorId);
+
+					HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId, PCI_INTERRUPT_LINE, Irq);  
+					if( HvRc != 0) {
+						pci_Log_Error("PciCfgStore Irq Failed!",Bus,SubBus,AgentId,HvRc);
+					}
+
 					++DeviceCount;
 					DeviceNode = build_device_node(Bus, SubBus, EADsIdSel, Function);
 					DeviceNode->Vendor      = VendorId;
diff -Nru a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c
--- a/arch/ppc64/kernel/iSeries_setup.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/iSeries_setup.c	Thu May  2 17:22:16 2002
@@ -37,8 +37,8 @@
 
 #include <asm/time.h>
 #include "iSeries_setup.h"
-#include <asm/Naca.h>
-#include <asm/Paca.h>
+#include <asm/naca.h>
+#include <asm/paca.h>
 #include <asm/iSeries/LparData.h>
 #include <asm/iSeries/HvCallHpt.h>
 #include <asm/iSeries/HvLpConfig.h>
@@ -85,7 +85,6 @@
 
 extern char _end[];
 
-extern struct Naca *naca;
 extern int rd_size;		/* Defined in drivers/block/rd.c */
 extern unsigned long klimit;
 extern unsigned long embedded_sysmap_start;
@@ -296,7 +295,7 @@
 		initrd_start = (unsigned long)__va(naca->xRamDisk);
 		initrd_end   = initrd_start + naca->xRamDiskSize * PAGE_SIZE;
 		initrd_below_start_ok = 1;	// ramdisk in kernel space
-		ROOT_DEV = MKDEV( RAMDISK_MAJOR, 0 );
+		ROOT_DEV = mk_kdev( RAMDISK_MAJOR, 0 );
 
 		if ( ((rd_size*1024)/PAGE_SIZE) < naca->xRamDiskSize )
 			rd_size = (naca->xRamDiskSize*PAGE_SIZE)/1024;
@@ -305,7 +304,7 @@
 #endif /* CONFIG_BLK_DEV_INITRD */
 	  {
                 
-	    /*		ROOT_DEV = MKDEV( VIODASD_MAJOR, 1 ); */
+	    /*		ROOT_DEV = mk_kdev( VIODASD_MAJOR, 1 ); */
 	  }
 
 	iSeries_recal_tb = get_tb();
@@ -889,13 +888,13 @@
 {
 	if ( dprof_buffer ) {
 		unsigned i;
-		for (i=0; i<maxPacas; ++i) {
-			xPaca[i].prof_shift = dprof_shift;
-			xPaca[i].prof_len = dprof_len-1;
-			xPaca[i].prof_buffer = dprof_buffer;
-			xPaca[i].prof_stext = (unsigned *)&_stext;
+		for (i=0; i<MAX_PACAS; ++i) {
+			paca[i].prof_shift = dprof_shift;
+			paca[i].prof_len = dprof_len-1;
+			paca[i].prof_buffer = dprof_buffer;
+			paca[i].prof_stext = (unsigned *)&_stext;
 			mb();
-			xPaca[i].prof_enabled = 1;
+			paca[i].prof_enabled = 1;
 		}
 	}
 }
diff -Nru a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
--- a/arch/ppc64/kernel/idle.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/idle.c	Thu May  2 17:22:17 2002
@@ -68,21 +68,24 @@
 
 int cpu_idle(void)
 {
-	struct Paca *paca;
+	struct paca_struct *lpaca;
 	long oldval;
 	unsigned long CTRL;
 
+#warning fix iseries run light
+#if 0
 	/* ensure iSeries run light will be out when idle */
 	current->thread.flags &= ~PPC_FLAG_RUN_LIGHT;
 	CTRL = mfspr(CTRLF);
 	CTRL &= ~RUNLATCH;
 	mtspr(CTRLT, CTRL);
+#endif
 
-	paca = get_paca();
+	lpaca = get_paca();
 
 	while (1) {
-		if (paca->xLpPaca.xSharedProc) {
-			if (ItLpQueue_isLpIntPending(paca->lpQueuePtr))
+		if (lpaca->xLpPaca.xSharedProc) {
+			if (ItLpQueue_isLpIntPending(lpaca->lpQueuePtr))
 				process_iSeries_events();
 			if (!need_resched())
 				yield_shared_processor();
@@ -94,7 +97,7 @@
 
 				while (!need_resched()) {
 					HMT_medium();
-					if (ItLpQueue_isLpIntPending(paca->lpQueuePtr))
+					if (ItLpQueue_isLpIntPending(lpaca->lpQueuePtr))
 						process_iSeries_events();
 					HMT_low();
 				}
diff -Nru a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c
--- a/arch/ppc64/kernel/ioctl32.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/ioctl32.c	Thu May  2 17:22:17 2002
@@ -44,6 +44,7 @@
 #include <linux/ppp_defs.h>
 #include <linux/if_ppp.h>
 #include <linux/if_pppox.h>
+#include <linux/if_tun.h>
 #include <linux/mtio.h>
 #include <linux/cdrom.h>
 #include <linux/loop.h>
@@ -102,20 +103,10 @@
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/nbd.h>
+#include <linux/random.h>
 #include <asm/ppc32.h>
 #include <asm/ppcdebug.h>
 
-/* Use this to get at 32-bit user passed pointers. 
-   See sys_sparc32.c for description about these. */
-#define A(__x) ((unsigned long)(__x))
-#define AA(__x)				\
-({	unsigned long __ret;		\
-	__asm__ ("clrldi	%0, %0, 32"	\
-		 : "=r" (__ret)		\
-		 : "0" (__x));		\
-	__ret;				\
-})
-
 /* Aiee. Someone does not find a difference between int and long */
 #define EXT2_IOC32_GETFLAGS               _IOR('f', 1, int)
 #define EXT2_IOC32_SETFLAGS               _IOW('f', 2, int)
@@ -480,6 +471,7 @@
 		return -ENODEV;
 
 	strcpy(ifr32.ifr_name, dev->name);
+	dev_put(dev);
 
 	err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
 	return (err ? -EFAULT : 0);
@@ -1168,6 +1160,234 @@
 	return err;
 }
 
+typedef struct sg_io_hdr32 {
+	s32 interface_id;	/* [i] 'S' for SCSI generic (required) */
+	s32 dxfer_direction;	/* [i] data transfer direction  */
+	u8  cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
+	u8  mx_sb_len;		/* [i] max length to write to sbp */
+	u16 iovec_count;	/* [i] 0 implies no scatter gather */
+	u32 dxfer_len;		/* [i] byte count of data transfer */
+	u32 dxferp;		/* [i], [*io] points to data transfer memory
+					      or scatter gather list */
+	u32 cmdp;		/* [i], [*i] points to command to perform */
+	u32 sbp;		/* [i], [*o] points to sense_buffer memory */
+	u32 timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
+	u32 flags;		/* [i] 0 -> default, see SG_FLAG... */
+	s32 pack_id;		/* [i->o] unused internally (normally) */
+	u32 usr_ptr;		/* [i->o] unused internally */
+	u8  status;		/* [o] scsi status */
+	u8  masked_status;	/* [o] shifted, masked scsi status */
+	u8  msg_status;		/* [o] messaging level data (optional) */
+	u8  sb_len_wr;		/* [o] byte count actually written to sbp */
+	u16 host_status;	/* [o] errors from host adapter */
+	u16 driver_status;	/* [o] errors from software driver */
+	s32 resid;		/* [o] dxfer_len - actual_transferred */
+	u32 duration;		/* [o] time taken by cmd (unit: millisec) */
+	u32 info;		/* [o] auxiliary information */
+} sg_io_hdr32_t;  /* 64 bytes long (on sparc32) */
+
+typedef struct sg_iovec32 {
+	u32 iov_base;
+	u32 iov_len;
+} sg_iovec32_t;
+
+static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov;
+	int i;
+
+	sgp->dxferp = kmalloc(sgp->iovec_count *
+			      sizeof(sg_iovec_t), GFP_KERNEL);
+	if (!sgp->dxferp)
+		return -ENOMEM;
+	memset(sgp->dxferp, 0,
+	       sgp->iovec_count * sizeof(sg_iovec_t));
+
+	kiov = (sg_iovec_t *) sgp->dxferp;
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+		if (__get_user(iov_base32, &uiov->iov_base) ||
+		    __get_user(kiov->iov_len, &uiov->iov_len))
+			return -EFAULT;
+
+		kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL);
+		if (!kiov->iov_base)
+			return -ENOMEM;
+		if (copy_from_user(kiov->iov_base,
+				   (void *) A(iov_base32),
+				   kiov->iov_len))
+			return -EFAULT;
+
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static int copy_back_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
+	int i;
+
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+
+		if (__get_user(iov_base32, &uiov->iov_base))
+			return -EFAULT;
+
+		if (copy_to_user((void *) A(iov_base32),
+				 kiov->iov_base,
+				 kiov->iov_len))
+			return -EFAULT;
+
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static void free_sg_iovec(sg_io_hdr_t *sgp)
+{
+	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
+	int i;
+
+	for (i = 0; i < sgp->iovec_count; i++) {
+		if (kiov->iov_base) {
+			kfree(kiov->iov_base);
+			kiov->iov_base = NULL;
+		}
+		kiov++;
+	}
+	kfree(sgp->dxferp);
+	sgp->dxferp = NULL;
+}
+
+static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	sg_io_hdr32_t *sg_io32;
+	sg_io_hdr_t sg_io64;
+	u32 dxferp32, cmdp32, sbp32;
+	mm_segment_t old_fs;
+	int err = 0;
+
+	sg_io32 = (sg_io_hdr32_t *)arg;
+	err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
+	err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
+	err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
+	err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
+	err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
+	err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
+	err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
+	err |= __get_user(sg_io64.flags, &sg_io32->flags);
+	err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
+
+	sg_io64.dxferp = NULL;
+	sg_io64.cmdp = NULL;
+	sg_io64.sbp = NULL;
+
+	err |= __get_user(cmdp32, &sg_io32->cmdp);
+	sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
+	if (!sg_io64.cmdp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.cmdp,
+			   (void *) A(cmdp32),
+			   sg_io64.cmd_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(sbp32, &sg_io32->sbp);
+	sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
+	if (!sg_io64.sbp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.sbp,
+			   (void *) A(sbp32),
+			   sg_io64.mx_sb_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(dxferp32, &sg_io32->dxferp);
+	if (sg_io64.iovec_count) {
+		int ret;
+
+		if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
+			err = ret;
+			goto out;
+		}
+	} else {
+		sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
+		if (!sg_io64.dxferp) {
+			err = -ENOMEM;
+			goto out;
+		}
+		if (copy_from_user(sg_io64.dxferp,
+				   (void *) A(dxferp32),
+				   sg_io64.dxfer_len)) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+
+	/* Unused internally, do not even bother to copy it over. */
+	sg_io64.usr_ptr = NULL;
+
+	if (err)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
+	set_fs (old_fs);
+
+	if (err < 0)
+		goto out;
+
+	err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
+	err |= __put_user(sg_io64.status, &sg_io32->status);
+	err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
+	err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
+	err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
+	err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
+	err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
+	err |= __put_user(sg_io64.resid, &sg_io32->resid);
+	err |= __put_user(sg_io64.duration, &sg_io32->duration);
+	err |= __put_user(sg_io64.info, &sg_io32->info);
+	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count)
+			err |= copy_back_sg_iovec(&sg_io64, dxferp32);
+		else
+			err |= copy_to_user((void *)A(dxferp32),
+					    sg_io64.dxferp,
+					    sg_io64.dxfer_len);
+	}
+	if (err)
+		err = -EFAULT;
+
+out:
+	if (sg_io64.cmdp)
+		kfree(sg_io64.cmdp);
+	if (sg_io64.sbp)
+		kfree(sg_io64.sbp);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count) {
+			free_sg_iovec(&sg_io64);
+		} else {
+			kfree(sg_io64.dxferp);
+		}
+	}
+	return err;
+}
+
 struct ppp_option_data32 {
 	__kernel_caddr_t32	ptr;
 	__u32			length;
@@ -3058,13 +3278,12 @@
 	return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
 }
 
-#if 0
 struct usbdevfs_ctrltransfer32 {
-	__u8 requesttype;
-	__u8 request;
-	__u16 value;
-	__u16 index;
-	__u16 length;
+	__u8 bRequestType;
+	__u8 bRequest;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
 	__u32 timeout;  /* in milliseconds */
 	__u32 data;
 };
@@ -3094,14 +3313,14 @@
 	/* In usbdevice_fs, it limits the control buffer to a page,
 	 * for simplicity so do we.
 	 */
-	if (!uptr || kctrl.length > PAGE_SIZE)
+	if (!uptr || kctrl.wLength > PAGE_SIZE)
 		return -EINVAL;
 
 	kptr = (void *)__get_free_page(GFP_KERNEL);
 
-	if ((kctrl.requesttype & 0x80) == 0) {
+	if ((kctrl.bRequestType & 0x80) == 0) {
 		err = -EFAULT;
-		if (copy_from_user(kptr, uptr, kctrl.length))
+		if (copy_from_user(kptr, uptr, kctrl.wLength))
 			goto out;
 	}
 
@@ -3113,8 +3332,8 @@
 	set_fs(old_fs);
 
 	if (err >= 0 &&
-	    ((kctrl.requesttype & 0x80) != 0)) {
-		if (copy_to_user(uptr, kptr, kctrl.length))
+	    ((kctrl.bRequestType & 0x80) != 0)) {
+		if (copy_to_user(uptr, kptr, kctrl.wLength))
 			err = -EFAULT;
 	}
 
@@ -3449,7 +3668,6 @@
 
 	return err;
 }
-#endif
 
 struct mtd_oob_buf32 {
 	u32 start;
@@ -3507,119 +3725,6 @@
 	return ((0 == ret) ? 0 : -EFAULT);
 }	
 
-struct sg_io_hdr_32
-{
-	int interface_id;
-	int dxfer_direction;
-	unsigned char cmd_len;
-	unsigned char mx_sb_len;
-	unsigned short iovec_count;
-	unsigned int dxfer_len;
-	u32 dxferp;
-	u32 cmdp;
-	u32 sbp;
-	unsigned int timeout;
-	unsigned int flags;
-	int pack_id;
-	u32 usr_ptr;
-	unsigned char status;
-	unsigned char masked_status;
-	unsigned char msg_status;
-	unsigned char sb_len_wr;
-	unsigned short host_status;
-	unsigned short driver_status;
-	int resid;
-	unsigned int duration;
-	unsigned int info;
-};
-
-static int do_sg_io(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct sg_io_hdr *sg = kmalloc(sizeof(struct sg_io_hdr), GFP_KERNEL);
-	struct sg_io_hdr_32 *sg_32 = (struct sg_io_hdr_32 *)arg;
-	u32 dxferp_32;
-	u32 cmdp_32;
-	u32 sbp_32;
-	u32 usr_ptr_32;
-	int ret = -EFAULT;
-	int err;
-	mm_segment_t old_fs = get_fs();
-
-	if (!sg)
-		return -ENOMEM;
-
-	memset(sg, 0, sizeof(*sg));
-
-	err = copy_from_user(sg, sg_32, offsetof(struct sg_io_hdr, dxferp));
-	err |= __get_user(dxferp_32, &sg_32->dxferp);
-	err |= __get_user(cmdp_32, &sg_32->cmdp);
-	err |= __get_user(sbp_32, &sg_32->sbp);
-
-	if (err)
-		goto error;
-
-	sg->dxferp = (void *)A(dxferp_32);
-	sg->cmdp = (void *)A(cmdp_32);
-	sg->sbp = (void *)A(sbp_32);
-
-	err = __copy_from_user(&sg->timeout, &sg_32->timeout,
-			       (long)&sg->usr_ptr - (long)&sg->timeout);
-
-	err |= __get_user(usr_ptr_32, &sg_32->usr_ptr);
-
-	if (err)
-		goto error;
-
-	sg->usr_ptr = (void *)A(usr_ptr_32);
-
-	err = __copy_from_user(&sg->status, &sg_32->status,
-			       sizeof(struct sg_io_hdr) -
-			       offsetof(struct sg_io_hdr, status));
-
-	if (err)
-		goto error;
-
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, cmd, (unsigned long)sg);
-	set_fs(old_fs);
-
-	err = copy_to_user(sg_32, sg, offsetof(struct sg_io_hdr, dxferp));
-
-	dxferp_32 = (unsigned long)sg->dxferp;
-	cmdp_32 = (unsigned long)sg->cmdp;
-	sbp_32 = (unsigned long)sg->sbp;
-	err |= __put_user(dxferp_32, &sg_32->dxferp);
-	err |= __put_user(cmdp_32, &sg_32->cmdp);
-	err |= __put_user(sbp_32, &sg_32->sbp);
-
-	if (err) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	err = __copy_to_user(&sg_32->timeout, &sg->timeout,
-			     (long)&sg->usr_ptr - (long)&sg->timeout);
-
-	usr_ptr_32 = (unsigned long)sg->usr_ptr;
-	err |= __put_user(usr_ptr_32, &sg_32->usr_ptr);
-
-	if (err) {
-		ret = -EFAULT;
-		goto error;
-	}
-
-	err = __copy_to_user(&sg_32->status, &sg->status,
-			      sizeof(struct sg_io_hdr) -
-			      offsetof(struct sg_io_hdr, status));
-
-	if (err)
-		ret = -EFAULT;
-
-error:
-	kfree(sg);
-	return ret;
-}
-
 struct ioctl_trans {
 	unsigned long cmd;
 	unsigned long handler;
@@ -3706,7 +3811,6 @@
  */
 COMPATIBLE_IOCTL(HDIO_GET_IDENTITY),
 COMPATIBLE_IOCTL(HDIO_SET_DMA),
-COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS),
 COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR),
 COMPATIBLE_IOCTL(HDIO_SET_NOWERR),
 COMPATIBLE_IOCTL(HDIO_SET_32BIT),
@@ -3797,6 +3901,7 @@
 /* Big S */
 COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN),
 COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST),
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI),
 COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK),
 COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK),
 COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY),
@@ -3804,6 +3909,12 @@
 COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE),
 COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER),
 COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND),
+/* Big T */
+COMPATIBLE_IOCTL(TUNSETNOCSUM),
+COMPATIBLE_IOCTL(TUNSETDEBUG),
+COMPATIBLE_IOCTL(TUNSETIFF),
+COMPATIBLE_IOCTL(TUNSETPERSIST),
+COMPATIBLE_IOCTL(TUNSETOWNER),
 /* Big V */
 COMPATIBLE_IOCTL(VT_SETMODE),
 COMPATIBLE_IOCTL(VT_GETMODE),
@@ -3880,6 +3991,11 @@
 COMPATIBLE_IOCTL(SIOCDRARP),
 COMPATIBLE_IOCTL(SIOCADDDLCI),
 COMPATIBLE_IOCTL(SIOCDELDLCI),
+COMPATIBLE_IOCTL(SIOCGMIIPHY),
+COMPATIBLE_IOCTL(SIOCGMIIREG),
+COMPATIBLE_IOCTL(SIOCSMIIREG),
+COMPATIBLE_IOCTL(SIOCGIFVLAN),
+COMPATIBLE_IOCTL(SIOCSIFVLAN),
 /* SG stuff */
 COMPATIBLE_IOCTL(SG_SET_TIMEOUT),
 COMPATIBLE_IOCTL(SG_GET_TIMEOUT),
@@ -4209,6 +4325,13 @@
 COMPATIBLE_IOCTL(WDIOC_GETTEMP),
 COMPATIBLE_IOCTL(WDIOC_SETOPTIONS),
 COMPATIBLE_IOCTL(WDIOC_KEEPALIVE),
+/* Big R */
+COMPATIBLE_IOCTL(RNDGETENTCNT),
+COMPATIBLE_IOCTL(RNDADDTOENTCNT),
+COMPATIBLE_IOCTL(RNDGETPOOL),
+COMPATIBLE_IOCTL(RNDADDENTROPY),
+COMPATIBLE_IOCTL(RNDZAPENTCNT),
+COMPATIBLE_IOCTL(RNDCLEARPOOL),
 /* Bluetooth ioctls */
 COMPATIBLE_IOCTL(HCIDEVUP),
 COMPATIBLE_IOCTL(HCIDEVDOWN),
@@ -4253,13 +4376,6 @@
 COMPATIBLE_IOCTL(NBD_PRINT_DEBUG),
 COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS),
 COMPATIBLE_IOCTL(NBD_DISCONNECT),
-/* Remove *PRIVATE in 2.5 */
-COMPATIBLE_IOCTL(SIOCDEVPRIVATE),
-COMPATIBLE_IOCTL(SIOCDEVPRIVATE+1),
-COMPATIBLE_IOCTL(SIOCDEVPRIVATE+2),
-COMPATIBLE_IOCTL(SIOCGMIIPHY),
-COMPATIBLE_IOCTL(SIOCGMIIREG),
-COMPATIBLE_IOCTL(SIOCSMIIREG),
 /* And these ioctls need translation */
 HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob),
 HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob),
@@ -4312,7 +4428,6 @@
 HANDLE_IOCTL(0x1260, broken_blkgetsize),
 HANDLE_IOCTL(BLKSECTGET, w_long),
 HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans),
-HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans),
 HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans),
 HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans),
 HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans),
@@ -4328,6 +4443,7 @@
 HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans),
 HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans),
 HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans),
+HANDLE_IOCTL(SG_IO,sg_ioctl_trans),
 HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans),
 HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans),
 HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans),
@@ -4420,15 +4536,12 @@
 HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma),
 HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx),
 #endif /* DRM */
-#if 0
 HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control),
 HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk),
 /*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
 HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb),
 HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb),
 HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal),
-#endif
-HANDLE_IOCTL(SG_IO, do_sg_io),
 };
 
 unsigned long ioctl32_hash_table[1024];
diff -Nru a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c
--- a/arch/ppc64/kernel/irq.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/irq.c	Thu May  2 17:22:16 2002
@@ -55,6 +55,7 @@
 #include <asm/ptrace.h>
 #include <asm/iSeries/LparData.h>
 #include <asm/machdep.h>
+#include <asm/paca.h>
 
 #include "local_irq.h"
 
@@ -501,58 +502,55 @@
 	spin_unlock(&desc->lock);
 }
 
-int do_IRQ(struct pt_regs *regs, int isfake)
+int do_IRQ(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
-	int irq;
-	struct Paca * paca;
-	struct ItLpQueue * lpq;
-
-	/* if(cpu) udbg_printf("Entering do_IRQ\n");  */
-
-        irq_enter(cpu);
+	int irq, first = 1;
+#ifdef CONFIG_PPC_ISERIES
+	struct paca_struct *lpaca;
+	struct ItLpQueue *lpq;
+#endif
 
-	if ( _machine != _MACH_iSeries ) {
-	
-		/* every arch is required to have a get_irq -- Cort */
-		irq = ppc_md.get_irq( regs );
+	irq_enter(cpu);
 
-		if ( irq >= 0 ) {
-			ppc_irq_dispatch_handler( regs, irq );
-			if (ppc_md.post_irq)
-				ppc_md.post_irq( regs, irq );
-		} else {
-			/* -2 means ignore, already handled */
-			if (irq != -2) {
-				printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-					irq, regs->nip);
-				ppc_spurious_interrupts++;
-			}
-		}
-	}
-	/* if on iSeries partition */
-	else {
-		paca = (struct Paca *)mfspr(SPRG3);
+#ifdef CONFIG_PPC_ISERIES
+	lpaca = get_paca();
 #ifdef CONFIG_SMP
-		if ( paca->xLpPaca.xIntDword.xFields.xIpiCnt ) {
-			paca->xLpPaca.xIntDword.xFields.xIpiCnt = 0;
-			iSeries_smp_message_recv( regs );
-		}
-#endif /* CONFIG_SMP */
-		lpq = paca->lpQueuePtr;
-		if ( lpq && ItLpQueue_isLpIntPending( lpq ) )
-			lpEvent_count += ItLpQueue_process( lpq, regs );
+	if (lpaca->xLpPaca.xIntDword.xFields.xIpiCnt) {
+		lpaca->xLpPaca.xIntDword.xFields.xIpiCnt = 0;
+		iSeries_smp_message_recv(regs);
 	}
-		
+#endif /* CONFIG_SMP */
+	lpq = lpaca->lpQueuePtr;
+	if (lpq && ItLpQueue_isLpIntPending(lpq))
+		lpEvent_count += ItLpQueue_process(lpq, regs);
+#else
+	/*
+	 * Every arch is required to implement ppc_md.get_irq.
+	 * This function will either return an irq number or -1 to
+	 * indicate there are no more pending.  But the first time
+	 * through the loop this means there wasn't an IRQ pending.
+	 * The value -2 is for buggy hardware and means that this IRQ
+	 * has already been handled. -- Tom
+	 */
+	while ((irq = ppc_md.get_irq(regs)) >= 0) {
+		ppc_irq_dispatch_handler(regs, irq);
+		first = 0;
+	}
+	if (irq != -2 && first)
+		/* That's not SMP safe ... but who cares ? */
+		ppc_spurious_interrupts++;
+#endif
+
         irq_exit(cpu);
 
-	if ( _machine == _MACH_iSeries ) {
-		if ( paca->xLpPaca.xIntDword.xFields.xDecrInt ) {
-			paca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
-			/* Signal a fake decrementer interrupt */
-			timer_interrupt( regs );
-		}
+#ifdef CONFIG_PPC_ISERIES
+	if (lpaca->xLpPaca.xIntDword.xFields.xDecrInt) {
+		lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
+		/* Signal a fake decrementer interrupt */
+		timer_interrupt(regs);
 	}
+#endif
 
 	if (softirq_pending(cpu))
 		do_softirq();
@@ -847,11 +845,11 @@
 #ifdef CONFIG_PPC_ISERIES
 	{
 		unsigned i;
-		for (i=0; i<maxPacas; ++i) {
-			if ( xPaca[i].prof_buffer && (new_value & 1) )
-				xPaca[i].prof_enabled = 1;
+		for (i=0; i<MAX_PACAS; ++i) {
+			if ( paca[i].prof_buffer && (new_value & 1) )
+				paca[i].prof_enabled = 1;
 			else
-				xPaca[i].prof_enabled = 0;
+				paca[i].prof_enabled = 0;
 			new_value >>= 1;
 		}
 	}
diff -Nru a/arch/ppc64/kernel/mf.c b/arch/ppc64/kernel/mf.c
--- a/arch/ppc64/kernel/mf.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/mf.c	Thu May  2 17:22:17 2002
@@ -1003,7 +1003,7 @@
 		}
 	}
 
-	pci_unmap_single(iSeries_vio_dev, dma_addr, *size, PCI_DMA_FROMDEVICE);
+	pci_unmap_single(iSeries_vio_dev, dma_addr, len, PCI_DMA_FROMDEVICE);
 
 	return rc;
 }
diff -Nru a/arch/ppc64/kernel/mf_proc.c b/arch/ppc64/kernel/mf_proc.c
--- a/arch/ppc64/kernel/mf_proc.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/mf_proc.c	Thu May  2 17:22:16 2002
@@ -71,12 +71,12 @@
 	ent->read_proc = proc_mf_dump_cmdline;
 	ent->write_proc = proc_mf_change_cmdline;
 
-	ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR|S_IWUSR, mf_a);
+	ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf_a);
 	if (!ent) return;
 	ent->nlink = 1;
 	ent->data = (void *)0;
-	ent->read_proc = proc_mf_dump_vmlinux;
 	ent->write_proc = proc_mf_change_vmlinux;
+	ent->read_proc = NULL;
 
 	mf_b = proc_mkdir("B", mf_proc_root);
 	if (!mf_b) return;
@@ -88,12 +88,12 @@
 	ent->read_proc = proc_mf_dump_cmdline;
 	ent->write_proc = proc_mf_change_cmdline;
 
-	ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR|S_IWUSR, mf_b);
+	ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf_b);
 	if (!ent) return;
 	ent->nlink = 1;
 	ent->data = (void *)1;
-	ent->read_proc = proc_mf_dump_vmlinux;
 	ent->write_proc = proc_mf_change_vmlinux;
+	ent->read_proc = NULL;
 
 	mf_c = proc_mkdir("C", mf_proc_root);
 	if (!mf_c) return;
@@ -105,12 +105,12 @@
 	ent->read_proc = proc_mf_dump_cmdline;
 	ent->write_proc = proc_mf_change_cmdline;
 
-	ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR|S_IWUSR, mf_c);
+	ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf_c);
 	if (!ent) return;
 	ent->nlink = 1;
 	ent->data = (void *)2;
-	ent->read_proc = proc_mf_dump_vmlinux;
 	ent->write_proc = proc_mf_change_vmlinux;
+	ent->read_proc = NULL;
 
 	mf_d = proc_mkdir("D", mf_proc_root);
 	if (!mf_d) return;
@@ -122,14 +122,14 @@
 	ent->data = (void *)3;
 	ent->read_proc = proc_mf_dump_cmdline;
 	ent->write_proc = proc_mf_change_cmdline;
-
+#if 0
 	ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR, mf_d);
 	if (!ent) return;
 	ent->nlink = 1;
 	ent->data = (void *)3;
 	ent->read_proc = proc_mf_dump_vmlinux;
 	ent->write_proc = NULL;
-
+#endif
 	ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
 	if (!ent) return;
 	ent->nlink = 1;
@@ -191,20 +191,16 @@
 		if (sizeToGet != 0)
 		{
 			*start = page + off;
-			printk("mf_proc.c: got count %d off %d\n", sizeToGet, (int)off);
 			return sizeToGet;
 		} else {
-			printk("mf_proc.c: eof\n");
 			*eof = 1;
 			return 0;
 		}
 	} else {
-		printk("mf_proc.c: eof\n");
 		*eof = 1;
 		return 0;
 	}
 }
-
 
 int proc_mf_dump_side
 (char *page, char **start, off_t off, int count, int *eof, void *data)
diff -Nru a/arch/ppc64/kernel/mk_defs.c b/arch/ppc64/kernel/mk_defs.c
--- a/arch/ppc64/kernel/mk_defs.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/mk_defs.c	Thu May  2 17:22:16 2002
@@ -30,8 +30,8 @@
 #include <asm/processor.h>
 #include <asm/hardirq.h>
 
-#include <asm/Naca.h>
-#include <asm/Paca.h>
+#include <asm/naca.h>
+#include <asm/paca.h>
 #include <asm/iSeries/ItLpPaca.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/HvLpEvent.h>
@@ -60,44 +60,44 @@
 
 	DEFINE(MM, offsetof(struct task_struct, mm));
 
-	/* Naca */
-	DEFINE(DCACHEL1LINESIZE, offsetof(struct Naca, dCacheL1LineSize));
-        DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct Naca, dCacheL1LogLineSize));
-        DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct Naca, dCacheL1LinesPerPage));
-        DEFINE(ICACHEL1LINESIZE, offsetof(struct Naca, iCacheL1LineSize));
-        DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct Naca, iCacheL1LogLineSize));
-        DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct Naca, iCacheL1LinesPerPage));
-	DEFINE(SLBSIZE, offsetof(struct Naca, slb_size));
-
-	/* Paca */
-        DEFINE(PACA, offsetof(struct Naca, paca));
-        DEFINE(PACA_SIZE, sizeof(struct Paca));
-        DEFINE(PACAPACAINDEX, offsetof(struct Paca, xPacaIndex));
-        DEFINE(PACAPROCSTART, offsetof(struct Paca, xProcStart));
-        DEFINE(PACAKSAVE, offsetof(struct Paca, xKsave));
-	DEFINE(PACACURRENT, offsetof(struct Paca, xCurrent));
-        DEFINE(PACASAVEDMSR, offsetof(struct Paca, xSavedMsr));
-        DEFINE(PACASTABREAL, offsetof(struct Paca, xStab_data.real));
-        DEFINE(PACASTABVIRT, offsetof(struct Paca, xStab_data.virt));
-	DEFINE(PACASTABRR, offsetof(struct Paca, xStab_data.next_round_robin));
-        DEFINE(PACAR1, offsetof(struct Paca, xR1));
-        DEFINE(PACALPQUEUE, offsetof(struct Paca, lpQueuePtr));
-	DEFINE(PACATOC, offsetof(struct Paca, xTOC));
-	DEFINE(PACAEXCSP, offsetof(struct Paca, exception_sp));
-	DEFINE(PACAHRDWINTSTACK, offsetof(struct Paca, xHrdIntStack));
-	DEFINE(PACAPROCENABLED, offsetof(struct Paca, xProcEnabled));
-	DEFINE(PACAHRDWINTCOUNT, offsetof(struct Paca, xHrdIntCount));
-	DEFINE(PACADEFAULTDECR, offsetof(struct Paca, default_decr));
-	DEFINE(PACAPROFENABLED, offsetof(struct Paca, prof_enabled));
-	DEFINE(PACAPROFLEN, offsetof(struct Paca, prof_len));
-	DEFINE(PACAPROFSHIFT, offsetof(struct Paca, prof_shift));
-	DEFINE(PACAPROFBUFFER, offsetof(struct Paca, prof_buffer));
-	DEFINE(PACAPROFSTEXT, offsetof(struct Paca, prof_stext));
-	DEFINE(PACALPPACA, offsetof(struct Paca, xLpPaca));
-        DEFINE(LPPACA, offsetof(struct Paca, xLpPaca));
-        DEFINE(PACAREGSAV, offsetof(struct Paca, xRegSav));
-        DEFINE(PACAEXC, offsetof(struct Paca, exception_stack));
-        DEFINE(PACAGUARD, offsetof(struct Paca, guard));
+	/* naca */
+        DEFINE(PACA, offsetof(struct naca_struct, paca));
+	DEFINE(DCACHEL1LINESIZE, offsetof(struct naca_struct, dCacheL1LineSize));
+        DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize));
+        DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage));
+        DEFINE(ICACHEL1LINESIZE, offsetof(struct naca_struct, iCacheL1LineSize));
+        DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize));
+        DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage));
+	DEFINE(SLBSIZE, offsetof(struct naca_struct, slb_size));
+
+	/* paca */
+        DEFINE(PACA_SIZE, sizeof(struct paca_struct));
+        DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, xPacaIndex));
+        DEFINE(PACAPROCSTART, offsetof(struct paca_struct, xProcStart));
+        DEFINE(PACAKSAVE, offsetof(struct paca_struct, xKsave));
+	DEFINE(PACACURRENT, offsetof(struct paca_struct, xCurrent));
+        DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, xSavedMsr));
+        DEFINE(PACASTABREAL, offsetof(struct paca_struct, xStab_data.real));
+        DEFINE(PACASTABVIRT, offsetof(struct paca_struct, xStab_data.virt));
+	DEFINE(PACASTABRR, offsetof(struct paca_struct, xStab_data.next_round_robin));
+        DEFINE(PACAR1, offsetof(struct paca_struct, xR1));
+        DEFINE(PACALPQUEUE, offsetof(struct paca_struct, lpQueuePtr));
+	DEFINE(PACATOC, offsetof(struct paca_struct, xTOC));
+	DEFINE(PACAEXCSP, offsetof(struct paca_struct, exception_sp));
+	DEFINE(PACAHRDWINTSTACK, offsetof(struct paca_struct, xHrdIntStack));
+	DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, xProcEnabled));
+	DEFINE(PACAHRDWINTCOUNT, offsetof(struct paca_struct, xHrdIntCount));
+	DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr));
+	DEFINE(PACAPROFENABLED, offsetof(struct paca_struct, prof_enabled));
+	DEFINE(PACAPROFLEN, offsetof(struct paca_struct, prof_len));
+	DEFINE(PACAPROFSHIFT, offsetof(struct paca_struct, prof_shift));
+	DEFINE(PACAPROFBUFFER, offsetof(struct paca_struct, prof_buffer));
+	DEFINE(PACAPROFSTEXT, offsetof(struct paca_struct, prof_stext));
+	DEFINE(PACALPPACA, offsetof(struct paca_struct, xLpPaca));
+        DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca));
+        DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav));
+        DEFINE(PACAEXC, offsetof(struct paca_struct, exception_stack));
+        DEFINE(PACAGUARD, offsetof(struct paca_struct, guard));
         DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
         DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
 	DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt));
diff -Nru a/arch/ppc64/kernel/open_pic.c b/arch/ppc64/kernel/open_pic.c
--- a/arch/ppc64/kernel/open_pic.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/open_pic.c	Thu May  2 17:22:17 2002
@@ -47,7 +47,6 @@
 OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
 
 static void openpic_end_irq(unsigned int irq_nr);
-static void openpic_ack_irq(unsigned int irq_nr);
 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
 
 struct hw_interrupt_type open_pic = {
@@ -56,14 +55,13 @@
 	NULL,
 	openpic_enable_irq,
 	openpic_disable_irq,
-	openpic_ack_irq,
+	NULL,
 	openpic_end_irq,
 	openpic_set_affinity
 };
 
 #ifdef CONFIG_SMP
 static void openpic_end_ipi(unsigned int irq_nr);
-static void openpic_ack_ipi(unsigned int irq_nr);
 static void openpic_enable_ipi(unsigned int irq_nr);
 static void openpic_disable_ipi(unsigned int irq_nr);
 
@@ -73,9 +71,9 @@
 	NULL,
 	openpic_enable_ipi,
 	openpic_disable_ipi,
-	openpic_ack_ipi,
+	NULL,
 	openpic_end_ipi,
-	0
+	NULL
 };
 #endif /* CONFIG_SMP */
 
@@ -756,13 +754,6 @@
 				(sense ? OPENPIC_SENSE_LEVEL : 0));
 }
 
-/* No spinlocks, should not be necessary with the OpenPIC
- * (1 register = 1 interrupt and we have the desc lock).
- */
-static void openpic_ack_irq(unsigned int irq_nr)
-{
-}
-
 static void openpic_end_irq(unsigned int irq_nr)
 {
 	if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
@@ -775,10 +766,6 @@
 }
 
 #ifdef CONFIG_SMP
-static void openpic_ack_ipi(unsigned int irq_nr)
-{
-}
-
 static void openpic_end_ipi(unsigned int irq_nr)
 {
 	/* IPIs are marked IRQ_PER_CPU. This has the side effect of
diff -Nru a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c
--- a/arch/ppc64/kernel/pSeries_lpar.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/pSeries_lpar.c	Thu May  2 17:22:17 2002
@@ -31,7 +31,7 @@
 #include <asm/ppcdebug.h>
 #include <asm/pci_dma.h>
 #include <linux/pci.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/tlbflush.h>
 
 /* Status return values */
@@ -219,7 +219,7 @@
 static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum, 
 				unsigned long uaddr, int direction )
 {
-	u64 setTceRc;
+	u64 set_tce_rc;
 	union Tce tce;
 	
 	PPCDBG(PPCDBG_TCE, "build_tce: uaddr = 0x%lx\n", uaddr);
@@ -232,90 +232,35 @@
 	tce.tceBits.readWrite = 1;
 	if ( direction != PCI_DMA_TODEVICE ) tce.tceBits.pciWrite = 1;
 
-	setTceRc = plpar_tce_put((u64)tbl->index, 
+	set_tce_rc = plpar_tce_put((u64)tbl->index, 
 				 (u64)tcenum << 12, 
 				 tce.wholeTce );
-	/* Make sure the update is visible to hardware.
-	 * ToDo: sync after setting *all* the tce's.
-	 */
-	__asm__ __volatile__ ("sync" : : : "memory");
 
-	if(setTceRc) {
-		PPCDBG(PPCDBG_TCE, "setTce failed. rc=%ld\n", setTceRc);
-		PPCDBG(PPCDBG_TCE, "\tindex   = 0x%lx\n", (u64)tbl->index);
-		PPCDBG(PPCDBG_TCE, "\ttcenum  = 0x%lx\n", (u64)tcenum);
-		PPCDBG(PPCDBG_TCE, "\ttce val = 0x%lx\n", tce.wholeTce );
+	if(set_tce_rc) {
+		printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", set_tce_rc);
+		printk("\tindex   = 0x%lx\n", (u64)tbl->index);
+		printk("\ttcenum  = 0x%lx\n", (u64)tcenum);
+		printk("\ttce val = 0x%lx\n", tce.wholeTce );
 	}
 }
 
-static inline void free_tce_range(struct TceTable *tbl, 
-				  long tcenum, unsigned order )
+static void tce_free_one_pSeriesLP(struct TceTable *tbl, long tcenum)
 {
-	unsigned long flags;
-
-	/* Lock the tce allocation bitmap */
-	spin_lock_irqsave( &(tbl->lock), flags );
-
-	/* Do the actual work */
-	free_tce_range_nolock( tbl, tcenum, order );
-	
-	/* Unlock the tce allocation bitmap */
-	spin_unlock_irqrestore( &(tbl->lock), flags );
-
-}
-
-static void tce_free_pSeriesLP(struct TceTable *tbl, dma_addr_t dma_addr, 
-			       unsigned order, unsigned numPages)
-{
-	u64 setTceRc;
-	long tcenum, freeTce, maxTcenum;
-	unsigned i;
+	u64 set_tce_rc;
 	union Tce tce;
 
-	maxTcenum = (tbl->size * (PAGE_SIZE / sizeof(union Tce))) - 1;
-	
-	tcenum = dma_addr >> PAGE_SHIFT;
-
-	freeTce = tcenum - tbl->startOffset;
-
-	if ( freeTce > maxTcenum ) {
-		printk("free_tces: tcenum > maxTcenum\n");
-		printk("\ttcenum    = 0x%lx\n", tcenum); 
-		printk("\tfreeTce   = 0x%lx\n", freeTce); 
-		printk("\tmaxTcenum = 0x%lx\n", maxTcenum); 
-		printk("\tTCE Table = 0x%lx\n", (u64)tbl);
-		printk("\tbus#      = 0x%lx\n", 
-		       (u64)tbl->busNumber );
-		printk("\tsize      = 0x%lx\n", (u64)tbl->size);
-		printk("\tstartOff  = 0x%lx\n", 
-		       (u64)tbl->startOffset );
-		printk("\tindex     = 0x%lx\n", (u64)tbl->index);
-		return;
-	}
-	
-	for (i=0; i<numPages; ++i) {
-		tce.wholeTce = 0;
-		setTceRc = plpar_tce_put((u64)tbl->index, 
-					 (u64)tcenum << 12, /* note: not freeTce */
-					 tce.wholeTce );
-		if ( setTceRc ) {
-			printk("tce_free: setTce failed\n");
-			printk("\trc      = %ld\n", setTceRc);
-			printk("\tindex   = 0x%lx\n", 
-			       (u64)tbl->index);
-			printk("\ttcenum  = 0x%lx\n", (u64)tcenum);
-			printk("\tfreeTce = 0x%lx\n", (u64)freeTce);
-			printk("\ttce val = 0x%lx\n", 
-			       tce.wholeTce );
-		}
-
-		++tcenum;
+	tce.wholeTce = 0;
+	set_tce_rc = plpar_tce_put((u64)tbl->index, 
+				 (u64)tcenum << 12,
+				 tce.wholeTce );
+	if ( set_tce_rc ) {
+		printk("tce_free_one_pSeriesLP: plpar_tce_put failed\n");
+		printk("\trc      = %ld\n", set_tce_rc);
+		printk("\tindex   = 0x%lx\n", (u64)tbl->index);
+		printk("\ttcenum  = 0x%lx\n", (u64)tcenum);
+		printk("\ttce val = 0x%lx\n", tce.wholeTce );
 	}
 
-	/* Make sure the update is visible to hardware. */
-	__asm__ __volatile__ ("sync" : : : "memory");
-
-	free_tce_range( tbl, freeTce, order );
 }
 
 /* PowerPC Interrupts for lpar. */
@@ -446,7 +391,7 @@
 	pSeries_lpar_mm_init();
 
 	ppc_md.tce_build	 = tce_build_pSeriesLP;
-	ppc_md.tce_free		 = tce_free_pSeriesLP;
+	ppc_md.tce_free_one	 = tce_free_one_pSeriesLP;
 
 #ifdef CONFIG_SMP
 	smp_init_pSeries();
diff -Nru a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c
--- a/arch/ppc64/kernel/pSeries_pci.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/pSeries_pci.c	Thu May  2 17:22:17 2002
@@ -39,11 +39,9 @@
 #include <asm/init.h>
 #include <asm/pci-bridge.h>
 #include <asm/ppcdebug.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/pci_dma.h>
-#ifdef CONFIG_PPC_EEH
 #include <asm/eeh.h>
-#endif
 
 #include "xics.h"
 #include "open_pic.h"
@@ -130,7 +128,10 @@
 } \
 int __chrp \
 rtas_pci_write_config_##size(struct pci_dev *dev, int offset, type val) { \
-	return rtas_write_config_##size(pci_device_to_OF_node(dev), offset, val); \
+	struct device_node*  dn = pci_device_to_OF_node(dev); \
+	int  ret = rtas_write_config_##size(dn, offset, val); \
+	/* udbg_printf("write bus=%x, devfn=%x, ret=%d phb=%lx, dn=%lx\n", dev->bus->number, dev->devfn, ret, dn ? dn->phb : 0, dn); */ \
+	return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; \
 }
 
 RTAS_PCI_READ_OP(byte, u8 *, 1)
@@ -256,9 +257,8 @@
 	write_pci_config = rtas_token("write-pci-config");
 	ibm_read_pci_config = rtas_token("ibm,read-pci-config");
 	ibm_write_pci_config = rtas_token("ibm,write-pci-config");
-#ifdef CONFIG_PPC_EEH
+
 	eeh_init();
-#endif
 
 	if (naca->interrupt_controller == IC_OPEN_PIC) {
 		opprop = (unsigned int *)get_property(find_path_device("/"),
@@ -358,24 +358,24 @@
 				res = &phb->io_resource;
 				res->name = Pci_Node->full_name;
 				res->flags = IORESOURCE_IO;
-#ifdef CONFIG_PPC_EEH
-				if (!isa_io_base && has_isa) {
-					/* map a page for ISA ports.  Not EEH protected. */
-					isa_io_base = (unsigned long)__ioremap(phb->io_base_phys, PAGE_SIZE, _PAGE_NO_CACHE);
-				}
-			        res->start = phb->io_base_virt = eeh_token(index, 0, 0, 0);
-				res->end = eeh_token(index, 0xff, 0xff, 0xffffffff);
-#else
-			        phb->io_base_virt = ioremap(phb->io_base_phys, range.size);
-				if (!pci_io_base) {
-					pci_io_base = (unsigned long)phb->io_base_virt;
-					if (has_isa)
-						isa_io_base = pci_io_base;
+				if (is_eeh_implemented()) {
+					if (!isa_io_base && has_isa) {
+						/* map a page for ISA ports.  Not EEH protected. */
+						isa_io_base = (unsigned long)__ioremap(phb->io_base_phys, PAGE_SIZE, _PAGE_NO_CACHE);
+					}
+					res->start = phb->io_base_virt = eeh_token(index, 0, 0, 0);
+					res->end = eeh_token(index, 0xff, 0xff, 0xffffffff);
+				} else {
+					phb->io_base_virt = ioremap(phb->io_base_phys, range.size);
+					if (!pci_io_base) {
+						pci_io_base = (unsigned long)phb->io_base_virt;
+						if (has_isa)
+							isa_io_base = pci_io_base;
+					}
+					res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo));
+					res->start += (unsigned long)phb->io_base_virt;
+					res->end =   res->start + range.size - 1;
 				}
-				res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo));
-				res->start += (unsigned long)phb->io_base_virt;
-				res->end =   res->start + range.size - 1;
-#endif
 				res->parent = NULL;
 				res->sibling = NULL;
 				res->child = NULL;
@@ -399,13 +399,13 @@
 					++memno;
 					res->name = Pci_Node->full_name;
 					res->flags = IORESOURCE_MEM;
-#ifdef CONFIG_PPC_EEH
-					res->start = eeh_token(index, 0, 0, 0);
-					res->end =   eeh_token(index, 0xff, 0xff, 0xffffffff);
-#else
-					res->start = range.parent_addr;
-					res->end =   range.parent_addr + range.size - 1;
-#endif
+					if (is_eeh_implemented()) {
+						res->start = eeh_token(index, 0, 0, 0);
+						res->end =   eeh_token(index, 0xff, 0xff, 0xffffffff);
+					} else {
+						res->start = range.parent_addr;
+						res->end =   range.parent_addr + range.size - 1;
+					}
 					res->parent = NULL;
 					res->sibling = NULL;
 					res->child = NULL;
@@ -521,7 +521,7 @@
 	        phb = pci_alloc_pci_controller("PHB SW",phb_type_speedwagon);
 		if (phb == NULL) return NULL;
 
-		if (_machine == _MACH_pSeries) {
+		if (naca->platform == PLATFORM_PSERIES) {
 			phb->cfg_addr = (volatile unsigned long *) 
 			  ioremap(reg_struct.address + 0x140, PAGE_SIZE);
 			phb->cfg_data = (char*)(phb->cfg_addr - 0x02); /* minus is correct */
@@ -566,14 +566,11 @@
 	phb->ops = &rtas_pci_ops;
 
 	buid_vals = (int *) get_property(dev, "ibm,fw-phb-id", &len);
-	if (buid_vals == NULL || len < 2 * sizeof(int)) {
+	
+  if (buid_vals == NULL) {
 		phb->buid = 0;
-	} else {
-		/* Big bus system.  These systems start new bus numbers under
-		 * each phb.  Until pci domains are standard, we depend on a
-		 * patch which makes bus numbers ints and we shift the phb
-		 * number into the upper bits.
-		 */
+	} 
+  else {
 		struct pci_bus check;
 		if (sizeof(check.number) == 1 || sizeof(check.primary) == 1 ||
 		    sizeof(check.secondary) == 1 || sizeof(check.subordinate) == 1) {
@@ -583,9 +580,14 @@
 			panic("pSeries_pci:  this system has large bus numbers and the kernel was not\n"
 			      "built with the patch that fixes include/linux/pci.h struct pci_bus so\n"
 			      "number, primary, secondary and subordinate are ints.\n");
-		}
-		phb->buid = (((unsigned long)buid_vals[0]) << 32UL) |
-			(((unsigned long)buid_vals[1]) & 0xffffffff);
+    }
+    
+    if (len < 2 * sizeof(int))
+      phb->buid = (unsigned long)buid_vals[0];  // Support for new OF that only has 1 integer for buid.
+    else
+      phb->buid = (((unsigned long)buid_vals[0]) << 32UL) |
+                  (((unsigned long)buid_vals[1]) & 0xffffffff);
+  	
 		phb->first_busno += (phb->global_number << 8);
 		phb->last_busno += (phb->global_number << 8);
 	}
@@ -601,7 +603,6 @@
 {
  	int i;
  	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
-#ifdef CONFIG_PPC_EEH
 	struct device_node *dn;
 	unsigned long eeh_disable_bit;
 
@@ -620,19 +621,19 @@
 		}
 	}
 
-	if (is_eeh_configured(dev)) {
-		eeh_disable_bit = 0;
-		printk("PCI: eeh configured for %s %s\n", dev->slot_name, dev->name);
-		if (eeh_set_option(dev, EEH_ENABLE) != 0) {
-			printk("PCI: failed to enable eeh for %s %s\n", dev->slot_name, dev->name);
+	if (is_eeh_implemented()) {
+		if (is_eeh_configured(dev)) {
+			eeh_disable_bit = 0;
+			if (eeh_set_option(dev, EEH_ENABLE) != 0) {
+				printk("PCI: failed to enable EEH for %s %s\n", dev->slot_name, dev->name);
+				eeh_disable_bit = EEH_TOKEN_DISABLED;
+			}
+		} else {
+			/* Assume device is by default EEH_DISABLE'd */
+			printk("PCI: eeh NOT configured for %s %s\n", dev->slot_name, dev->name);
 			eeh_disable_bit = EEH_TOKEN_DISABLED;
 		}
-	} else {
-		/* Assume device is by default EEH_DISABLE'd */
-		printk("PCI: eeh NOT configured for %s %s\n", dev->slot_name, dev->name);
-		eeh_disable_bit = EEH_TOKEN_DISABLED;
 	}
-#endif
 
 	PPCDBG(PPCDBG_PHBINIT, "fixup_resources:\n"); 
 	PPCDBG(PPCDBG_PHBINIT, "\tphb                 = 0x%016LX\n", phb); 
@@ -657,19 +658,19 @@
 		}
 
 		if (dev->resource[i].flags & IORESOURCE_IO) {
-#ifdef CONFIG_PPC_EEH
-			unsigned int busno = dev->bus ? dev->bus->number : 0;
-			unsigned long size = dev->resource[i].end - dev->resource[i].start;
-			unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->io_base_phys, size, _PAGE_NO_CACHE);
-			if (!addr)
-				panic("fixup_resources: ioremap failed!\n");
-			dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
-			dev->resource[i].end = dev->resource[i].start + size;
-#else
-			unsigned long offset = (unsigned long)phb->io_base_virt;
-			dev->resource[i].start += offset;
-			dev->resource[i].end += offset;
-#endif
+			if (is_eeh_implemented()) {
+				unsigned int busno = dev->bus ? dev->bus->number : 0;
+				unsigned long size = dev->resource[i].end - dev->resource[i].start;
+				unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->io_base_phys, size, _PAGE_NO_CACHE);
+				if (!addr)
+					panic("fixup_resources: ioremap failed!\n");
+				dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
+				dev->resource[i].end = dev->resource[i].start + size;
+			} else {
+				unsigned long offset = (unsigned long)phb->io_base_virt;
+				dev->resource[i].start += offset;
+				dev->resource[i].end += offset;
+			}
 			PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx .. %lx]\n",
 			       dev->resource[i].start, dev->resource[i].end);
 		} else if (dev->resource[i].flags & IORESOURCE_MEM) {
@@ -677,18 +678,18 @@
 				/* Bogus.  Probably an unused bridge. */
 				dev->resource[i].end = 0;
 			} else {
-#ifdef CONFIG_PPC_EEH
-				unsigned int busno = dev->bus ? dev->bus->number : 0;
-				unsigned long size = dev->resource[i].end - dev->resource[i].start;
-				unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->pci_mem_offset, size, _PAGE_NO_CACHE);
-				if (!addr)
-					panic("fixup_resources: ioremap failed!\n");
-				dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
-				dev->resource[i].end = dev->resource[i].start + size;
-#else
-				dev->resource[i].start += phb->pci_mem_offset;
-				dev->resource[i].end += phb->pci_mem_offset;
-#endif
+				if (is_eeh_implemented()) {
+					unsigned int busno = dev->bus ? dev->bus->number : 0;
+					unsigned long size = dev->resource[i].end - dev->resource[i].start;
+					unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->pci_mem_offset, size, _PAGE_NO_CACHE);
+					if (!addr)
+						panic("fixup_resources: ioremap failed!\n");
+					dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
+					dev->resource[i].end = dev->resource[i].start + size;
+				} else {
+					dev->resource[i].start += phb->pci_mem_offset;
+					dev->resource[i].end += phb->pci_mem_offset;
+				}
 			}
 			PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx..%lx]\n",
 			       dev->resource[i].start, dev->resource[i].end);
diff -Nru a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c
--- a/arch/ppc64/kernel/pacaData.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/pacaData.c	Thu May  2 17:22:16 2002
@@ -7,7 +7,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#define __KERNEL__ 1
 #include <asm/types.h>
 #include <asm/page.h>
 #include <stddef.h>
@@ -17,8 +16,10 @@
 #include <asm/ptrace.h>
 
 #include <asm/iSeries/ItLpPaca.h>
-#include <asm/Paca.h>
+#include <asm/naca.h>
+#include <asm/paca.h>
 
+struct naca_struct *naca;
 
 /* The Paca is an array with one entry per processor.  Each contains an 
  * ItLpPaca, which contains the information shared between the 
@@ -32,8 +33,8 @@
  */
 #define PACAINITDATA(number,start,lpq,asrr,asrv) \
 {                                                                          \
-        xLpPacaPtr: &xPaca[number].xLpPaca,                                 \
-        xLpRegSavePtr: &xPaca[number].xRegSav,                              \
+        xLpPacaPtr: &paca[number].xLpPaca,                                 \
+        xLpRegSavePtr: &paca[number].xRegSav,                              \
         xPacaIndex: (number),           /* Paca Index        */             \
         default_decr: 0x00ff0000,       /* Initial Decr      */             \
         xStab_data: {                                                       \
@@ -59,10 +60,10 @@
                 xSize: sizeof(struct ItLpRegSave)                           \
         },                                                                  \
         exception_sp:                                                       \
-                (&xPaca[number].exception_stack[0]) - EXC_FRAME_SIZE,       \
+                (&paca[number].exception_stack[0]) - EXC_FRAME_SIZE,       \
 }
 
-struct Paca xPaca[maxPacas] __page_aligned = {
+struct paca_struct paca[MAX_PACAS] __page_aligned = {
 #ifdef CONFIG_PPC_ISERIES
 	PACAINITDATA( 0, 1, &xItLpQueue, 0, 0xc000000000005000),
 #else
diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
--- a/arch/ppc64/kernel/pci.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/pci.c	Thu May  2 17:22:16 2002
@@ -30,12 +30,10 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/ppcdebug.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/pci_dma.h>
 #include <asm/machdep.h>
-#ifdef CONFIG_PPC_EEH
 #include <asm/eeh.h>
-#endif
 
 #include "pci.h"
 
@@ -61,14 +59,12 @@
 void   iSeries_pcibios_init(void);
 void   pSeries_pcibios_init(void);
 
-
-extern struct Naca *naca;
-
-int pci_assign_all_busses = 0;
-
+int    pci_assign_all_busses = 0;
 struct pci_controller* hose_head;
 struct pci_controller** hose_tail = &hose_head;
 
+LIST_HEAD(iSeries_Global_Device_List);
+
 /*******************************************************************
  * Counters and control flags. 
  *******************************************************************/
@@ -517,7 +513,6 @@
 {
 	struct pci_controller *phb = PCI_GET_PHB_PTR(bus);
 	struct resource *res;
-	unsigned long io_offset;
 	int i;
 
 #ifndef CONFIG_PPC_ISERIES
@@ -549,23 +544,23 @@
 				/* Transparent resource -- don't try to "fix" it. */
 				continue;
 			}
-#ifdef CONFIG_PPC_EEH
-			if (res->flags & (IORESOURCE_IO|IORESOURCE_MEM)) {
-				res->start = eeh_token(phb->global_number, bus->number, 0, 0);
-				res->end = eeh_token(phb->global_number, bus->number, 0xff, 0xffffffff);
-			}
-#else
-			if (res->flags & IORESOURCE_IO) {
-				res->start += (unsigned long)phb->io_base_virt;
-				res->end += (unsigned long)phb->io_base_virt;
-			} else if (phb->pci_mem_offset
-				   && (res->flags & IORESOURCE_MEM)) {
-				if (res->start < phb->pci_mem_offset) {
-					res->start += phb->pci_mem_offset;
-					res->end += phb->pci_mem_offset;
+			if (is_eeh_implemented()) {
+				if (res->flags & (IORESOURCE_IO|IORESOURCE_MEM)) {
+					res->start = eeh_token(phb->global_number, bus->number, 0, 0);
+					res->end = eeh_token(phb->global_number, bus->number, 0xff, 0xffffffff);
+				}
+			} else {
+				if (res->flags & IORESOURCE_IO) {
+					res->start += (unsigned long)phb->io_base_virt;
+					res->end += (unsigned long)phb->io_base_virt;
+				} else if (phb->pci_mem_offset
+					   && (res->flags & IORESOURCE_MEM)) {
+					if (res->start < phb->pci_mem_offset) {
+						res->start += phb->pci_mem_offset;
+						res->end += phb->pci_mem_offset;
+					}
 				}
 			}
-#endif
 		}
 	}
 #endif	
@@ -584,7 +579,7 @@
 	int idx;
 	struct resource *r;
 
-	PPCDBG(PPCDBG_BUSWALK,"PCI: "__FUNCTION__" for device %s \n",dev->slot_name);
+	PPCDBG(PPCDBG_BUSWALK,"PCI: %s for device %s \n",__FUNCTION__,dev->slot_name);
 	if (ppc_md.pcibios_enable_device_hook)
 		if (ppc_md.pcibios_enable_device_hook(dev, 0))
 			return -EINVAL;
diff -Nru a/arch/ppc64/kernel/pci_dma.c b/arch/ppc64/kernel/pci_dma.c
--- a/arch/ppc64/kernel/pci_dma.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/pci_dma.c	Thu May  2 17:22:17 2002
@@ -43,7 +43,9 @@
 
 #include "pci.h"
 
-// #define DEBUG_TCE 1
+/* #define DEBUG_TCE 1   */
+/* #define MONITOR_TCE 1 */ /* Turn on to sanity check TCE generation. */
+
 
 /* Initialize so this guy does not end up in the BSS section.
  * Only used to pass OF initialization data set in prom.c into the main 
@@ -53,12 +55,13 @@
 
 extern struct pci_controller* hose_head;
 extern struct pci_controller** hose_tail;
+extern struct list_head iSeries_Global_Device_List;
 
 struct TceTable   virtBusVethTceTable;	/* Tce table for virtual ethernet */
 struct TceTable   virtBusVioTceTable;	/* Tce table for virtual I/O */
 
-struct device_node iSeries_veth_dev_node = { tce_table: &virtBusVethTceTable };
-struct device_node iSeries_vio_dev_node  = { tce_table: &virtBusVioTceTable };
+struct iSeries_Device_Node iSeries_veth_dev_node = { LogicalSlot: 0xFF, DevTceTable: &virtBusVethTceTable };
+struct iSeries_Device_Node iSeries_vio_dev_node  = { LogicalSlot: 0xFF, DevTceTable: &virtBusVioTceTable };
 
 struct pci_dev    iSeries_veth_dev_st = { sysdata: &iSeries_veth_dev_node };
 struct pci_dev    iSeries_vio_dev_st  = { sysdata: &iSeries_vio_dev_node  };
@@ -66,7 +69,8 @@
 struct pci_dev  * iSeries_veth_dev = &iSeries_veth_dev_st;
 struct pci_dev  * iSeries_vio_dev  = &iSeries_vio_dev_st;
 
-struct TceTable * tceTables[256];	/* Tce tables for 256 busses
+/* Device TceTable is stored in Device Node */
+/* struct TceTable * tceTables[256]; */	/* Tce tables for 256 busses
 					 * Bus 255 is the virtual bus
 					 * zero indicates no bus defined
 					 */
@@ -103,18 +107,8 @@
 			    long tcenum, 
 			    unsigned order );
 
-static unsigned fill_scatterlist_sg(struct scatterlist *sg, int nents, 
-				    dma_addr_t dma_addr, 
-				    unsigned long numTces );
-
-static unsigned long num_tces_sg( struct scatterlist *sg, 
-				  int nents );
-	
-static dma_addr_t create_tces_sg( struct TceTable *tbl, 
-				  struct scatterlist *sg, 
-			 	  int nents, 
-				  unsigned numTces,
-				  int direction );
+static void getTceTableParmsiSeries(struct iSeries_Device_Node* DevNode,
+				      struct TceTable *tce_table_parms );
 
 static void getTceTableParmsPSeries( struct pci_controller *phb, 
 				     struct device_node *dn,
@@ -124,6 +118,8 @@
 				    struct device_node *dn,
 				    struct TceTable *newTceTable );
 
+static struct TceTable* findHwTceTable(struct TceTable * newTceTable );
+
 void create_pci_bus_tce_table( unsigned long token );
 
 u8 iSeries_Get_Bus( struct pci_dev * dv )
@@ -137,11 +133,11 @@
 		dev = ppc64_isabridge_dev;
 	if (!dev)
 		return NULL;
-	if ( ( _machine == _MACH_iSeries ) && ( dev->bus ) ) 
-		return tceTables[dev->bus->number];
-	/* On the iSeries, the virtual bus will take this path.  There is a */
-	/* fake pci_dev and dev_node built and used.                        */
-	return PCI_GET_DN(dev)->tce_table;
+	if (naca->platform == PLATFORM_ISERIES_LPAR) {
+ 		return ISERIES_DEVNODE(dev)->DevTceTable;
+	} else {
+		return PCI_GET_DN(dev)->tce_table;
+	}
 }
 
 static unsigned long __inline__ count_leading_zeros64( unsigned long x )
@@ -180,13 +176,8 @@
 	setTceRc = HvCallXm_setTce((u64)tbl->index, 
 				   (u64)tcenum, 
 				   tce.wholeTce );
-
 	if(setTceRc) {
-		printk("PCI: tce_build failed 0x%lx tcenum: 0x%lx\n", setTceRc, (u64)tcenum);
-		//PPCDBG(PPCDBG_TCE, "setTce failed. rc=%ld\n", setTceRc);
-		//PPCDBG(PPCDBG_TCE, "\tindex   = 0x%lx\n", (u64)tbl->index);
-		//PPCDBG(PPCDBG_TCE, "\ttce num = 0x%lx\n", (u64)tcenum);
-		//PPCDBG(PPCDBG_TCE, "\ttce val = 0x%lx\n", tce.wholeTce );
+		panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", setTceRc);
 	}
 }
 
@@ -209,8 +200,6 @@
 	tce_addr = ((union Tce *)tbl->base) + tcenum;
 	*tce_addr = (union Tce)tce.wholeTce;
 
-	/* Make sure the update is visible to hardware. */
-	__asm__ __volatile__ ("sync" : : : "memory");
 }
 
 /* 
@@ -245,18 +234,18 @@
 	}
 	PPCDBG(PPCDBG_TCEINIT, "build_tce_table: totalBytes=%ld\n", totalBytes );
 	
-	pos = (char *)__get_free_pages( GFP_ATOMIC, get_order( totalBytes )); 
-	if ( !pos )
-		return NULL;
+	pos = (char *)__get_free_pages( GFP_ATOMIC, get_order( totalBytes ));
+ 
+	if ( pos == NULL ) {
+		panic("PCI_DMA: Allocation failed in build_tce_table!\n");
+	}
 
-	memset( pos, 0, totalBytes );
-	
 	/* For each level, fill in the pointer to the bit map,
 	 * and turn on the last bit in the bit map (if the
 	 * number of bits in the map is odd).  The highest
 	 * level will get all of its bits turned on.
 	 */
-	
+	memset( pos, 0, totalBytes );
 	for (i=0; i<NUM_TCE_LEVELS; ++i) {
 		if ( numBytes[i] ) {
 			tbl->mlbm.level[i].map = pos;
@@ -333,9 +322,9 @@
 	 * biggest, indicate failure
 	 */
 	if(order >= NUM_TCE_LEVELS) {
-		PPCDBG(PPCDBG_TCE,
-		       "alloc_tce_range_nolock: invalid order: %d\n", order );
-		return -1;
+		/* This can happen if block of TCE's are not found. This code      */
+		/*  maybe in a recursive loop looking up the bit map for the range.*/
+		panic("PCI_DMA: alloc_tce_range_nolock: invalid order: %d\n",order);
 	}
 	
 	numBits =  tbl->mlbm.level[order].numBits;
@@ -352,7 +341,7 @@
 			 * number (of this size)
 			 */
 			bit = count_leading_zeros64( *map );
-			block = (i * 64) + bit;
+			block = (i * 64) + bit;    /* Bit count to free entry */
 
 			/* turn off the bit in the map to indicate
 			 * that the block is now in use
@@ -373,10 +362,12 @@
 #ifdef DEBUG_TCE
 	if ( tcenum == -1 ) {
 		PPCDBG(PPCDBG_TCE, "alloc_tce_range_nolock: no available blocks of order = %d\n", order );
-		if ( order < tbl->mlbm.maxLevel )
+		if ( order < tbl->mlbm.maxLevel ) {
 			PPCDBG(PPCDBG_TCE, "alloc_tce_range_nolock: trying next bigger size\n" );
-		else
-			PPCDBG(PPCDBG_TCE, "alloc_tce_range_nolock: maximum size reached...failing\n");
+		}
+		else {
+			panic("PCI_DMA: alloc_tce_range_nolock: maximum size reached...failing\n");
+		}
 	}
 #endif	
 	
@@ -395,7 +386,6 @@
 	 * (or -1 if we failed)
 	 */
 	return tcenum;
-	
 }
 
 static inline void free_tce_range(struct TceTable *tbl, 
@@ -422,37 +412,25 @@
 	unsigned char  * map, * bytep;
 
 	if (order >= NUM_TCE_LEVELS) {
-		PPCDBG(PPCDBG_TCE, 
-		       "free_tce_range: invalid order: %d, tcenum = %d\n", 
-		       order, tcenum );
+		panic("PCI_DMA: free_tce_range: invalid order: 0x%x\n",order);
 		return;
 	}
 
 	block = tcenum >> order;
 
-#ifdef DEBUG_TCE
+#ifdef MONITOR_TCE
 	if ( tcenum != (block << order ) ) {
-		PPCDBG(PPCDBG_TCE, 
-		       "free_tce_range: tcenum %lx misaligned for order %x\n",
-		       tcenum, order );
+		printk("PCI_DMA: Free_tce_range: tcenum %lx misaligned for order %x\n",tcenum, order);
 		return;
 	}
-
-
 	if ( block >= tbl->mlbm.level[order].numBits ) {
-		PPCDBG(PPCDBG_TCE, 
-		       "free_tce_range: tcenum %lx is outside the range of this map (order %x, numBits %lx\n", 
+		printk("PCI_DMA: Free_tce_range: tcenum %lx is outside the range of this map (order %x, numBits %lx\n", 
 		       tcenum, order, tbl->mlbm.level[order].numBits );
 		return;
 	}
-
-
 	if ( test_tce_range( tbl, tcenum, order ) ) {
-		PPCDBG(PPCDBG_TCE, 
-		       "free_tce_range: freeing range not allocated.\n");
-		PPCDBG(PPCDBG_TCE, 
-		       "\tTceTable %p, tcenum %lx, order %x\n", 
-		       tbl, tcenum, order );
+		printk("PCI_DMA: Freeing range not allocated: tTceTable %p, tcenum %lx, order %x\n",tbl, tcenum, order );
+		return;
 	}
 #endif
 
@@ -463,13 +441,14 @@
 	bytep = map + byte;
 
 #ifdef DEBUG_TCE
-	PPCDBG(PPCDBG_TCE, 
-	       "free_tce_range_nolock: freeing block %ld (byte=%d, bit=%d) of order %d\n",
+	PPCDBG(PPCDBG_TCE,"free_tce_range_nolock: freeing block %ld (byte=%d, bit=%d) of order %d\n",
 	       block, byte, bit, order);
-	if ( *bytep & mask )
-		PPCDBG(PPCDBG_TCE, 
-		       "free_tce_range: already free: TceTable %p, tcenum %lx, order %x\n", 
-		       tbl, tcenum, order );
+#endif	
+
+#ifdef MONITOR_TCE
+	if ( *bytep & mask ) {
+		panic("PCI_DMA: Tce already free: TceTable %p, tcenum %lx, order %x\n",tbl,tcenum,order);
+	}
 #endif	
 
 	*bytep |= mask;
@@ -481,7 +460,8 @@
 	 *      we are freeing the last block we can't buddy up
 	 * Don't buddy up if it's in the first 1/4 of the level
 	 */
-	if (( block > (tbl->mlbm.level[order].numBits/4) ) &&
+	if (( order < tbl->mlbm.maxLevel ) &&
+	    ( block > (tbl->mlbm.level[order].numBits/4) ) &&
 	    (( block < tbl->mlbm.level[order].numBits-1 ) ||
 	      ( 0 == ( tbl->mlbm.level[order].numBits & 1)))) {
 		/* See if we can buddy up the block we just freed */
@@ -555,101 +535,78 @@
 			++tcenum;
 			uaddr += PAGE_SIZE;
 		}
+		/* Make sure the update is visible to hardware. 
+		   sync required to synchronize the update to 
+		   the TCE table with the MMIO that will send
+		   the bus address to the IOA */
+		__asm__ __volatile__ ("sync" : : : "memory");
 	}
-	else
-		PPCDBG(PPCDBG_TCE, "alloc_tce_range failed\n");
+	else {
+		panic("PCI_DMA: Tce Allocation failure in get_tces. 0x%p\n",tbl);
+	}
+
 	return retTce; 
 }
 
-static void tce_free_iSeries(struct TceTable *tbl, dma_addr_t dma_addr, 
-			     unsigned order, unsigned numPages)
+static void tce_free_one_iSeries( struct TceTable *tbl, long tcenum )
 {
-	u64 setTceRc;
-	long tcenum, freeTce, maxTcenum;
-	unsigned i;
+	u64 set_tce_rc;
 	union Tce tce;
+	tce.wholeTce = 0;
+	set_tce_rc = HvCallXm_setTce((u64)tbl->index,
+				   (u64)tcenum,
+				   tce.wholeTce);
+	if ( set_tce_rc ) 
+		panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", set_tce_rc);
 
-	maxTcenum = (tbl->size * (PAGE_SIZE / sizeof(union Tce))) - 1;
-	
-	tcenum = dma_addr >> PAGE_SHIFT;
+}
 
-	freeTce = tcenum - tbl->startOffset;
+static void tce_free_one_pSeries( struct TceTable *tbl, long tcenum )
+{
+	union Tce tce;
+	union Tce *tce_addr;
 
-	if ( freeTce > maxTcenum ) {
-		PPCDBG(PPCDBG_TCE, "free_tces: tcenum > maxTcenum\n");
-		PPCDBG(PPCDBG_TCE, "\ttcenum    = 0x%lx\n", tcenum); 
-		PPCDBG(PPCDBG_TCE, "\tmaxTcenum = 0x%lx\n", maxTcenum); 
-		PPCDBG(PPCDBG_TCE, "\tTCE Table = 0x%lx\n", (u64)tbl);
-		PPCDBG(PPCDBG_TCE, "\tbus#      = 0x%lx\n", (u64)tbl->busNumber );
-		PPCDBG(PPCDBG_TCE, "\tsize      = 0x%lx\n", (u64)tbl->size);
-		PPCDBG(PPCDBG_TCE, "\tstartOff  = 0x%lx\n", (u64)tbl->startOffset );
-		PPCDBG(PPCDBG_TCE, "\tindex     = 0x%lx\n", (u64)tbl->index);
-		return;
-	}
-	
-	for (i=0; i<numPages; ++i) {
-		tce.wholeTce = 0;
-		setTceRc = HvCallXm_setTce((u64)tbl->index, 
-					   (u64)tcenum, 
-					   tce.wholeTce );
-
-		if ( setTceRc ) {
-			printk("PCI: tce_free failed 0x%lx tcenum: 0x%lx\n", setTceRc, (u64)tcenum);
-			//PPCDBG(PPCDBG_TCE, "tce_free: setTce failed\n");
-			//PPCDBG(PPCDBG_TCE, "\trc      = 0x%lx\n", setTceRc);
-			//PPCDBG(PPCDBG_TCE, "\tindex   = 0x%lx\n", (u64)tbl->index);
-			//PPCDBG(PPCDBG_TCE, "\ttce num = 0x%lx\n", (u64)tcenum);
-			//PPCDBG(PPCDBG_TCE, "\ttce val = 0x%lx\n", tce.wholeTce );
-		}
+	tce.wholeTce = 0;
 
-		++tcenum;
-	}
+	tce_addr  = ((union Tce *)tbl->base) + tcenum;
+	*tce_addr = (union Tce)tce.wholeTce;
 
-	free_tce_range( tbl, freeTce, order );
 }
 
-static void tce_free_pSeries(struct TceTable *tbl, dma_addr_t dma_addr, 
-			     unsigned order, unsigned numPages)
+static void tce_free(struct TceTable *tbl, dma_addr_t dma_addr, 
+			     unsigned order, unsigned num_pages)
 {
-	long tcenum, freeTce, maxTcenum;
+	long tcenum, total_tces, free_tce;
 	unsigned i;
-	union Tce tce;
-	union Tce *tce_addr;
 
-	maxTcenum = (tbl->size * (PAGE_SIZE / sizeof(union Tce))) - 1;
+	total_tces = (tbl->size * (PAGE_SIZE / sizeof(union Tce)));
 	
 	tcenum = dma_addr >> PAGE_SHIFT;
-	// tcenum -= tbl->startOffset;
+	free_tce = tcenum - tbl->startOffset;
 
-	freeTce = tcenum - tbl->startOffset;
-
-	if ( freeTce > maxTcenum ) {
-		PPCDBG(PPCDBG_TCE, "free_tces: tcenum > maxTcenum\n");
-		PPCDBG(PPCDBG_TCE, "\ttcenum    = 0x%lx\n", tcenum); 
-		PPCDBG(PPCDBG_TCE, "\tmaxTcenum = 0x%lx\n", maxTcenum); 
-		PPCDBG(PPCDBG_TCE, "\tTCE Table = 0x%lx\n", (u64)tbl);
-		PPCDBG(PPCDBG_TCE, "\tbus#      = 0x%lx\n", 
-		       (u64)tbl->busNumber );
-		PPCDBG(PPCDBG_TCE, "\tsize      = 0x%lx\n", (u64)tbl->size);
-		PPCDBG(PPCDBG_TCE, "\tstartOff  = 0x%lx\n", 
-		       (u64)tbl->startOffset );
-		PPCDBG(PPCDBG_TCE, "\tindex     = 0x%lx\n", (u64)tbl->index);
+	if ( ( (free_tce + num_pages) > total_tces ) ||
+	     ( tcenum < tbl->startOffset ) ) {
+		printk("tce_free: invalid tcenum\n");
+		printk("\ttcenum    = 0x%lx\n", tcenum); 
+		printk("\tTCE Table = 0x%lx\n", (u64)tbl);
+		printk("\tbus#      = 0x%lx\n", (u64)tbl->busNumber );
+		printk("\tsize      = 0x%lx\n", (u64)tbl->size);
+		printk("\tstartOff  = 0x%lx\n", (u64)tbl->startOffset );
+		printk("\tindex     = 0x%lx\n", (u64)tbl->index);
 		return;
 	}
 	
-	for (i=0; i<numPages; ++i) {
-		tce.wholeTce = 0;
-
-		tce_addr  = ((union Tce *)tbl->base) + tcenum;
-		*tce_addr = (union Tce)tce.wholeTce;
-
+	for (i=0; i<num_pages; ++i) {
+		ppc_md.tce_free_one(tbl, tcenum);
 		++tcenum;
 	}
 
-	/* Make sure the update is visible to hardware. */
-	__asm__ __volatile__ ("sync" : : : "memory");
+	/* No sync (to make TCE change visible) is required here.
+	   The lwsync when acquiring the lock in free_tce_range
+	   is sufficient to synchronize with the bitmap.
+	*/
 
-	free_tce_range( tbl, freeTce, order );
+	free_tce_range( tbl, free_tce, order );
 }
 
 void __init create_virtual_bus_tce_table(void)
@@ -679,7 +636,8 @@
 
 	t = build_tce_table( &virtBusVethTceTable );
 	if ( t ) {
-		tceTables[255] = t;
+		/* tceTables[255] = t; */
+		//VirtBusVethTceTable = t;
 		printk( "Virtual Bus VETH TCE table built successfully.\n");
 		printk( "  TCE table size = %ld entries\n", 
 				(unsigned long)t->size*(PAGE_SIZE/sizeof(union Tce)) );
@@ -688,11 +646,11 @@
 		printk( "  TCE table start entry = 0x%lx\n",
 				(unsigned long)t->startOffset );
 	}
-	else 
-		printk( "Virtual Bus VETH TCE table failed.\n");
+	else printk( "Virtual Bus VETH TCE table failed.\n");
 
 	t = build_tce_table( &virtBusVioTceTable );
 	if ( t ) {
+		//VirtBusVioTceTable = t;
 		printk( "Virtual Bus VIO TCE table built successfully.\n");
 		printk( "  TCE table size = %ld entries\n", 
 				(unsigned long)t->size*(PAGE_SIZE/sizeof(union Tce)) );
@@ -701,8 +659,7 @@
 		printk( "  TCE table start entry = 0x%lx\n",
 				(unsigned long)t->startOffset );
 	}
-	else 
-		printk( "Virtual Bus VIO TCE table failed.\n");
+	else printk( "Virtual Bus VIO TCE table failed.\n");
 }
 
 void create_tce_tables_for_buses(struct list_head *bus_list)
@@ -765,11 +722,12 @@
 	struct pci_dev *dev;
 	struct device_node *dn, *mydn;
 
-	if (_machine == _MACH_pSeriesLP)
+	if (naca->platform == PLATFORM_PSERIES_LPAR) {
 		create_tce_tables_for_busesLP(&pci_root_buses);
-	else
-	create_tce_tables_for_buses(&pci_root_buses);
-
+	}
+	else {
+		create_tce_tables_for_buses(&pci_root_buses);
+	}
 	/* Now copy the tce_table ptr from the bus devices down to every
 	 * pci device_node.  This means get_tce_table() won't need to search
 	 * up the device tree to find it.
@@ -784,95 +742,134 @@
 	}
 }
 
+
 /*
- * iSeries token = busNumber 
+ * iSeries token = iSeries_device_Node*
  * pSeries token = pci_controller*
+ *
  */
 void create_pci_bus_tce_table( unsigned long token ) {
-	struct TceTable * builtTceTable;
 	struct TceTable * newTceTable;
-	struct TceTableManagerCB pciBusTceTableParms;
-	u64 parmsPtr;
 
 	PPCDBG(PPCDBG_TCE, "Entering create_pci_bus_tce_table.\n");
 	PPCDBG(PPCDBG_TCE, "\ttoken = 0x%lx\n", token);
 
-	newTceTable = kmalloc( sizeof(struct TceTable), GFP_KERNEL );
-
-	if(_machine == _MACH_iSeries) {
-		if ( token > 254 ) {
-			printk("PCI: Bus TCE table failed, invalid bus number %lu\n", token );
-			return;
-		}
+	newTceTable = (struct TceTable *)kmalloc( sizeof(struct TceTable), GFP_KERNEL );
 
-		pciBusTceTableParms.busNumber = token;
-		pciBusTceTableParms.virtualBusFlag = 0; 
-		parmsPtr = virt_to_absolute( (u64)&pciBusTceTableParms );
-
-		/* 
-		 * Call HV with the architected data structure to get TCE table
-		 * info. Put the returned data into the Linux representation
-		 * of the TCE table data.
-		 */
-		HvCallXm_getTceTableParms( parmsPtr );
-		printk("PCI: getTceTableParms: Bus: 0x%lx Size: 0x%lx, Start: 0x%lx, Index: 0x%lx\n",
-		       pciBusTceTableParms.busNumber,
-		       pciBusTceTableParms.size,
-		       pciBusTceTableParms.startOffset,
-		       pciBusTceTableParms.index);
-
-		/* Determine if the table identified by the index and startOffset      */
-		/* returned by the hypervisor for this bus has already been created.   */
-		/* If so, set the tceTable entry to point to the linux shared tceTable.*/ 
-		int BusIndex;
-		for ( BusIndex=0; BusIndex<255; ++BusIndex) {
-			if (tceTables[BusIndex] != NULL) { 
-				struct TceTable* CmprTceTable = tceTables[BusIndex];
-				if ( ( CmprTceTable->index       == pciBusTceTableParms.index ) &&
-				     ( CmprTceTable->startOffset == pciBusTceTableParms.startOffset ) ) {
-					tceTables[token] = CmprTceTable;
-					printk("PCI: Bus %lu Shares a TCE table with bus %d\n",token,BusIndex);
-					break;
-				}
-			}
-		}	
-		/* No shared table, build a new table for this bus. */
-		if (tceTables[token] == NULL) {
-			newTceTable->size = pciBusTceTableParms.size;
-			newTceTable->busNumber = pciBusTceTableParms.busNumber;
-			newTceTable->startOffset = pciBusTceTableParms.startOffset;
-			newTceTable->index = pciBusTceTableParms.index;
-
-			builtTceTable = build_tce_table( newTceTable );
-			builtTceTable->tceType = TCE_PCI;
-			tceTables[token] = builtTceTable;
+	/*****************************************************************/
+ 	/* For the iSeries machines, the HvTce Table can be one of three */
+ 	/* flavors,                                                      */
+ 	/* - Single bus TCE table,                                       */
+ 	/* - Tce Table Share between buses,                              */
+ 	/* - Tce Table per logical slot.                                 */
+	/*****************************************************************/
+	if(naca->platform == PLATFORM_ISERIES_LPAR) {
+
+		struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)token;
+		getTceTableParmsiSeries(DevNode,newTceTable);
+
+		/* Look for existing TCE table for this device.          */
+		DevNode->DevTceTable = findHwTceTable(newTceTable );
+		if( DevNode->DevTceTable == NULL) {
+			DevNode->DevTceTable = build_tce_table( newTceTable );
 		}
 		else {
-		    /* We're using the shared table, not this new one. */
+		    /* We're using a shared table, free this new one.    */
 		    kfree(newTceTable);
 		}
-		    
-		printk("PCI: Pci bus %lu TceTable: %p\n",token,tceTables[token]);
+		printk("Pci Device 0x%p TceTable: %p\n",DevNode,DevNode->DevTceTable);
  		return;
-	} else {
+	}
+	/* pSeries Leg */
+	else {
 		struct device_node *dn;
 		struct pci_controller *phb;
 
 		dn = (struct device_node *)token;
 		phb = dn->phb;
-		if (_machine == _MACH_pSeries)
+		if (naca->platform == PLATFORM_PSERIES)
 			getTceTableParmsPSeries(phb, dn, newTceTable);
 		else
 			getTceTableParmsPSeriesLP(phb, dn, newTceTable);
-		builtTceTable = build_tce_table( newTceTable );
-		dn->tce_table = builtTceTable;
+
+		dn->tce_table  = build_tce_table( newTceTable );
 	}
-	
-	if(builtTceTable == NULL ) {
-		kfree( newTceTable );
-		PPCDBG(PPCDBG_TCE, "PCI Bus TCE table failed.\n");
-		return;
+}
+
+/***********************************************************************/
+/* This function compares the known Tce tables to find a TceTable that */
+/* has already been built for hardware TCEs.                           */
+/* Search the complete(all devices) for a TCE table assigned.  If the  */
+/* startOffset, index, and size match, then the TCE for this device has*/
+/* already been built and it should be shared with this device         */
+/***********************************************************************/
+static struct TceTable* findHwTceTable(struct TceTable * newTceTable )
+{
+	struct list_head* Device_Node_Ptr    = iSeries_Global_Device_List.next;
+	/* Cache the compare values. */
+	u64  startOffset = newTceTable->startOffset;
+	u64  index       = newTceTable->index;
+	u64  size        = newTceTable->size;
+
+	while(Device_Node_Ptr != &iSeries_Global_Device_List) {
+		struct iSeries_Device_Node* CmprNode = (struct iSeries_Device_Node*)Device_Node_Ptr;
+		if( CmprNode->DevTceTable != NULL &&
+		    CmprNode->DevTceTable->tceType == TCE_PCI) {
+			if( CmprNode->DevTceTable->startOffset == startOffset &&
+			    CmprNode->DevTceTable->index       == index       &&
+			    CmprNode->DevTceTable->size        == size        ) {
+				printk("PCI TCE table matches 0x%p \n",CmprNode->DevTceTable);
+				return CmprNode->DevTceTable;
+			}
+		}
+		/* Get next Device Node in List             */
+		Device_Node_Ptr = Device_Node_Ptr->next;
 	}
+	return NULL;
+}
+
+/***********************************************************************/
+/* Call Hv with the architected data structure to get TCE table info.  */
+/* info. Put the returned data into the Linux representation of the    */
+/* TCE table data.                                                     */
+/* The Hardware Tce table comes in three flavors.                      */ 
+/* 1. TCE table shared between Buses.                                  */
+/* 2. TCE table per Bus.                                               */
+/* 3. TCE Table per IOA.                                               */
+/***********************************************************************/
+static void getTceTableParmsiSeries(struct iSeries_Device_Node* DevNode,
+				    struct TceTable* newTceTable )
+{
+	struct TceTableManagerCB* pciBusTceTableParms = (struct TceTableManagerCB*)kmalloc( sizeof(struct TceTableManagerCB), GFP_KERNEL );
+	if(pciBusTceTableParms == NULL) panic("PCI_DMA: TCE Table Allocation failed.");
+
+	memset( (void*)pciBusTceTableParms,0,sizeof(struct TceTableManagerCB) );
+	pciBusTceTableParms->busNumber      = ISERIES_BUS(DevNode);
+	pciBusTceTableParms->logicalSlot    = DevNode->LogicalSlot;
+	pciBusTceTableParms->virtualBusFlag = 0;
+
+	HvCallXm_getTceTableParms( REALADDR(pciBusTceTableParms) );
+
+        /* PciTceTableParms Bus:0x18 Slot:0x04 Start:0x000000 Offset:0x04c000 Size:0x0020 */
+	printk("PciTceTableParms Bus:0x%02lx Slot:0x%02x Start:0x%06lx Offset:0x%06lx Size:0x%04lx\n",
+	       pciBusTceTableParms->busNumber,
+	       pciBusTceTableParms->logicalSlot,
+	       pciBusTceTableParms->start,
+	       pciBusTceTableParms->startOffset,
+	       pciBusTceTableParms->size);
+
+	if(pciBusTceTableParms->size == 0) {
+		printk("PCI_DMA: Possible Structure mismatch, 0x%p\n",pciBusTceTableParms);
+		panic( "PCI_DMA: pciBusTceTableParms->size is zero, halt here!");
+	}
+
+	newTceTable->size        = pciBusTceTableParms->size;
+	newTceTable->busNumber   = pciBusTceTableParms->busNumber;
+	newTceTable->startOffset = pciBusTceTableParms->startOffset;
+	newTceTable->index       = pciBusTceTableParms->index;
+	newTceTable->tceType     = TCE_PCI;
+
+	kfree(pciBusTceTableParms);
 }
 
 static void getTceTableParmsPSeries(struct pci_controller *phb,
@@ -927,8 +924,7 @@
 
 			/* Test if we are going over 2GB of DMA space.  */
 			if(phb->dma_window_base_cur > (1 << 19)) { 
-				udbg_printf("Unexpected number of IOAs under this PHB"); 
-				panic("Unexpected number of IOAs under this PHB"); 
+				panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); 
 			}
 
 			newTceTable->base = of_tce_table[i].base;
@@ -967,7 +963,7 @@
 				    struct TceTable *newTceTable ) {
 	u32 *dma_window = (u32 *)get_property(dn, "ibm,dma-window", 0);
 	if (!dma_window) {
-		panic("getTceTableParmsPSeriesLP:  device %s has no ibm,dma-window property!\n", dn->full_name);
+		panic("PCI_DMA: getTceTableParmsPSeriesLP: device %s has no ibm,dma-window property!\n", dn->full_name);
 	}
 
 	newTceTable->busNumber = dn->busno;
@@ -1003,6 +999,13 @@
 	order = get_order(size);
 	nPages = 1 << order;
 
+ 	/* Client asked for way to much space.  This is checked later anyway */
+	/* It is easier to debug here for the drivers than in the tce tables.*/
+ 	if(order >= NUM_TCE_LEVELS) {
+ 		printk("PCI_DMA: pci_alloc_consistent size to large: 0x%lx \n",size);
+ 		return (void *)NO_TCE;
+ 	}
+
 	tbl = get_tce_table(hwdev); 
 
 	if ( tbl ) {
@@ -1045,14 +1048,17 @@
 	order = get_order(size);
 	nPages = 1 << order;
 
-	if ( order > 10 )
-		PPCDBG(PPCDBG_TCE, "pci_free_consistent: order=%d, size=%d, nPages=%d, dma_handle=%016lx, vaddr=%016lx\n",
-			order, size, nPages, (unsigned long)dma_handle, (unsigned long)vaddr );
+ 	/* Client asked for way to much space.  This is checked later anyway */
+	/* It is easier to debug here for the drivers than in the tce tables.*/
+ 	if(order >= NUM_TCE_LEVELS) {
+ 		printk("PCI_DMA: pci_free_consistent size to large: 0x%lx \n",size);
+ 		return;
+ 	}
 	
 	tbl = get_tce_table(hwdev); 
 
 	if ( tbl ) {
-		ppc_md.tce_free(tbl, dma_handle, order, nPages);
+		tce_free(tbl, dma_handle, order, nPages);
 		free_pages( (unsigned long)vaddr, order );
 	}
 }
@@ -1081,6 +1087,13 @@
 	order = get_order( nPages & PAGE_MASK );
 	nPages >>= PAGE_SHIFT;
 	
+ 	/* Client asked for way to much space.  This is checked later anyway */
+	/* It is easier to debug here for the drivers than in the tce tables.*/
+ 	if(order >= NUM_TCE_LEVELS) {
+ 		printk("PCI_DMA: pci_map_single size to large: 0x%lx \n",size);
+ 		return NO_TCE;
+ 	}
+
 	tbl = get_tce_table(hwdev); 
 
 	if ( tbl ) {
@@ -1105,14 +1118,17 @@
 	order = get_order( nPages & PAGE_MASK );
 	nPages >>= PAGE_SHIFT;
 
-	if ( order > 10 )
-		PPCDBG(PPCDBG_TCE, "pci_unmap_single: order=%d, size=%d, nPages=%d, dma_handle=%016lx\n",
-			order, size, nPages, (unsigned long)dma_handle );
+ 	/* Client asked for way to much space.  This is checked later anyway */
+	/* It is easier to debug here for the drivers than in the tce tables.*/
+ 	if(order >= NUM_TCE_LEVELS) {
+ 		printk("PCI_DMA: pci_unmap_single size to large: 0x%lx \n",size);
+ 		return;
+ 	}
 	
 	tbl = get_tce_table(hwdev); 
 
 	if ( tbl ) 
-		ppc_md.tce_free(tbl, dma_handle, order, nPages);
+		tce_free(tbl, dma_handle, order, nPages);
 
 }
 
@@ -1261,6 +1277,13 @@
 	dmaAddr = NO_TCE;
 
 	order = get_order( numTces << PAGE_SHIFT );
+ 	/* Client asked for way to much space.  This is checked later anyway */
+	/* It is easier to debug here for the drivers than in the tce tables.*/
+ 	if(order >= NUM_TCE_LEVELS) {
+		printk("PCI_DMA: create_tces_sg size to large: 0x%x \n",(numTces << PAGE_SHIFT));
+ 		return NO_TCE;
+ 	}
+
 	/* allocate a block of tces */
 	tcenum = alloc_tce_range( tbl, order );
 	if ( tcenum != -1 ) {
@@ -1291,10 +1314,16 @@
 			  ++tcenum;
 			  uaddr += PAGE_SIZE;
 			}
-			
+		
 			prevEndPage = endPage;
 			sg++;
 		}
+		/* Make sure the update is visible to hardware. 
+		   sync required to synchronize the update to 
+		   the TCE table with the MMIO that will send
+		   the bus address to the IOA */
+		__asm__ __volatile__ ("sync" : : : "memory");
+
 		if ((tcenum - starttcenum) != numTces)
 	    		PPCDBG(PPCDBG_TCE, "create_tces_sg: numTces %d, tces used %d\n",
 		   		numTces, (unsigned)(tcenum - starttcenum));
@@ -1364,14 +1393,17 @@
 	numTces = ((dma_end_page - dma_start_page ) >> PAGE_SHIFT) + 1;
 	order = get_order( numTces << PAGE_SHIFT );
 
-	if ( order > 10 )
-		PPCDBG(PPCDBG_TCE, "pci_unmap_sg: order=%d, numTces=%d, nelms=%d, dma_start_page=%016lx, dma_end_page=%016lx\n",
-			order, numTces, nelms, (unsigned long)dma_start_page, (unsigned long)dma_end_page );
+ 	/* Client asked for way to much space.  This is checked later anyway */
+	/* It is easier to debug here for the drivers than in the tce tables.*/
+ 	if(order >= NUM_TCE_LEVELS) {
+		printk("PCI_DMA: pci_unmap_sg size to large: 0x%x \n",(numTces << PAGE_SHIFT));
+ 		return;
+ 	}
 	
 	tbl = get_tce_table(hwdev); 
 
 	if ( tbl ) 
-		ppc_md.tce_free( tbl, dma_start_page, order, numTces );
+		tce_free( tbl, dma_start_page, order, numTces );
 
 }
 #else
@@ -1381,11 +1413,11 @@
 	int i;
 
 	for (i = 0; i < nelems; i++) {
-		unsigned long vaddr = (page_address(sglist->page) +
-				       sglist->offset);
+		void *vaddr = page_address(sglist->page) + sglist->offset;
 
 		sglist->dma_address = pci_map_single(pdev, vaddr,
-					sglist->length, direction);
+						     sglist->length,
+						     direction);
 		sglist->dma_length = sglist->length;
 		sglist++;
 	}
@@ -1471,11 +1503,11 @@
 void tce_init_pSeries(void)
 {
 	ppc_md.tce_build = tce_build_pSeries;
-	ppc_md.tce_free  = tce_free_pSeries;
+	ppc_md.tce_free_one = tce_free_one_pSeries;
 }
 
 void tce_init_iSeries(void)
 {
 	ppc_md.tce_build = tce_build_iSeries;
-	ppc_md.tce_free  = tce_free_iSeries;
+	ppc_md.tce_free_one = tce_free_one_iSeries;
 }
diff -Nru a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c
--- a/arch/ppc64/kernel/pci_dn.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/pci_dn.c	Thu May  2 17:22:17 2002
@@ -36,7 +36,7 @@
 #include <asm/init.h>
 #include <asm/pci-bridge.h>
 #include <asm/ppcdebug.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/pci_dma.h>
 
 #include "pci.h"
diff -Nru a/arch/ppc64/kernel/pmc.c b/arch/ppc64/kernel/pmc.c
--- a/arch/ppc64/kernel/pmc.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/pmc.c	Thu May  2 17:22:16 2002
@@ -23,7 +23,7 @@
  */
 
 #include <asm/proc_fs.h>
-#include <asm/Paca.h>
+#include <asm/paca.h>
 #include <asm/iSeries/ItLpPaca.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/processor.h>
@@ -32,9 +32,7 @@
 #include <linux/spinlock.h>
 #include <asm/pmc.h>
 #include <asm/uaccess.h>
-#include <asm/Naca.h>
-
-extern struct Naca *naca;
+#include <asm/naca.h>
 
 struct _pmc_sw pmc_sw_system = {
 	0  
diff -Nru a/arch/ppc64/kernel/ppc_asm.h b/arch/ppc64/kernel/ppc_asm.h
--- a/arch/ppc64/kernel/ppc_asm.h	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/ppc_asm.h	Thu May  2 17:22:16 2002
@@ -1,5 +1,5 @@
 /*
- * arch/ppc/kernel/ppc_asm.h
+ * arch/ppc64/kernel/ppc_asm.h
  *
  * Definitions used by various bits of low-level assembly code on PowerPC.
  *
@@ -13,7 +13,7 @@
 
 #include <linux/config.h>
 
-#include "ppc_asm.tmpl"
+#include <asm/ppc_asm.tmpl>
 #include "ppc_defs.h"
 
 /*
diff -Nru a/arch/ppc64/kernel/ppc_asm.tmpl b/arch/ppc64/kernel/ppc_asm.tmpl
--- a/arch/ppc64/kernel/ppc_asm.tmpl	Thu May  2 17:22:16 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,115 +0,0 @@
-/* Condition Register Bit Fields */
-
-#define	cr0	0
-#define	cr1	1
-#define	cr2	2
-#define	cr3	3
-#define	cr4	4
-#define	cr5	5
-#define	cr6	6
-#define	cr7	7
-
-
-/* General Purpose Registers (GPRs) */
-
-#define	r0	0
-#define	r1	1
-#define	r2	2
-#define	r3	3
-#define	r4	4
-#define	r5	5
-#define	r6	6
-#define	r7	7
-#define	r8	8
-#define	r9	9
-#define	r10	10
-#define	r11	11
-#define	r12	12
-#define	r13	13
-#define	r14	14
-#define	r15	15
-#define	r16	16
-#define	r17	17
-#define	r18	18
-#define	r19	19
-#define	r20	20
-#define	r21	21
-#define	r22	22
-#define	r23	23
-#define	r24	24
-#define	r25	25
-#define	r26	26
-#define	r27	27
-#define	r28	28
-#define	r29	29
-#define	r30	30
-#define	r31	31
-
-
-/* Floating Point Registers (FPRs) */
-
-#define	fr0	0
-#define	fr1	1
-#define	fr2	2
-#define	fr3	3
-#define	fr4	4
-#define	fr5	5
-#define	fr6	6
-#define	fr7	7
-#define	fr8	8
-#define	fr9	9
-#define	fr10	10
-#define	fr11	11
-#define	fr12	12
-#define	fr13	13
-#define	fr14	14
-#define	fr15	15
-#define	fr16	16
-#define	fr17	17
-#define	fr18	18
-#define	fr19	19
-#define	fr20	20
-#define	fr21	21
-#define	fr22	22
-#define	fr23	23
-#define	fr24	24
-#define	fr25	25
-#define	fr26	26
-#define	fr27	27
-#define	fr28	28
-#define	fr29	29
-#define	fr30	30
-#define	fr31	31
-
-#define	vr0	0
-#define	vr1	1
-#define	vr2	2
-#define	vr3	3
-#define	vr4	4
-#define	vr5	5
-#define	vr6	6
-#define	vr7	7
-#define	vr8	8
-#define	vr9	9
-#define	vr10	10
-#define	vr11	11
-#define	vr12	12
-#define	vr13	13
-#define	vr14	14
-#define	vr15	15
-#define	vr16	16
-#define	vr17	17
-#define	vr18	18
-#define	vr19	19
-#define	vr20	20
-#define	vr21	21
-#define	vr22	22
-#define	vr23	23
-#define	vr24	24
-#define	vr25	25
-#define	vr26	26
-#define	vr27	27
-#define	vr28	28
-#define	vr29	29
-#define	vr30	30
-#define	vr31	31
diff -Nru a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c
--- a/arch/ppc64/kernel/ppc_ksyms.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/ppc_ksyms.c	Thu May  2 17:22:16 2002
@@ -14,7 +14,6 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/interrupt.h>
-#include <linux/nvram.h>
 #include <linux/spinlock.h>
 #include <linux/console.h>
 #include <linux/irq.h>
@@ -47,6 +46,9 @@
 #ifdef CONFIG_PPC_ISERIES
 #include <asm/iSeries/iSeries_pci.h>
 #include <asm/iSeries/iSeries_proc.h>
+#include <asm/iSeries/mf.h>
+#include <asm/iSeries/HvLpEvent.h>
+#include <asm/iSeries/HvLpConfig.h>
 #endif
 
 /* Tell string.h we don't want memcpy etc. as cpp defines */
@@ -150,6 +152,11 @@
 EXPORT_SYMBOL(HvCall5);
 EXPORT_SYMBOL(HvCall6);
 EXPORT_SYMBOL(HvCall7);
+EXPORT_SYMBOL(HvLpEvent_unregisterHandler);
+EXPORT_SYMBOL(HvLpEvent_registerHandler);
+EXPORT_SYMBOL(mf_allocateLpEvents);
+EXPORT_SYMBOL(mf_deallocateLpEvents);
+EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline);
 #endif
 
 EXPORT_SYMBOL(_insb);
@@ -183,13 +190,11 @@
 EXPORT_SYMBOL(iSeries_Read_Word);
 EXPORT_SYMBOL(iSeries_Read_Byte);
 EXPORT_SYMBOL(iSeries_Write_Byte);
-
 #endif /* CONFIG_PPC_ISERIES */
-#ifdef CONFIG_PPC_EEH
+#ifndef CONFIG_PPC_ISERIES
 EXPORT_SYMBOL(eeh_check_failure);
 EXPORT_SYMBOL(eeh_total_mmio_ffs);
-EXPORT_SYMBOL(eeh_total_mmio_reads);
-#endif /* CONFIG_PPC_EEH */
+#endif /* CONFIG_PPC_ISERIES */
 #endif /* CONFIG_PCI */
 
 EXPORT_SYMBOL(iSeries_veth_dev);
@@ -219,9 +224,6 @@
 #endif
 #endif
 
-#ifndef CONFIG_MACH_SPECIFIC
-EXPORT_SYMBOL(_machine);
-#endif
 EXPORT_SYMBOL(ppc_md);
 
 EXPORT_SYMBOL(find_devices);
@@ -233,10 +235,6 @@
 EXPORT_SYMBOL(find_all_nodes);
 EXPORT_SYMBOL(get_property);
 
-#ifdef CONFIG_NVRAM
-EXPORT_SYMBOL(nvram_read_byte);
-EXPORT_SYMBOL(nvram_write_byte);
-#endif /* CONFIG_NVRAM */
 
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
 EXPORT_SYMBOL_NOVERS(__ashldi3);
diff -Nru a/arch/ppc64/kernel/proc_pmc.c b/arch/ppc64/kernel/proc_pmc.c
--- a/arch/ppc64/kernel/proc_pmc.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/proc_pmc.c	Thu May  2 17:22:16 2002
@@ -25,7 +25,7 @@
  */
 
 #include <asm/proc_fs.h>
-#include <asm/Paca.h>
+#include <asm/paca.h>
 #include <asm/iSeries/ItLpPaca.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/HvCallXm.h>
@@ -38,7 +38,7 @@
 #include <linux/spinlock.h>
 #include <asm/pmc.h>
 #include <asm/uaccess.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 
 
 static int proc_pmc_control_mode = 0;
@@ -49,9 +49,6 @@
 static struct proc_dir_entry *proc_ppc64_pmc_cpu_root[NR_CPUS] = {NULL, };
 
 static spinlock_t proc_ppc64_lock;
-
-extern struct Naca *naca;
-
 int proc_ppc64_pmc_find_file(void *data);
 int proc_ppc64_pmc_read(char *page, char **start, off_t off,
 			int count, int *eof, char *buffer);
@@ -385,7 +382,7 @@
 	len += sprintf( page+len, "\n  events processed by processor:\n" );
 	for (i=0; i<naca->processorCount; ++i) {
 		len += sprintf( page+len, "    CPU%02d  %10u\n",
-			i, xPaca[i].lpEvent_count );
+			i, paca[i].lpEvent_count );
 	}
 
 	return pmc_calc_metrics( page, start, off, count, eof, len );
@@ -587,7 +584,7 @@
 	proc_pmc_control_mode = PMC_CONTROL_CPI;
 	
 	/* Indicate to hypervisor that we are using the PMCs */
-	((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 1;
+	get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
 
 	/* Freeze all counters */
 	mtspr( MMCR0, 0x80000000 );
@@ -638,7 +635,7 @@
 	proc_pmc_control_mode = PMC_CONTROL_TLB;
 	
 	/* Indicate to hypervisor that we are using the PMCs */
-	((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 1;
+	get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
 
 	/* Freeze all counters */
 	mtspr( MMCR0, 0x80000000 );
@@ -688,9 +685,9 @@
 	v = proc_pmc_conv_int( buffer, count );
 	v = v & ~0x04000000;	/* Don't allow interrupts for now */
 	if ( v & ~0x80000000 ) 	/* Inform hypervisor we are using PMCs */
-		((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 1;
+		get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
 	else
-		((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 0;
+		get_paca()->xLpPacaPtr->xPMCRegsInUse = 0;
 	mtspr( MMCR0, v );
 	
 	return count;	
diff -Nru a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c
--- a/arch/ppc64/kernel/process.c	Thu May  2 17:22:15 2002
+++ b/arch/ppc64/kernel/process.c	Thu May  2 17:22:15 2002
@@ -43,9 +43,6 @@
 #include <asm/ppcdebug.h>
 #include <asm/machdep.h>
 #include <asm/iSeries/HvCallHpt.h>
-#include <asm/Naca.h>
-
-#include "ppc_defs.h"
 
 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
 
@@ -300,7 +297,7 @@
 
 void initialize_paca_hardware_interrupt_stack(void)
 {
-	extern struct Naca *naca;
+	extern struct naca_struct *naca;
 
 	int i;
 	unsigned long stack;
@@ -317,8 +314,8 @@
 
 
 		/* Store the stack value in the PACA for the processor */
-		xPaca[i].xHrdIntStack = stack + (8*PAGE_SIZE) - STACK_FRAME_OVERHEAD;
-		xPaca[i].xHrdIntCount = 0;
+		paca[i].xHrdIntStack = stack + (8*PAGE_SIZE) - STACK_FRAME_OVERHEAD;
+		paca[i].xHrdIntCount = 0;
 
 	}
 
@@ -331,7 +328,7 @@
 
 	for (i=0; i < naca->processorCount; i++) {
 		/* set page at the top of stack to be protected - prevent overflow */
-		end_of_stack = xPaca[i].xHrdIntStack - (8*PAGE_SIZE - STACK_FRAME_OVERHEAD);
+		end_of_stack = paca[i].xHrdIntStack - (8*PAGE_SIZE - STACK_FRAME_OVERHEAD);
 		ppc_md.hpte_updateboltedpp(PP_RXRX,end_of_stack);
 	}
 }
diff -Nru a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
--- a/arch/ppc64/kernel/prom.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/prom.c	Thu May  2 17:22:17 2002
@@ -64,7 +64,7 @@
 #include <asm/mmu.h>
 #include <asm/pgtable.h>
 #include <asm/bitops.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/pci.h>
 #include "open_pic.h"
 #include <asm/bootinfo.h>
@@ -169,7 +169,6 @@
 extern struct rtas_t rtas;
 extern unsigned long klimit;
 extern unsigned long embedded_sysmap_end;
-extern struct Naca *naca;
 extern struct lmb lmb;
 #ifdef CONFIG_MSCHUNKS
 extern struct msChunks msChunks;
@@ -339,7 +338,7 @@
         unsigned long num_cpus = 0;
         unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
-        struct Naca *_naca = RELOC(naca);
+        struct naca_struct *_naca = RELOC(naca);
 
 #ifdef DEBUG_PROM
 	prom_print(RELOC("prom_initialize_naca: start...\n"));
@@ -377,7 +376,7 @@
 				_naca->iCacheL1LogLineSize  = __ilog2(size);
 				_naca->iCacheL1LinesPerPage = PAGE_SIZE / size;
 
-				if (RELOC(_machine) == _MACH_pSeriesLP) {
+				if (_naca->platform == PLATFORM_PSERIES_LPAR) {
 					u32 pft_size[2];
 					call_prom(RELOC("getprop"), 4, 1, node, 
 						  RELOC("ibm,pft-size"),
@@ -452,7 +451,7 @@
 
 	_naca->physicalMemorySize = lmb_phys_mem_size();
 
-	if (RELOC(_machine) == _MACH_pSeries) {
+	if (_naca->platform == PLATFORM_PSERIES) {
 		unsigned long rnd_mem_size, pteg_count;
 
 		/* round mem_size up to next power of 2 */
@@ -523,8 +522,8 @@
         prom_print_hex(_naca->interrupt_controller);
         prom_print_nl();
 
-        prom_print(RELOC("_machine                   = 0x"));
-        prom_print_hex(RELOC(_machine));
+        prom_print(RELOC("naca->platform             = 0x"));
+        prom_print_hex(_naca->platform);
         prom_print_nl();
 
 	prom_print(RELOC("prom_initialize_naca: end...\n"));
@@ -627,6 +626,7 @@
 	unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
 	struct rtas_t *_rtas = PTRRELOC(&rtas);
+	struct naca_struct *_naca = RELOC(naca);
 	ihandle prom_rtas;
         u32 getprop_rval;
 
@@ -643,7 +643,7 @@
 				  RELOC("ibm,hypertas-functions"), 
 				  hypertas_funcs, 
 				  sizeof(hypertas_funcs))) > 0) {
-			RELOC(_machine) = _MACH_pSeriesLP;
+			_naca->platform = PLATFORM_PSERIES_LPAR;
 		}
 
 		call_prom(RELOC("getprop"), 
@@ -1043,8 +1043,8 @@
         unsigned long *spinloop     = __v2a(&__secondary_hold_spinloop);
         unsigned long *acknowledge  = __v2a(&__secondary_hold_acknowledge);
         unsigned long secondary_hold = (unsigned long)__v2a(*PTRRELOC((unsigned long *)__secondary_hold));
-        struct Naca *_naca = RELOC(naca);
-	struct Paca *_xPaca = PTRRELOC(&xPaca[0]);
+        struct naca_struct *_naca = RELOC(naca);
+	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
 
 	/* Initially, we must have one active CPU. */
@@ -1237,12 +1237,12 @@
 	char *p, *d;
  	unsigned long phys;
         u32 getprop_rval;
-        struct Naca   *_naca = RELOC(naca);
-	struct Paca *_xPaca = PTRRELOC(&xPaca[0]);
+        struct naca_struct   *_naca = RELOC(naca);
+	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
 
 	/* Default machine type. */
-	RELOC(_machine) = _MACH_pSeries;
+	_naca->platform = PLATFORM_PSERIES;
 	/* Reset klimit to take into account the embedded system map */
 	if (RELOC(embedded_sysmap_end))
 		RELOC(klimit) = __va(PAGE_ALIGN(RELOC(embedded_sysmap_end)));
@@ -1414,7 +1414,7 @@
 
 	lmb_reserve(0, __pa(RELOC(klimit)));
 
-	if (RELOC(_machine) == _MACH_pSeries)
+	if (_naca->platform == PLATFORM_PSERIES)
 		prom_initialize_tce_table();
 
  	if ((long) call_prom(RELOC("getprop"), 4, 1,
diff -Nru a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c
--- a/arch/ppc64/kernel/rtas-proc.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/rtas-proc.c	Thu May  2 17:22:17 2002
@@ -200,7 +200,7 @@
 	struct proc_dir_entry *entry;
 
 	rtas_node = find_devices("rtas");
-	if ((rtas_node == 0) || (_machine == _MACH_iSeries)) {
+	if ((rtas_node == 0) || (naca->platform == PLATFORM_ISERIES_LPAR)) {
 		return;
 	}
 	
diff -Nru a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c
--- a/arch/ppc64/kernel/rtas.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/kernel/rtas.c	Thu May  2 17:22:16 2002
@@ -20,7 +20,7 @@
 #include <asm/prom.h>
 #include <asm/rtas.h>
 #include <asm/machdep.h>
-#include <asm/Paca.h>
+#include <asm/paca.h>
 #include <asm/page.h>
 #include <asm/system.h>
 #include <asm/udbg.h>
diff -Nru a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
--- a/arch/ppc64/kernel/setup.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/setup.c	Thu May  2 17:22:17 2002
@@ -32,8 +32,8 @@
 #include <asm/elf.h>
 #include <asm/machdep.h>
 #include <asm/iSeries/LparData.h>
-#include <asm/Naca.h>
-#include <asm/Paca.h>
+#include <asm/naca.h>
+#include <asm/paca.h>
 #include <asm/ppcdebug.h>
 #include <asm/time.h>
 
@@ -76,14 +76,11 @@
 		    unsigned long r6, unsigned long r7);
 int parse_bootinfo(void);
 
-int _machine = _MACH_unknown;
-
 #ifdef CONFIG_MAGIC_SYSRQ
 unsigned long SYSRQ_KEY;
 #endif /* CONFIG_MAGIC_SYSRQ */
 
 struct machdep_calls ppc_md;
-struct Naca *naca;
 
 /*
  * Perhaps we can put the pmac screen_info[] here
@@ -118,34 +115,11 @@
  */
 void ppcdbg_initialize(void) {
 	unsigned long offset = reloc_offset();
-	struct Naca *_naca = RELOC(naca);
+	struct naca_struct *_naca = RELOC(naca);
 
 	_naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
 }
 
-/* 
- * Initialize a set of PACA's, one for each processor.
- *
- * At this point, relocation is on, but we have not done any other
- * setup of the mm subsystem.
- */
-void paca_init(void) {
-#if 0
-	int processorCount = naca->processorCount, i;
-	struct Paca *paca[];
-
-	/* Put the array of paca's on a page boundary & allocate 1/2 page of */
-	/* storage for each.                                                 */  
-	klimit += (PAGE_SIZE-1) & PAGE_MASK;
-	naca->xPaca = paca[0] = klimit;
-	klimit += ((PAGE_SIZE>>1) * processorCount); 
-
-	for(i=0; i<processorCount; i++) {
-		paca[0]->xPacaIndex = i;
-	}
-#endif
-}
-
 /*
  * Do some initial setup of the system.  The paramters are those which 
  * were passed in from the bootloader.
@@ -158,14 +132,15 @@
 
 	/* pSeries systems are identified in prom.c via OF. */
 	if ( itLpNaca.xLparInstalled == 1 )
-		_machine = _MACH_iSeries;
-	switch (_machine) {
-	case _MACH_iSeries:
+		naca->platform = PLATFORM_ISERIES_LPAR;
+	
+	switch (naca->platform) {
+	case PLATFORM_ISERIES_LPAR:
 		iSeries_init_early();
 		break;
 
 #ifdef CONFIG_PPC_PSERIES
-	case _MACH_pSeries:
+	case PLATFORM_PSERIES:
 		pSeries_init_early();
 #ifdef CONFIG_BLK_DEV_INITRD
 		initrd_start = initrd_end = 0;
@@ -173,7 +148,7 @@
 		parse_bootinfo();
 		break;
 
-	case _MACH_pSeriesLP:
+	case PLATFORM_PSERIES_LPAR:
 		pSeriesLP_init_early();
 #ifdef CONFIG_BLK_DEV_INITRD
 		initrd_start = initrd_end = 0;
@@ -244,15 +219,15 @@
 	udbg_puts("\n-----------------------------------------------------\n");
 
 
-	if ( _machine & _MACH_pSeries ) {
+	if (naca->platform & PLATFORM_PSERIES) {
 		finish_device_tree();
 		chrp_init(r3, r4, r5, r6, r7);
 	}
 
 	mm_init_ppc64();
 
-	switch (_machine) {
-	case _MACH_iSeries:
+	switch (naca->platform) {
+	case PLATFORM_ISERIES_LPAR:
 		iSeries_init();
 		break;
 	default:
@@ -300,14 +275,14 @@
 		return 0;
 #endif
 
-	pvr = xPaca[cpu_id].pvr;
+	pvr = paca[cpu_id].pvr;
 	maj = (pvr >> 8) & 0xFF;
 	min = pvr & 0xFF;
 
 	seq_printf(m, "processor\t: %lu\n", cpu_id);
 	seq_printf(m, "cpu\t\t: ");
 
-	pvr = xPaca[cpu_id].pvr;
+	pvr = paca[cpu_id].pvr;
 
 	switch (PVR_VER(pvr)) {
 	case PV_PULSAR:
@@ -337,7 +312,7 @@
 	 * Assume here that all clock rates are the same in a
 	 * smp system.  -- Cort
 	 */
-	if (_machine != _MACH_iSeries) {
+	if (naca->platform != PLATFORM_ISERIES_LPAR) {
 		struct device_node *cpu_node;
 		int *fp;
 
@@ -564,6 +539,7 @@
 	ppc_md.setup_arch();
 
 	paging_init();
+	sort_exception_table();
 	ppc_md.progress("setup_arch: exit", 0x3eab);
 }
 
@@ -681,9 +657,9 @@
 	/* The parameter is the number of processors to share in processing lp events */
 	unsigned long i;
 	unsigned long val = simple_strtoul( str, NULL, 0 );
-	if ( ( val > 0 ) && ( val <= maxPacas ) ) {
+	if ( ( val > 0 ) && ( val <= MAX_PACAS ) ) {
 		for ( i=1; i<val; ++i )
-			xPaca[i].lpQueuePtr = xPaca[0].lpQueuePtr;
+			paca[i].lpQueuePtr = paca[0].lpQueuePtr;
 		printk("lpevent processing spread over %ld processors\n", val);
 	}
 	else
@@ -694,13 +670,13 @@
 /* This should only be called on processor 0 during calibrate decr */
 void setup_default_decr(void)
 {
-	struct Paca * paca = (struct Paca *)mfspr(SPRG3);
+	struct paca_struct *lpaca = get_paca();
 
 	if ( decr_overclock_set && !decr_overclock_proc0_set )
 		decr_overclock_proc0 = decr_overclock;
 
-	paca->default_decr = tb_ticks_per_jiffy / decr_overclock_proc0;	
-	paca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy;
+	lpaca->default_decr = tb_ticks_per_jiffy / decr_overclock_proc0;	
+	lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy;
 }
 
 int set_decr_overclock_proc0( char * str )
diff -Nru a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c
--- a/arch/ppc64/kernel/signal.c	Thu May  2 17:22:15 2002
+++ b/arch/ppc64/kernel/signal.c	Thu May  2 17:22:15 2002
@@ -28,6 +28,8 @@
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <linux/elf.h>
+#include <linux/tty.h>
+#include <linux/binfmts.h>
 #include <asm/ppc32.h>
 #include <asm/sigcontext.h>
 #include <asm/ucontext.h>
diff -Nru a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c
--- a/arch/ppc64/kernel/signal32.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/signal32.c	Thu May  2 17:22:17 2002
@@ -43,10 +43,12 @@
 #include <linux/personality.h>
 #include <linux/stat.h>
 #include <linux/filter.h>
+#include <linux/tty.h>
+#include <linux/binfmts.h>
+#include <linux/elf.h>
 #include <asm/types.h>
 #include <asm/ipc.h>
 #include <asm/uaccess.h>
-#include <linux/elf.h>
 #include <asm/ppc32.h>
 #include <asm/ppcdebug.h>
 #include <asm/unistd.h>
@@ -1245,18 +1247,19 @@
 		    || __put_user((unsigned int)frame, &sc->regs)
 		    || __put_user(sig, &sc->signal))
 			goto badframe;
+	}
 
-		if (ka->sa.sa_flags & SA_ONESHOT)
-			ka->sa.sa_handler = SIG_DFL;
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
 
-		if (!(ka->sa.sa_flags & SA_NODEFER)) {
-			spin_lock_irq(&current->sigmask_lock);
-			sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-			sigaddset(&current->blocked,sig);
-			recalc_sigpending();
-			spin_unlock_irq(&current->sigmask_lock);
-		}
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sigmask_lock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sigmask_lock);
 	}
+	
 	return;
 
 badframe:
diff -Nru a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c
--- a/arch/ppc64/kernel/smp.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/smp.c	Thu May  2 17:22:17 2002
@@ -43,8 +43,8 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/smp.h>
-#include <asm/Naca.h>
-#include <asm/Paca.h>
+#include <asm/naca.h>
+#include <asm/paca.h>
 #include <asm/iSeries/LparData.h>
 #include <asm/iSeries/HvCall.h>
 #include <asm/iSeries/HvCallCfg.h>
@@ -77,8 +77,6 @@
 void smp_call_function_interrupt(void);
 void smp_message_pass(int target, int msg, unsigned long data, int wait);
 static unsigned long iSeries_smp_message[NR_CPUS];
-extern struct Naca *naca;
-extern struct Paca xPaca[];
 
 void xics_setup_cpu(void);
 void xics_cause_IPI(int cpu);
@@ -123,7 +121,7 @@
                     (target == i) || 
                     ((target == MSG_ALL_BUT_SELF) && (i != smp_processor_id())) ) {
 			set_bit( msg, &iSeries_smp_message[i] );
-			HvCall_sendIPI(&(xPaca[i]));
+			HvCall_sendIPI(&(paca[i]));
 		}
 	}
 }
@@ -134,8 +132,8 @@
 	struct ItLpPaca * lpPaca;
 
 	np = 0;
-        for (i=0; i < maxPacas; ++i) {
-                lpPaca = xPaca[i].xLpPacaPtr;
+        for (i=0; i < MAX_PACAS; ++i) {
+                lpPaca = paca[i].xLpPacaPtr;
                 if ( lpPaca->xDynProcStatus < 2 ) {
                         ++np;
                 }
@@ -150,11 +148,11 @@
 	struct ItLpPaca * lpPaca;
 
 	np = 0;
-	for (i=0; i < maxPacas; ++i) {
-		lpPaca = xPaca[i].xLpPacaPtr;
+	for (i=0; i < MAX_PACAS; ++i) {
+		lpPaca = paca[i].xLpPacaPtr;
 		if ( lpPaca->xDynProcStatus < 2 ) {
 			++np;
-			xPaca[i].next_jiffy_update_tb = xPaca[0].next_jiffy_update_tb;
+			paca[i].next_jiffy_update_tb = paca[0].next_jiffy_update_tb;
 		}
 	}
 	
@@ -167,18 +165,25 @@
 	struct ItLpPaca * lpPaca;
 	/* Verify we have a Paca for processor nr */
 	if ( ( nr <= 0 ) ||
-	     ( nr >= maxPacas ) )
+	     ( nr >= MAX_PACAS ) )
 		return;
 	/* Verify that our partition has a processor nr */
-	lpPaca = xPaca[nr].xLpPacaPtr;
+	lpPaca = paca[nr].xLpPacaPtr;
 	if ( lpPaca->xDynProcStatus >= 2 )
 		return;
+
+	/* The information for processor bringup must
+	 * be written out to main store before we release
+	 * the processor.
+	 */
+	mb();
+
 	/* The processor is currently spinning, waiting
 	 * for the xProcStart field to become non-zero
 	 * After we set xProcStart, the processor will
 	 * continue on to secondary_start in iSeries_head.S
 	 */
-	xPaca[nr].xProcStart = 1;
+	paca[nr].xProcStart = 1;
 }
 
 static void smp_iSeries_setup_cpu(int nr)
@@ -235,15 +240,21 @@
 {
 	/* Verify we have a Paca for processor nr */
 	if ( ( nr <= 0 ) ||
-	     ( nr >= maxPacas ) )
+	     ( nr >= MAX_PACAS ) )
 		return;
 
+	/* The information for processor bringup must
+	 * be written out to main store before we release
+	 * the processor.
+	 */
+	mb();
+
 	/* The processor is currently spinning, waiting
 	 * for the xProcStart field to become non-zero
 	 * After we set xProcStart, the processor will
 	 * continue on to secondary_start in iSeries_head.S
 	 */
-	xPaca[nr].xProcStart = 1;
+	paca[nr].xProcStart = 1;
 }
 
 extern struct gettimeofday_struct do_gtod;
@@ -254,7 +265,7 @@
 	
 	offset = tb_ticks_per_jiffy / nr;
 	for ( i=1; i<nr; ++i ) {
-		xPaca[i].next_jiffy_update_tb = xPaca[i-1].next_jiffy_update_tb + offset;
+		paca[i].next_jiffy_update_tb = paca[i-1].next_jiffy_update_tb + offset;
 	}
 }
 
@@ -264,9 +275,9 @@
 	static atomic_t ready = ATOMIC_INIT(1);
 	static volatile int frozen = 0;
 
-	if (_machine == _MACH_pSeriesLP) {
+	if (naca->platform == PLATFORM_PSERIES_LPAR) {
 		/* timebases already synced under the hypervisor. */
-		xPaca[cpu_nr].next_jiffy_update_tb = tb_last_stamp = get_tb();
+		paca[cpu_nr].next_jiffy_update_tb = tb_last_stamp = get_tb();
 		if (cpu_nr == 0) {
 			do_gtod.tb_orig_stamp = tb_last_stamp;
 			/* Should update do_gtod.stamp_xsec.
@@ -286,7 +297,7 @@
 			mb();
 			frozen = 1;
 			set_tb(0, 0);
-			xPaca[0].next_jiffy_update_tb = 0;
+			paca[0].next_jiffy_update_tb = 0;
 			smp_space_timers(smp_num_cpus);
 			while (atomic_read(&ready) < smp_num_cpus)
 				barrier();
@@ -549,7 +560,6 @@
 
 void __init smp_boot_cpus(void)
 {
-	struct Paca *paca;
 	int i, cpu_nr;
 	struct task_struct *p;
 
@@ -568,9 +578,8 @@
 	current_thread_info()->cpu = 0;
 
 	for (i = 0; i < NR_CPUS; i++) {
-		paca = &xPaca[i];
-		paca->prof_counter = 1;
-		paca->prof_multiplier = 1;
+		paca[i].prof_counter = 1;
+		paca[i].prof_multiplier = 1;
 		if(i != 0) {
 		        /*
 			 * Processor 0's segment table is statically 
@@ -578,10 +587,10 @@
 			 * Other processor's tables are created and
 			 * initialized here.
 			 */
-			paca->xStab_data.virt = (unsigned long)&stab_array[PAGE_SIZE * (i-1)];
-			memset((void *)paca->xStab_data.virt, 0, PAGE_SIZE); 
-			paca->xStab_data.real = __v2a(paca->xStab_data.virt);
-			paca->default_decr = tb_ticks_per_jiffy / decr_overclock;
+			paca[i].xStab_data.virt = (unsigned long)&stab_array[PAGE_SIZE * (i-1)];
+			memset((void *)paca[i].xStab_data.virt, 0, PAGE_SIZE); 
+			paca[i].xStab_data.real = __v2a(paca[i].xStab_data.virt);
+			paca[i].default_decr = tb_ticks_per_jiffy / decr_overclock;
 		}
 	}
 
@@ -641,7 +650,7 @@
 
 		unhash_process(p);
 
-		xPaca[i].xCurrent = (u64)p;
+		paca[i].xCurrent = (u64)p;
 		current_set[i] = p->thread_info;
 
 		/* wake up cpus */
@@ -690,7 +699,7 @@
 	int cpu = smp_processor_id();
 
         smp_store_cpu_info(cpu);
-	set_dec(xPaca[cpu].default_decr);
+	set_dec(paca[cpu].default_decr);
 	cpu_callin_map[cpu] = 1;
 	set_bit(smp_processor_id(), &cpu_online_map);
 
@@ -730,7 +739,7 @@
  */
 void __init smp_store_cpu_info(int id)
 {
-        xPaca[id].pvr = _get_PVR();
+        paca[id].pvr = _get_PVR();
 }
 
 static int __init maxcpus(char *str)
diff -Nru a/arch/ppc64/kernel/stab.c b/arch/ppc64/kernel/stab.c
--- a/arch/ppc64/kernel/stab.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/stab.c	Thu May  2 17:22:17 2002
@@ -14,8 +14,8 @@
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
 #include <asm/mmu_context.h>
-#include <asm/Paca.h>
-#include <asm/Naca.h>
+#include <asm/paca.h>
+#include <asm/naca.h>
 #include <asm/pmc.h>
 
 int make_ste(unsigned long stab, 
diff -Nru a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c
--- a/arch/ppc64/kernel/time.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/time.c	Thu May  2 17:22:17 2002
@@ -250,8 +250,8 @@
 {
 	int next_dec;
 	unsigned long cur_tb;
-	struct Paca * paca = (struct Paca *)mfspr(SPRG3);
-	unsigned long cpu = paca->xPacaIndex;
+	struct paca_struct *lpaca = get_paca();
+	unsigned long cpu = lpaca->xPacaIndex;
 	struct ItLpQueue * lpq;
 
 	irq_enter(cpu);
@@ -261,16 +261,16 @@
 		ppc_do_profile(instruction_pointer(regs));
 #endif
 
-	paca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
+	lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
 
-	while (paca->next_jiffy_update_tb <= (cur_tb = get_tb())) {
+	while (lpaca->next_jiffy_update_tb <= (cur_tb = get_tb())) {
 
 #ifdef CONFIG_SMP
 		smp_local_timer_interrupt(regs);
 #endif
 		if (cpu == 0) {
 			write_lock(&xtime_lock);
-			tb_last_stamp = paca->next_jiffy_update_tb;
+			tb_last_stamp = lpaca->next_jiffy_update_tb;
 			do_timer(regs);
 			timer_sync_xtime( cur_tb );
 			timer_check_rtc();
@@ -278,15 +278,15 @@
 			if ( adjusting_time && (time_adjust == 0) )
 				ppc_adjtimex();
 		}
-		paca->next_jiffy_update_tb += tb_ticks_per_jiffy;
+		lpaca->next_jiffy_update_tb += tb_ticks_per_jiffy;
 	}
 	
-	next_dec = paca->next_jiffy_update_tb - cur_tb;
-	if (next_dec > paca->default_decr)
-        	next_dec = paca->default_decr;
+	next_dec = lpaca->next_jiffy_update_tb - cur_tb;
+	if (next_dec > lpaca->default_decr)
+        	next_dec = lpaca->default_decr;
 	set_dec(next_dec);
 
-	lpq = paca->lpQueuePtr;
+	lpq = lpaca->lpQueuePtr;
 	if (lpq && ItLpQueue_isLpIntPending(lpq))
 		lpEvent_count += ItLpQueue_process(lpq, regs); 
 
diff -Nru a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c
--- a/arch/ppc64/kernel/traps.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/kernel/traps.c	Thu May  2 17:22:17 2002
@@ -40,6 +40,9 @@
 extern int fix_alignment(struct pt_regs *);
 extern void bad_page_fault(struct pt_regs *, unsigned long);
 
+/* This is true if we are using the firmware NMI handler (typically LPAR) */
+extern int fwnmi_active;
+
 #ifdef CONFIG_XMON
 extern void xmon(struct pt_regs *regs);
 extern int xmon_bpt(struct pt_regs *regs);
@@ -91,13 +94,55 @@
 	force_sig(signr, current);
 }
 
+/* Get the error information for errors coming through the
+ * FWNMI vectors.  The pt_regs' r3 will be updated to reflect
+ * the actual r3 if possible, and a ptr to the error log entry
+ * will be returned if found.
+ */
+static struct rtas_error_log *FWNMI_get_errinfo(struct pt_regs *regs)
+{
+	unsigned long errdata = regs->gpr[3];
+	struct rtas_error_log *errhdr = NULL;
+	unsigned long *savep;
+
+	if ((errdata >= 0x7000 && errdata < 0x7fff0) ||
+	    (errdata >= rtas.base && errdata < rtas.base + rtas.size - 16)) {
+		savep = __va(errdata);
+		regs->gpr[3] = savep[0];	/* restore original r3 */
+		errhdr = (struct rtas_error_log *)(savep + 1);
+	} else {
+		printk("FWNMI: corrupt r3\n");
+	}
+	return errhdr;
+}
+
+/* Call this when done with the data returned by FWNMI_get_errinfo.
+ * It will release the saved data area for other CPUs in the
+ * partition to receive FWNMI errors.
+ */
+static void FWNMI_release_errinfo(void)
+{
+	unsigned long ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL);
+	if (ret != 0)
+		printk("FWNMI: nmi-interlock failed: %ld\n", ret);
+}
+
 void
 SystemResetException(struct pt_regs *regs)
 {
-	udbg_printf("System Reset in kernel mode.\n");
-	printk("System Reset in kernel mode.\n");
+	char *msg = "System Reset in kernel mode.\n";
+	udbg_printf(msg); printk(msg);
+	if (fwnmi_active) {
+		unsigned long *r3 = __va(regs->gpr[3]); /* for FWNMI debug */
+		struct rtas_error_log *errlog;
+
+		msg = "FWNMI is active with save area at %016lx\n";
+		udbg_printf(msg, r3); printk(msg, r3);
+		errlog = FWNMI_get_errinfo(regs);
+	}
 #if defined(CONFIG_XMON)
 	xmon(regs);
+	udbg_printf("leaving xmon...\n");
 #else
 	for(;;);
 #endif
@@ -106,6 +151,13 @@
 void
 MachineCheckException(struct pt_regs *regs)
 {
+	if (fwnmi_active) {
+		struct rtas_error_log *errhdr = FWNMI_get_errinfo(regs);
+		if (errhdr) {
+			/* ToDo: attempt to recover from some errors here */
+		}
+		FWNMI_release_errinfo();
+	}
 	if ( !user_mode(regs) )
 	{
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
diff -Nru a/arch/ppc64/kernel/udbg.c b/arch/ppc64/kernel/udbg.c
--- a/arch/ppc64/kernel/udbg.c	Thu May  2 17:22:15 2002
+++ b/arch/ppc64/kernel/udbg.c	Thu May  2 17:22:15 2002
@@ -19,13 +19,10 @@
 #define WANT_PPCDBG_TAB /* Only defined here */
 #include <asm/ppcdebug.h>
 #include <asm/processor.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/uaccess.h>
 #include <asm/machdep.h>
 
-extern struct Naca *naca;
-extern int _machine;
-
 struct NS16550 {
 	/* this struct must be packed */
 	unsigned char rbr;  /* 0 */
@@ -87,7 +84,7 @@
 				/* wait for idle */;
 			udbg_comport->thr = '\r'; eieio();
 		}
-	} else if ( _machine == _MACH_iSeries ) {
+	} else if (naca->platform == PLATFORM_ISERIES_LPAR) {
 		/* ToDo: switch this via ppc_md */
 		printk("%c", c);
 	}
@@ -181,7 +178,7 @@
 void
 udbg_printSP(const char *s)
 {
-	if (_machine == _MACH_pSeries) {
+	if (naca->platform == PLATFORM_PSERIES) {
 		unsigned long sp;
 		asm("mr %0,1" : "=r" (sp) :);
 		if (s)
diff -Nru a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c
--- a/arch/ppc64/kernel/xics.c	Thu May  2 17:22:15 2002
+++ b/arch/ppc64/kernel/xics.c	Thu May  2 17:22:15 2002
@@ -17,14 +17,12 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/smp.h>
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/rtas.h>
 #include "i8259.h"
 #include "xics.h"
 #include <asm/ppcdebug.h>
 
-extern struct Naca *naca;
-
 void xics_enable_irq(u_int irq);
 void xics_disable_irq(u_int irq);
 void xics_mask_and_ack_irq(u_int irq);
@@ -233,9 +231,9 @@
 		}
 	} else if( vec == XICS_IRQ_SPURIOUS ) {
 		irq = -1;
-		printk("spurious PPC interrupt!\n");
-	} else
+	} else {
 		irq = real_irq_to_virt(vec) + XICS_IRQ_OFFSET;
+	}
 	return irq;
 }
 
@@ -371,7 +369,7 @@
 		xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real);
 	}
 
-	if (_machine == _MACH_pSeries) {
+	if (naca->platform == PLATFORM_PSERIES) {
 #ifdef CONFIG_SMP
 		for (i = 0; i < naca->processorCount; ++i) {
 			xics_info.per_cpu[i] =
@@ -385,7 +383,7 @@
 	/* actually iSeries does not use any of xics...but it has link dependencies
 	 * for now, except this new one...
 	 */
-	} else if (_machine == _MACH_pSeriesLP) {
+	} else if (naca->platform == PLATFORM_PSERIES_LPAR) {
 		ops = &pSeriesLP_ops;
 #endif
 	}
diff -Nru a/arch/ppc64/lib/checksum.S b/arch/ppc64/lib/checksum.S
--- a/arch/ppc64/lib/checksum.S	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/lib/checksum.S	Thu May  2 17:22:16 2002
@@ -15,7 +15,7 @@
 #include <linux/sys.h>
 #include <asm/processor.h>
 #include <asm/errno.h>
-#include "../kernel/ppc_asm.tmpl"
+#include <asm/ppc_asm.tmpl>
 
 /*
  * ip_fast_csum(r3=buf, r4=len) -- Optimized for IP header
diff -Nru a/arch/ppc64/lib/string.S b/arch/ppc64/lib/string.S
--- a/arch/ppc64/lib/string.S	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/lib/string.S	Thu May  2 17:22:16 2002
@@ -8,7 +8,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#include "../kernel/ppc_asm.tmpl"
+#include <asm/ppc_asm.tmpl>
 #include <asm/processor.h>
 #include <asm/errno.h>
 
diff -Nru a/arch/ppc64/mm/extable.c b/arch/ppc64/mm/extable.c
--- a/arch/ppc64/mm/extable.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/mm/extable.c	Thu May  2 17:22:16 2002
@@ -9,11 +9,47 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
-extern const struct exception_table_entry __start___ex_table[];
-extern const struct exception_table_entry __stop___ex_table[];
+extern struct exception_table_entry __start___ex_table[];
+extern struct exception_table_entry __stop___ex_table[];
+
+/*
+ * The exception table needs to be sorted because we use the macros
+ * which put things into the exception table in a variety of segments
+ * such as the prep, pmac, chrp, etc. segments as well as the init
+ * segment and the main kernel text segment.
+ */
+static inline void
+sort_ex_table(struct exception_table_entry *start,
+	      struct exception_table_entry *finish)
+{
+	struct exception_table_entry el, *p, *q;
+
+	/* insertion sort */
+	for (p = start + 1; p < finish; ++p) {
+		/* start .. p-1 is sorted */
+		if (p[0].insn < p[-1].insn) {
+			/* move element p down to its right place */
+			el = *p;
+			q = p;
+			do {
+				/* el comes before q[-1], move q[-1] up one */
+				q[0] = q[-1];
+				--q;
+			} while (q > start && el.insn < q[-1].insn);
+			*q = el;
+		}
+	}
+}
+
+void
+sort_exception_table(void)
+{
+	sort_ex_table(__start___ex_table, __stop___ex_table);
+}
 
 static inline unsigned long
 search_one_table(const struct exception_table_entry *first,
@@ -41,8 +77,22 @@
 {
 	unsigned long ret;
 
+#ifndef CONFIG_MODULES
+	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
 	if (ret) return ret;
+#else
+	/* The kernel is the last "module" -- no need to treat it special.  */
+	struct module *mp;
+	for (mp = module_list; mp != NULL; mp = mp->next) {
+		if (mp->ex_table_start == NULL)
+			continue;
+		ret = search_one_table(mp->ex_table_start,
+				       mp->ex_table_end - 1, addr);
+		if (ret)
+			return ret;
+	}
+#endif
 
 	return 0;
 }
diff -Nru a/arch/ppc64/mm/fault.c b/arch/ppc64/mm/fault.c
--- a/arch/ppc64/mm/fault.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/mm/fault.c	Thu May  2 17:22:16 2002
@@ -49,11 +49,6 @@
 void bad_page_fault(struct pt_regs *, unsigned long);
 void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
 
-#ifdef CONFIG_PPCDBG
-extern unsigned long get_srr0(void);
-extern unsigned long get_srr1(void);
-#endif
-
 /*
  * For 600- and 800-family processors, the error_code parameter is DSISR
  * for a data fault, SRR1 for an instruction fault.
@@ -66,9 +61,7 @@
 	siginfo_t info;
 	unsigned long code = SEGV_MAPERR;
 	unsigned long is_write = error_code & 0x02000000;
-	unsigned long mm_fault_return;
 
-	PPCDBG(PPCDBG_MM, "Entering do_page_fault: addr = 0x%16.16lx, error_code = %lx\n\tregs_trap = %lx, srr0 = %lx, srr1 = %lx\n", address, error_code, regs->trap, get_srr0(), get_srr1());
 	/*
 	 * Fortunately the bit assignments in SRR1 for an instruction
 	 * fault and DSISR for a data fault are mostly the same for the
@@ -98,23 +91,16 @@
 	}
 	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, address);
-	PPCDBG(PPCDBG_MM, "\tdo_page_fault: vma = 0x%16.16lx\n", vma);
-	if (!vma) {
-	        PPCDBG(PPCDBG_MM, "\tdo_page_fault: !vma\n");
+	if (!vma)
 		goto bad_area;
-	}
-	PPCDBG(PPCDBG_MM, "\tdo_page_fault: vma->vm_start = 0x%16.16lx, vma->vm_flags = 0x%16.16lx\n", vma->vm_start, vma->vm_flags);
+
 	if (vma->vm_start <= address) {
 		goto good_area;
 	}
-	if (!(vma->vm_flags & VM_GROWSDOWN)) {
-		PPCDBG(PPCDBG_MM, "\tdo_page_fault: vma->vm_flags = %lx, %lx\n", vma->vm_flags, VM_GROWSDOWN);
+	if (!(vma->vm_flags & VM_GROWSDOWN))
 		goto bad_area;
-	}
-	if (expand_stack(vma, address)) {
-		PPCDBG(PPCDBG_MM, "\tdo_page_fault: expand_stack\n");
+	if (expand_stack(vma, address))
 		goto bad_area;
-	}
 
 good_area:
 	code = SEGV_ACCERR;
@@ -132,16 +118,14 @@
 			goto bad_area;
 	}
 
+ survive:
 	/*
 	 * If for any reason at all we couldn't handle the fault,
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	PPCDBG(PPCDBG_MM, "\tdo_page_fault: calling handle_mm_fault\n");
-        mm_fault_return = handle_mm_fault(mm, vma, address, is_write);
-	PPCDBG(PPCDBG_MM, "\tdo_page_fault: handle_mm_fault = 0x%lx\n", 
-	       mm_fault_return);
-        switch(mm_fault_return) {
+        switch (handle_mm_fault(mm, vma, address, is_write)) {
+
         case 1:
                 current->min_flt++;
                 break;
@@ -166,7 +150,6 @@
 		info.si_errno = 0;
 		info.si_code = code;
 		info.si_addr = (void *) address;
-		PPCDBG(PPCDBG_SIGNAL, "Bad addr in user: 0x%lx\n", address);
 #ifdef CONFIG_XMON
 	        ifppcdebug(PPCDBG_SIGNALXMON)
         	    PPCDBG_ENTER_DEBUGGER_REGS(regs);
@@ -185,6 +168,11 @@
  */
 out_of_memory:
 	up_read(&mm->mmap_sem);
+	if (current->pid == 1) {
+		yield();
+		down_read(&mm->mmap_sem);
+		goto survive;
+	}
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
--- a/arch/ppc64/mm/init.c	Thu May  2 17:22:17 2002
+++ b/arch/ppc64/mm/init.c	Thu May  2 17:22:17 2002
@@ -57,10 +57,8 @@
 #include <asm/smp.h>
 #include <asm/machdep.h>
 #include <asm/tlb.h>
-#include <asm/Naca.h>
-#ifdef CONFIG_PPC_EEH
+#include <asm/naca.h>
 #include <asm/eeh.h>
-#endif
 
 #include <asm/ppcdebug.h>
 
@@ -85,7 +83,6 @@
 extern char _start[], _end[];
 extern char _stext[], etext[];
 extern struct task_struct *current_set[NR_CPUS];
-extern struct Naca *naca;
 
 void mm_init_ppc64(void);
 
@@ -158,13 +155,11 @@
 #ifdef CONFIG_PPC_ISERIES
 	return (void*)addr;
 #else
-#ifdef CONFIG_PPC_EEH
 	if(mem_init_done && (addr >> 60UL)) {
 		if (IS_EEH_TOKEN_DISABLED(addr))
-			return IO_TOKEN_TO_ADDR(addr);
+			return (void *)IO_TOKEN_TO_ADDR(addr);
 		return (void*)addr; /* already mapped address or EEH token. */
 	}
-#endif
 	return __ioremap(addr, size, _PAGE_NO_CACHE);
 #endif
 }
@@ -458,7 +453,7 @@
  * Do very early mm setup.
  */
 void __init mm_init_ppc64(void) {
-	struct Paca *paca;
+	struct paca_struct *lpaca;
 	unsigned long guard_page, index;
 
 	ppc_md.progress("MM:init", 0);
@@ -477,8 +472,8 @@
 
 	/* Setup guard pages for the Paca's */
 	for (index = 0; index < NR_CPUS; index++) {
-		paca = &xPaca[index];
-		guard_page = ((unsigned long)paca) + 0x1000;
+		lpaca = &paca[index];
+		guard_page = ((unsigned long)lpaca) + 0x1000;
 		ppc_md.hpte_updateboltedpp(PP_RXRX, guard_page);
 	}
 
diff -Nru a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c
--- a/arch/ppc64/xmon/xmon.c	Thu May  2 17:22:16 2002
+++ b/arch/ppc64/xmon/xmon.c	Thu May  2 17:22:16 2002
@@ -22,8 +22,8 @@
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
 #include <asm/mmu_context.h>
-#include <asm/Naca.h>
-#include <asm/Paca.h>
+#include <asm/naca.h>
+#include <asm/paca.h>
 #include <asm/ppcdebug.h>
 #include "nonstdio.h"
 #include "privinst.h"
@@ -123,12 +123,10 @@
 static void mem_check(void);
 static void mem_find_real(void);
 static void mem_find_vsid(void);
-static void mem_check_full_group(void);
 static void mem_check_pagetable_vsids (void);
 
 static void mem_map_check_slab(void);
 static void mem_map_lock_pages(void);
-static void mem_map_check_hash(void);
 static void mem_check_dup_rpn (void);
 static void debug_trace(void);
 
@@ -141,7 +139,6 @@
 extern int setjmp(u_int *);
 extern void longjmp(u_int *, int);
 extern unsigned long _ASR;
-extern struct Naca *naca;
 
 pte_t *find_linux_pte(pgd_t *pgdir, unsigned long va);	/* from htab.c */
 
@@ -540,7 +537,7 @@
 	int i;
 	struct bpt *bp;
 
-	if (_machine != _MACH_pSeries)
+	if (naca->platform != PLATFORM_PSERIES)
 		return;
 	bp = bpts;
 	for (i = 0; i < NBPTS; ++i, ++bp) {
@@ -571,7 +568,7 @@
 	struct bpt *bp;
 	unsigned instr;
 
-	if (_machine != _MACH_pSeries)
+	if (naca->platform != PLATFORM_PSERIES)
 		return;
 	if (!__is_processor(PV_POWER4)) {
 		set_dabr(0);
@@ -646,15 +643,9 @@
 			case 'c':
 				mem_check();
 				break;
-			case 'g':
-				mem_check_full_group();
-				break;
 			case 'j':
 				mem_map_check_slab();
 				break;
-			case 'h':
-				mem_map_check_hash();
-				break;
 			case 'f':
 				mem_find_real();
 				break;
@@ -1261,7 +1252,7 @@
 {
 	int i, cmd;
 	unsigned long val;
-	struct Paca*  ptrPaca = NULL;
+	struct paca_struct*  ptrPaca = NULL;
 	struct ItLpPaca*  ptrLpPaca = NULL;
 	struct ItLpRegSave*  ptrLpRegSave = NULL;
 
@@ -1283,7 +1274,7 @@
 
 		// Dump out relevant Paca data areas.
 		printf("Paca: \n");
-		ptrPaca = (struct Paca*)get_sprg3();
+		ptrPaca = get_paca();
     
 		printf("  Local Processor Control Area (LpPaca): \n");
 		ptrLpPaca = ptrPaca->xLpPacaPtr;
@@ -2502,34 +2493,6 @@
 	printf(" count of locked pages = %d \n", lock_count); 
 }
 
-
-
-void mem_map_check_hash()
-{
-	int i = max_mapnr;
-	
-	while (i-- > 0)  {
-		/* skip the reserved */
-		if (!PageReserved(mem_map+i)) {
-			if (((mem_map+i)->next_hash) != NULL) {
-				if ( REGION_ID((mem_map+i)->next_hash) != KERNEL_REGION_ID ) {
-					printf(" mem_map check hash - non c0 entry - "
-					       "address/value = %p %lx\n", mem_map+i,(mem_map+i)->next_hash);
-				} 
-				if ((unsigned long)((mem_map+i)->next_hash) ==  KERNELBASE){
-					printf(" mem_map check hash - 0x%lx  entry = %p \n",
-					       KERNELBASE, mem_map+i);
-				} 
-			}
-		} else {
-			if (page_count(mem_map+i) < 0) {
-				printf(" reserved page with negative count- entry = %lx \n", mem_map+i);
-			}
-		}
-	}
-	printf(" mem_map check hash completed \n");
-}
-
 void mem_check_dup_rpn ()
 {
 	unsigned long htab_size_bytes;
@@ -2737,70 +2700,6 @@
 
 	printf("\nDone -------------------\n");
 
-}
-
-
-void mem_check_full_group()
-{
-	unsigned long htab_size_bytes;
-	unsigned count;
-	unsigned count_array[] = {0,0,0,0,0,0,0,0,0}; 
-	unsigned i;
-	unsigned long htab_end;
-	HPTE *hpte1, *hpte2, *hpte3;
-	u64  rpn = 0;
-
-	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
-	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
-
-	printf("\nHardware Page Find full groups \n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("htab size      : %.16lx\n", htab_size_bytes);
-
-	for (hpte1 = htab_data.htab; (unsigned long)hpte1 < htab_end; hpte1= hpte1 + 8)
-	{
-		count = 0;
-		hpte2 = hpte1;
-		for (i=0; i<8; ++i)
-		{
-			if ( hpte2->dw0.dw0.v != 0 )
-			{
-				count++;
-			}
-			hpte2++;
-		}
-		if (count == 8 )
-		{
-			printf("  full group starting with entry %lx \n", hpte1);
-			hpte3 = hpte1;
-			for (i=0; i<8; ++i)
-			{
-				if ( hpte3->dw0.dw0.v != 0 )
-				{
-					printf(" entry number %d   \n",i);
-					printf("          vsid: %.13lx   api: %.2lx  hash: %.1lx\n", 
-					       (hpte3->dw0.dw0.avpn)>>5, 
-					       (hpte3->dw0.dw0.avpn) & 0x1f,
-					       (hpte3->dw0.dw0.h));
-					printf("          rpn: %.13lx \n", (hpte3->dw1.dw1.rpn)); 
-					// Dump out the memmap array entry address, corresponding virtual address, and reference count.
-					rpn = hpte3->dw1.dw1.rpn;
-					printf("          mem_map+rpn=%p, virtual@=%p, count=%lx \n", mem_map+rpn, (mem_map+rpn)->virtual, (mem_map+rpn)->count);
-				}
-				hpte3++;
-			}
-			if (xmon_interrupted())
-				return;
-		}
-
-		count_array[count]++;
-	}
-	for (i=1; i<9; ++i)
-	{
-		printf("  group count for size  %i = %lx \n", i, count_array[i]);
-	}
-
-	printf("\nDone -------------------\n");
 }
 
 static void debug_trace(void) {
diff -Nru a/arch/sparc/Config.help b/arch/sparc/Config.help
--- a/arch/sparc/Config.help	Thu May  2 17:22:17 2002
+++ b/arch/sparc/Config.help	Thu May  2 17:22:17 2002
@@ -34,6 +34,11 @@
   maintains both the SPARC32 and SPARC64 ports; its web page is
   available at <http://www.ultralinux.org/>.
 
+SPARC power management support
+CONFIG_SUN_PM
+  Enable power management and CPU standby features on supported 
+  SPARC platforms. 
+
 CONFIG_BLK_DEV_FD
   If you want to use the floppy disk drive(s) of your PC under Linux,
   say Y. Information about this driver, especially important for IBM
diff -Nru a/arch/sparc/config.in b/arch/sparc/config.in
--- a/arch/sparc/config.in	Thu May  2 17:22:16 2002
+++ b/arch/sparc/config.in	Thu May  2 17:22:16 2002
@@ -38,6 +38,7 @@
 define_bool CONFIG_SUN_IO y
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+define_bool CONFIG_SUN_PM y
 
 bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4
 if [ "$CONFIG_SUN4" != "y" ]; then
diff -Nru a/arch/sparc/defconfig b/arch/sparc/defconfig
--- a/arch/sparc/defconfig	Thu May  2 17:22:17 2002
+++ b/arch/sparc/defconfig	Thu May  2 17:22:17 2002
@@ -48,6 +48,7 @@
 CONFIG_SUN_IO=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_SUN_PM=y
 # CONFIG_SUN4 is not set
 # CONFIG_PCI is not set
 CONFIG_SUN_OPENPROMFS=m
diff -Nru a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
--- a/arch/sparc/kernel/Makefile	Thu May  2 17:22:16 2002
+++ b/arch/sparc/kernel/Makefile	Thu May  2 17:22:16 2002
@@ -32,6 +32,7 @@
 obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
 obj-$(CONFIG_SUN_AUXIO) += auxio.o
 obj-$(CONFIG_PCI) += ebus.o
+obj-$(CONFIG_SUN_PM) += apc.o pmc.o
 
 ifdef CONFIG_SUNOS_EMUL
 obj-y += sys_sunos.o sunos_ioctl.o
diff -Nru a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sparc/kernel/apc.c	Thu May  2 17:22:17 2002
@@ -0,0 +1,171 @@
+/* apc - Driver implementation for power management functions
+ * of Aurora Personality Chip (APC) on SPARCstation-4/5 and
+ * derivatives.
+ *
+ * Copyright (c) 2002 Eric Brower (ebrower@usa.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/pm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/uaccess.h>
+#include <asm/auxio.h>
+#include <asm/apc.h>
+
+/* Debugging
+ * 
+ * #define APC_DEBUG_LED
+ * #define APC_NO_IDLE
+ */
+
+#define APC_MINOR	MISC_DYNAMIC_MINOR
+#define APC_OBPNAME	"power-management"
+#define APC_DEVNAME "apc"
+
+volatile static u8 *regs; 
+static int apc_regsize;
+
+#define apc_readb(offs)			(sbus_readb(regs+offs))
+#define apc_writeb(val, offs) 	(sbus_writeb(val, regs+offs))
+
+/* 
+ * CPU idle callback function
+ * See .../arch/sparc/kernel/process.c
+ */
+void apc_swift_idle(void)
+{
+#ifdef APC_DEBUG_LED
+	set_auxio(0x00, AUXIO_LED); 
+#endif
+
+	apc_writeb(apc_readb(APC_IDLE_REG) | APC_IDLE_ON, APC_IDLE_REG);
+
+#ifdef APC_DEBUG_LED
+	set_auxio(AUXIO_LED, 0x00); 
+#endif
+} 
+
+static inline void apc_free(void)
+{
+	sbus_iounmap((unsigned long)regs, apc_regsize);
+}
+
+static int apc_open(struct inode *inode, struct file *f)
+{
+	return 0;
+}
+
+static int apc_release(struct inode *inode, struct file *f)
+{
+	return 0;
+}
+
+static int apc_ioctl(struct inode *inode, struct file *f, 
+		     unsigned int cmd, unsigned long arg)
+{
+	__u8 inarg;
+
+	switch (cmd) {
+		case APCIOCGFANCTL:
+			if(put_user(apc_readb(APC_FANCTL_REG) & APC_REGMASK, (__u8*) arg)) {
+				return -EFAULT;
+			}
+			break;
+		case APCIOCGCPWR:
+			if(put_user(apc_readb(APC_CPOWER_REG) & APC_REGMASK, (__u8*) arg)) {
+				return -EFAULT;
+			}
+			break;
+		case APCIOCGBPORT:
+			if(put_user(apc_readb(APC_BPORT_REG) & APC_BPMASK, (__u8*) arg)) {
+				return -EFAULT;
+			}
+			break;
+
+		case APCIOCSFANCTL:
+			if(get_user(inarg, (__u8*) arg)) {
+				return -EFAULT;
+			}
+			apc_writeb(inarg & APC_REGMASK, APC_FANCTL_REG);
+			break;
+		case APCIOCSCPWR:
+			if(get_user(inarg, (__u8*) arg)) {
+				return -EFAULT;
+			}
+			apc_writeb(inarg & APC_REGMASK, APC_CPOWER_REG);
+			break;
+		case APCIOCSBPORT:
+			if(get_user(inarg, (__u8*) arg)) {
+				return -EFAULT;
+			}
+			apc_writeb(inarg & APC_BPMASK, APC_BPORT_REG);
+			break;
+		default:
+			return -EINVAL;
+	};
+
+	return 0;
+}
+
+static struct file_operations apc_fops = {
+	ioctl:		apc_ioctl,
+	open:		apc_open,
+	release:	apc_release,
+};
+
+static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
+
+static int __init apc_probe(void)
+{
+	struct sbus_bus *sbus = NULL;
+	struct sbus_dev *sdev = NULL;
+	int iTmp = 0;
+	for_each_sbus(sbus) {
+		for_each_sbusdev(sdev, sbus) {
+			if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
+				goto sbus_done;
+			}
+		}
+	}
+
+sbus_done:
+	if (!sdev) {
+		return -ENODEV;
+	}
+
+	apc_regsize = sdev->reg_addrs[0].reg_size;
+	regs = (u8*) sbus_ioremap(&sdev->resource[0], 0, 
+				   apc_regsize, APC_OBPNAME);
+	if(NULL == regs) {
+		printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME);
+		return -ENODEV;
+	}
+
+	iTmp = misc_register(&apc_miscdev);
+	if (iTmp != 0) {
+		printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME);
+		apc_free();
+		return -ENODEV;
+	}
+
+#ifndef APC_NO_IDLE	
+	/* Assign power management IDLE handler */
+	pm_idle = apc_swift_idle;	
+#endif
+
+	printk(KERN_INFO "%s: power management initialized\n", APC_DEVNAME);
+	return 0;
+}
+
+/* This driver is not critical to the boot process
+ * and is easiest to ioremap when SBus is already
+ * initialized, so we install ourselves thusly:
+ */
+__initcall(apc_probe);
diff -Nru a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sparc/kernel/pmc.c	Thu May  2 17:22:17 2002
@@ -0,0 +1,99 @@
+/* pmc - Driver implementation for power management functions
+ * of Power Management Controller (PMC) on SPARCstation-Voyager.
+ *
+ * Copyright (c) 2002 Eric Brower (ebrower@usa.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/pm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/uaccess.h>
+#include <asm/auxio.h>
+
+/* Debug
+ *
+ * #define PMC_DEBUG_LED
+ * #define PMC_NO_IDLE
+ */
+
+#define PMC_MINOR	MISC_DYNAMIC_MINOR
+#define PMC_OBPNAME	"SUNW,pmc"
+#define PMC_DEVNAME "pmc"
+
+#define PMC_IDLE_REG	0x00
+#define PMC_IDLE_ON		0x01
+
+volatile static u8 *regs; 
+static int pmc_regsize;
+
+#define pmc_readb(offs)			(sbus_readb(regs+offs))
+#define pmc_writeb(val, offs) 	(sbus_writeb(val, regs+offs))
+
+/* 
+ * CPU idle callback function
+ * See .../arch/sparc/kernel/process.c
+ */
+void pmc_swift_idle(void)
+{
+#ifdef PMC_DEBUG_LED
+	set_auxio(0x00, AUXIO_LED); 
+#endif
+
+	pmc_writeb(pmc_readb(PMC_IDLE_REG) | PMC_IDLE_ON, PMC_IDLE_REG);
+
+#ifdef PMC_DEBUG_LED
+	set_auxio(AUXIO_LED, 0x00); 
+#endif
+} 
+
+static inline void pmc_free(void)
+{
+	sbus_iounmap((unsigned long)regs, pmc_regsize);
+}
+
+static int __init pmc_probe(void)
+{
+	struct sbus_bus *sbus = NULL;
+	struct sbus_dev *sdev = NULL;
+	for_each_sbus(sbus) {
+		for_each_sbusdev(sdev, sbus) {
+			if (!strcmp(sdev->prom_name, PMC_OBPNAME)) {
+				goto sbus_done;
+			}
+		}
+	}
+
+sbus_done:
+	if (!sdev) {
+		return -ENODEV;
+	}
+
+	pmc_regsize = sdev->reg_addrs[0].reg_size;
+	regs = (u8*) sbus_ioremap(&sdev->resource[0], 0, 
+				   pmc_regsize, PMC_OBPNAME);
+	if(NULL == regs) {
+		printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME);
+		return -ENODEV;
+	}
+
+#ifndef PMC_NO_IDLE
+	/* Assign power management IDLE handler */
+	pm_idle = pmc_swift_idle;	
+#endif
+
+	printk(KERN_INFO "%s: power management initialized\n", PMC_DEVNAME);
+	return 0;
+}
+
+/* This driver is not critical to the boot process
+ * and is easiest to ioremap when SBus is already
+ * initialized, so we install ourselves thusly:
+ */
+__initcall(pmc_probe);
diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
--- a/arch/sparc/kernel/process.c	Thu May  2 17:22:16 2002
+++ b/arch/sparc/kernel/process.c	Thu May  2 17:22:16 2002
@@ -27,6 +27,7 @@
 #include <linux/smp_lock.h>
 #include <linux/reboot.h>
 #include <linux/delay.h>
+#include <linux/pm.h>
 
 #include <asm/auxio.h>
 #include <asm/oplib.h>
@@ -40,6 +41,19 @@
 #include <asm/psr.h>
 #include <asm/elf.h>
 
+/* 
+ * Power management idle function 
+ * Set in pm platform drivers
+ */
+void (*pm_idle)(void);
+
+/* 
+ * Power-off handler instantiation for pm.h compliance
+ * This is done via auxio, but could be used as a fallback
+ * handler when auxio is not present-- unused for now...
+ */
+void (*pm_power_off)(void);
+
 extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
 
 struct task_struct *last_task_used_math = NULL;
@@ -91,8 +105,13 @@
 			}
 			restore_flags(flags);
 		}
-		check_pgt_cache();
+
+		while((!current->need_resched) && pm_idle) {
+				(*pm_idle)();
+		}
+
 		schedule();
+		check_pgt_cache();
 	}
 	ret = 0;
 out:
diff -Nru a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
--- a/arch/sparc/kernel/signal.c	Thu May  2 17:22:17 2002
+++ b/arch/sparc/kernel/signal.c	Thu May  2 17:22:17 2002
@@ -1173,9 +1173,23 @@
 		signr = dequeue_signal(&current->blocked, &info);
 		spin_unlock_irq(&current->sigmask_lock);
 
-		if (!signr) break;
+		if (!signr)
+			break;
 
 		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+			/* Do the syscall restart before we let the debugger
+			 * look at the child registers.
+			 */
+			if (restart_syscall &&
+			    (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+			     regs->u_regs[UREG_I0] == ERESTARTSYS ||
+			     regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
+				/* replay the system call when we are done */
+				regs->u_regs[UREG_I0] = orig_i0;
+				regs->pc -= 4;
+				regs->npc -= 4;
+				restart_syscall = 0;
+			}
 			current->exit_code = signr;
 			current->state = TASK_STOPPED;
 
@@ -1208,8 +1222,8 @@
 
 		ka = &current->sig->action[signr-1];
 
-		if(ka->sa.sa_handler == SIG_IGN) {
-			if(signr != SIGCHLD)
+		if (ka->sa.sa_handler == SIG_IGN) {
+			if (signr != SIGCHLD)
 				continue;
 
 			/* sys_wait4() grabs the master kernel lock, so
@@ -1221,12 +1235,12 @@
 				;
 			continue;
 		}
-		if(ka->sa.sa_handler == SIG_DFL) {
+		if (ka->sa.sa_handler == SIG_DFL) {
 			unsigned long exit_code = signr;
 
-			if(current->pid == 1)
+			if (current->pid == 1)
 				continue;
-			switch(signr) {
+			switch (signr) {
 			case SIGCONT: case SIGCHLD: case SIGWINCH:
 				continue;
 
@@ -1265,8 +1279,8 @@
 					struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP];
 					unsigned int ins[8];
 
-					while(rw &&
-					      !(((unsigned long) rw) & 0x3)) {
+					while (rw &&
+					       !(((unsigned long) rw) & 0x3)) {
 						copy_from_user(ins, &rw->ins[0], sizeof(ins));
 						printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
 						rw = (struct reg_window *)(unsigned long)ins[6];
@@ -1287,15 +1301,15 @@
 				/* NOT REACHED */
 			}
 		}
-		if(restart_syscall)
+		if (restart_syscall)
 			syscall_restart(orig_i0, regs, &ka->sa);
 		handle_signal(signr, ka, &info, oldset, regs, svr4_signal);
 		return 1;
 	}
-	if(restart_syscall &&
-	   (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
-	    regs->u_regs[UREG_I0] == ERESTARTSYS ||
-	    regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
+	if (restart_syscall &&
+	    (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+	     regs->u_regs[UREG_I0] == ERESTARTSYS ||
+	     regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
 		/* replay the system call when we are done */
 		regs->u_regs[UREG_I0] = orig_i0;
 		regs->pc -= 4;
diff -Nru a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
--- a/arch/sparc/kernel/sparc_ksyms.c	Thu May  2 17:22:16 2002
+++ b/arch/sparc/kernel/sparc_ksyms.c	Thu May  2 17:22:16 2002
@@ -22,6 +22,7 @@
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
 #endif
+#include <linux/pm.h>
 
 #include <asm/oplib.h>
 #include <asm/delay.h>
@@ -295,3 +296,6 @@
 EXPORT_SYMBOL_DOT(umul);
 EXPORT_SYMBOL_DOT(div);
 EXPORT_SYMBOL_DOT(udiv);
+
+/* Sun Power Management Idle Handler */
+EXPORT_SYMBOL(pm_idle);
diff -Nru a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
--- a/arch/sparc/kernel/systbls.S	Thu May  2 17:22:17 2002
+++ b/arch/sparc/kernel/systbls.S	Thu May  2 17:22:17 2002
@@ -50,7 +50,7 @@
 /*145*/	.long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 /*155*/	.long sys_fcntl64, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
-/*160*/	.long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
+/*160*/	.long sys_sched_setaffinity, sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
 /*165*/	.long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_setxattr
 /*170*/	.long sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
 /*175*/	.long sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
diff -Nru a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
--- a/arch/sparc/mm/init.c	Thu May  2 17:22:16 2002
+++ b/arch/sparc/mm/init.c	Thu May  2 17:22:16 2002
@@ -459,7 +459,7 @@
 	initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin));
 	initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
 
-	printk("Memory: %dk available (%dk kernel code, %dk data, %dk init, %ldk highmem) [%08lx,%08lx]\n",
+	printk(KERN_INFO "Memory: %dk available (%dk kernel code, %dk data, %dk init, %ldk highmem) [%08lx,%08lx]\n",
 	       nr_free_pages() << (PAGE_SHIFT-10),
 	       codepages << (PAGE_SHIFT-10),
 	       datapages << (PAGE_SHIFT-10), 
@@ -486,14 +486,14 @@
 		totalram_pages++;
 		num_physpages++;
 	}
-	printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+	printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
 	if (start < end)
-		printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+		printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 	for (; start < end; start += PAGE_SIZE) {
 		struct page *p = virt_to_page(start);
 
diff -Nru a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
--- a/arch/sparc64/kernel/binfmt_aout32.c	Thu May  2 17:22:17 2002
+++ b/arch/sparc64/kernel/binfmt_aout32.c	Thu May  2 17:22:17 2002
@@ -201,6 +201,7 @@
 	unsigned long error;
 	unsigned long fd_offset;
 	unsigned long rlim;
+	unsigned long orig_thr_flags;
 	int retval;
 
 	ex = *((struct exec *) bprm->buf);		/* exec-header */
@@ -305,8 +306,14 @@
 
 	set_brk(current->mm->start_brk, current->mm->brk);
 
+	/* Make sure STACK_TOP returns the right thing.  */
+	orig_thr_flags = current_thread_info()->flags;
+	current_thread_info()->flags |= _TIF_32BIT;
+
 	retval = setup_arg_pages(bprm);
 	if (retval < 0) { 
+		current_thread_info()->flags = orig_thr_flags;
+
 		/* Someone check-me: is this error path enough? */ 
 		send_sig(SIGKILL, current, 0); 
 		return retval;
@@ -314,7 +321,7 @@
 
 	current->mm->start_stack =
 		(unsigned long) create_aout32_tables((char *)bprm->p, bprm);
-	if (!(test_thread_flag(TIF_32BIT))) {
+	if (!(orig_thr_flags & _TIF_32BIT)) {
 		unsigned long pgd_cache;
 
 		pgd_cache = ((unsigned long)current->mm->pgd[0])<<11UL;
@@ -323,7 +330,6 @@
 				     : /* no outputs */
 				     : "r" (pgd_cache),
 				       "r" (TSB_REG), "i" (ASI_DMMU));
-		set_thread_flag(TIF_32BIT);
 	}
 	start_thread32(regs, ex.a_entry, current->mm->start_stack);
 	if (current->ptrace & PT_PTRACED)
diff -Nru a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
--- a/arch/sparc64/kernel/entry.S	Thu May  2 17:22:15 2002
+++ b/arch/sparc64/kernel/entry.S	Thu May  2 17:22:15 2002
@@ -1436,7 +1436,9 @@
 		 * %o7 for us.  Check performance counter stuff too.
 		 */
 		andn		%o7, _TIF_NEWCHILD, %l0
+#if CONFIG_SMP || CONFIG_PREEMPT
 		call		schedule_tail
+#endif
 		 stx		%l0, [%g6 + TI_FLAGS]
 		andcc		%l0, _TIF_PERFCTR, %g0
 		be,pt		%icc, 1f
diff -Nru a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
--- a/arch/sparc64/kernel/ioctl32.c	Thu May  2 17:22:16 2002
+++ b/arch/sparc64/kernel/ioctl32.c	Thu May  2 17:22:16 2002
@@ -77,6 +77,7 @@
 #include <asm/watchdog.h>
 #include <asm/module.h>
 #include <linux/soundcard.h>
+#include <linux/lp.h>
 
 #include <linux/atm.h>
 #include <linux/atmarp.h>
@@ -3908,6 +3909,8 @@
 COMPATIBLE_IOCTL(TCSETSW)
 COMPATIBLE_IOCTL(TCSETSF)
 COMPATIBLE_IOCTL(TIOCLINUX)
+COMPATIBLE_IOCTL(TIOCSTART)
+COMPATIBLE_IOCTL(TIOCSTOP)
 /* Little t */
 COMPATIBLE_IOCTL(TIOCGETD)
 COMPATIBLE_IOCTL(TIOCSETD)
@@ -3934,6 +3937,7 @@
 COMPATIBLE_IOCTL(TIOCGSERIAL)
 COMPATIBLE_IOCTL(TIOCSSERIAL)
 COMPATIBLE_IOCTL(TIOCSERGETLSR)
+COMPATIBLE_IOCTL(TIOCSLTC)
 /* Big F */
 COMPATIBLE_IOCTL(FBIOGTYPE)
 COMPATIBLE_IOCTL(FBIOSATTR)
@@ -3968,7 +3972,6 @@
  */
 COMPATIBLE_IOCTL(HDIO_GET_IDENTITY)
 COMPATIBLE_IOCTL(HDIO_SET_DMA)
-COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS)
 COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR)
 COMPATIBLE_IOCTL(HDIO_SET_NOWERR)
 COMPATIBLE_IOCTL(HDIO_SET_32BIT)
@@ -4070,6 +4073,8 @@
 COMPATIBLE_IOCTL(KIOCGRATE)
 /* Big S */
 COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
+COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
 COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
 COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
 COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
@@ -4078,11 +4083,11 @@
 COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
 COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
 /* Big T */
-COMPATIBLE_IOCTL(TUNSETNOCSUM);
-COMPATIBLE_IOCTL(TUNSETDEBUG);
-COMPATIBLE_IOCTL(TUNSETIFF);
-COMPATIBLE_IOCTL(TUNSETPERSIST);
-COMPATIBLE_IOCTL(TUNSETOWNER);
+COMPATIBLE_IOCTL(TUNSETNOCSUM)
+COMPATIBLE_IOCTL(TUNSETDEBUG)
+COMPATIBLE_IOCTL(TUNSETIFF)
+COMPATIBLE_IOCTL(TUNSETPERSIST)
+COMPATIBLE_IOCTL(TUNSETOWNER)
 /* Big V */
 COMPATIBLE_IOCTL(VT_SETMODE)
 COMPATIBLE_IOCTL(VT_GETMODE)
@@ -4234,6 +4239,7 @@
 COMPATIBLE_IOCTL(PPPIOCSMRU)
 COMPATIBLE_IOCTL(PPPIOCSMAXCID)
 COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
+COMPATIBLE_IOCTL(LPGETSTATUS)
 COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
 COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
 COMPATIBLE_IOCTL(PPPIOCGNPMODE)
@@ -4249,8 +4255,8 @@
 COMPATIBLE_IOCTL(PPPIOCATTCHAN)
 COMPATIBLE_IOCTL(PPPIOCGCHAN)
 /* PPPOX */
-COMPATIBLE_IOCTL(PPPOEIOCSFWD);
-COMPATIBLE_IOCTL(PPPOEIOCDFWD);
+COMPATIBLE_IOCTL(PPPOEIOCSFWD)
+COMPATIBLE_IOCTL(PPPOEIOCDFWD)
 /* CDROM stuff */
 COMPATIBLE_IOCTL(CDROMPAUSE)
 COMPATIBLE_IOCTL(CDROMRESUME)
@@ -4650,7 +4656,6 @@
 HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans)
 HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans)
 HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans)
-HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans)
 HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans)
 HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans)
 HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans)
@@ -4746,15 +4751,15 @@
 HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
 #endif /* LVM */
 #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
-HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version);
-HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique);
-HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique);
-HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap);
-HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs);
-HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs);
-HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs);
-HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma);
-HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx);
+HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version)
+HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique)
+HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique)
+HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap)
+HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs)
+HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs)
+HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs)
+HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma)
+HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx)
 #endif /* DRM */
 #if 0
 HANDLE_IOCTL(RTC32_IRQP_READ, do_rtc_ioctl)
diff -Nru a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
--- a/arch/sparc64/kernel/process.c	Thu May  2 17:22:16 2002
+++ b/arch/sparc64/kernel/process.c	Thu May  2 17:22:16 2002
@@ -42,6 +42,13 @@
 
 /* #define VERBOSE_SHOWREGS */
 
+/*
+ * Nothing special yet...
+ */
+void default_idle(void)
+{
+}
+
 #ifndef CONFIG_SMP
 
 /*
@@ -107,10 +114,8 @@
 
 	if (local_irq_count(cpu) == 0 &&
 	    local_bh_count(cpu) == 0 &&
-	    test_thread_flag(TIF_NEED_RESCHED)) {
-		current->state = TASK_RUNNING;
+	    test_thread_flag(TIF_NEED_RESCHED))
 		schedule();
-	}
 }
 #endif
 
@@ -422,6 +427,9 @@
 void flush_thread(void)
 {
 	struct thread_info *t = current_thread_info();
+
+	if (t->flags & _TIF_ABI_PENDING)
+		t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT);
 
 	if (t->task->mm) {
 		unsigned long pgd_cache = 0UL;
diff -Nru a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
--- a/arch/sparc64/kernel/ptrace.c	Thu May  2 17:22:17 2002
+++ b/arch/sparc64/kernel/ptrace.c	Thu May  2 17:22:17 2002
@@ -620,11 +620,10 @@
 	if (!(current->ptrace & PT_PTRACED))
 		return;
 	current->exit_code = SIGTRAP;
-	preempt_disable();
 	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
 	schedule();
-	preempt_enable();
+
 	/*
 	 * this isn't the same as continuing with a signal, but it will do
 	 * for normal use.  strace only continues with a signal if the
diff -Nru a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
--- a/arch/sparc64/kernel/rtrap.S	Thu May  2 17:22:17 2002
+++ b/arch/sparc64/kernel/rtrap.S	Thu May  2 17:22:17 2002
@@ -274,12 +274,12 @@
 #ifdef CONFIG_PREEMPT
 		ldsw			[%g6 + TI_PRE_COUNT], %l5
 		brnz			%l5, kern_fpucheck
-		 add			%l5, 1, %l6
+		 sethi			%hi(PREEMPT_ACTIVE), %l6
 		stw			%l6, [%g6 + TI_PRE_COUNT]
 		call			kpreempt_maybe
 		 nop
 		ba,pt			%xcc, rtrap
-		 stw			%l5, [%g6 + TI_PRE_COUNT]
+		 stw			%g0, [%g6 + TI_PRE_COUNT]
 #endif
 kern_fpucheck:	ldub			[%g6 + TI_FPDEPTH], %l5
 		brz,pt			%l5, rt_continue
diff -Nru a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
--- a/arch/sparc64/kernel/signal.c	Thu May  2 17:22:17 2002
+++ b/arch/sparc64/kernel/signal.c	Thu May  2 17:22:17 2002
@@ -709,15 +709,28 @@
 		signr = dequeue_signal(&current->blocked, &info);
 		spin_unlock_irq(&current->sigmask_lock);
 		
-		if (!signr) break;
+		if (!signr)
+			break;
 
 		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+			/* Do the syscall restart before we let the debugger
+			 * look at the child registers.
+			 */
+			if (restart_syscall &&
+			    (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+			     regs->u_regs[UREG_I0] == ERESTARTSYS ||
+			     regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
+				/* replay the system call when we are done */
+				regs->u_regs[UREG_I0] = orig_i0;
+				regs->tpc -= 4;
+				regs->tnpc -= 4;
+				restart_syscall = 0;
+			}
+
 			current->exit_code = signr;
-			preempt_disable();
 			current->state = TASK_STOPPED;
 			notify_parent(current, SIGCHLD);
 			schedule();
-			preempt_enable();
 			if (!(signr = current->exit_code))
 				continue;
 			current->exit_code = 0;
@@ -771,15 +784,13 @@
 			case SIGSTOP: {
 				struct signal_struct *sig;
 
+				current->state = TASK_STOPPED;
 				current->exit_code = signr;
 				sig = current->parent->sig;
-				preempt_disable();
-				current->state = TASK_STOPPED;
 				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags &
 				      SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
-				preempt_enable();
 				continue;
 			}
 
diff -Nru a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
--- a/arch/sparc64/kernel/signal32.c	Thu May  2 17:22:15 2002
+++ b/arch/sparc64/kernel/signal32.c	Thu May  2 17:22:15 2002
@@ -1383,15 +1383,28 @@
 		signr = dequeue_signal(&current->blocked, &info);
 		spin_unlock_irq(&current->sigmask_lock);
 		
-		if (!signr) break;
+		if (!signr)
+			break;
 
 		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+			/* Do the syscall restart before we let the debugger
+			 * look at the child registers.
+			 */
+			if (restart_syscall &&
+			    (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+			     regs->u_regs[UREG_I0] == ERESTARTSYS ||
+			     regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
+				/* replay the system call when we are done */
+				regs->u_regs[UREG_I0] = orig_i0;
+				regs->tpc -= 4;
+				regs->tnpc -= 4;
+				restart_syscall = 0;
+			}
+
 			current->exit_code = signr;
-			preempt_disable();
 			current->state = TASK_STOPPED;
 			notify_parent(current, SIGCHLD);
 			schedule();
-			preempt_enable();
 			if (!(signr = current->exit_code))
 				continue;
 			current->exit_code = 0;
@@ -1445,15 +1458,13 @@
 			case SIGSTOP: {
 				struct signal_struct *sig;
 
+				current->state = TASK_STOPPED;
 				current->exit_code = signr;
 				sig = current->parent->sig;
-				preempt_disable();
-				current->state = TASK_STOPPED;
 				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:
diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
--- a/arch/sparc64/kernel/smp.c	Thu May  2 17:22:15 2002
+++ b/arch/sparc64/kernel/smp.c	Thu May  2 17:22:15 2002
@@ -22,6 +22,7 @@
 #include <asm/head.h>
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
+#include <asm/tlbflush.h>
 
 #include <asm/irq.h>
 #include <asm/page.h>
@@ -614,6 +615,7 @@
 extern unsigned long xcall_flush_tlb_page;
 extern unsigned long xcall_flush_tlb_mm;
 extern unsigned long xcall_flush_tlb_range;
+extern unsigned long xcall_flush_tlb_kernel_range;
 extern unsigned long xcall_flush_tlb_all;
 extern unsigned long xcall_tlbcachesync;
 extern unsigned long xcall_flush_cache_all;
@@ -848,6 +850,18 @@
 	}
 }
 
+void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+	start &= PAGE_MASK;
+	end    = PAGE_ALIGN(end);
+	if (start != end) {
+		smp_cross_call(&xcall_flush_tlb_kernel_range,
+			       0, start, end);
+
+		__flush_tlb_kernel_range(start, end);
+	}
+}
+
 void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
 {
 	{
@@ -1153,7 +1167,6 @@
 unsigned long cache_decay_ticks;
 
 extern unsigned long cheetah_tune_scheduling(void);
-extern unsigned long timer_ticks_per_usec_quotient;
 
 static void __init smp_tune_scheduling(void)
 {
@@ -1196,24 +1209,39 @@
 			*((volatile unsigned long *)p);
 
 		/* Now the real measurement. */
-		__asm__ __volatile__("
-		b,pt	%%xcc, 1f
-		 rd	%%tick, %0
-
-		.align	64
-1:		ldx	[%2 + 0x000], %%g1
-		ldx	[%2 + 0x040], %%g2
-		ldx	[%2 + 0x080], %%g3
-		ldx	[%2 + 0x0c0], %%g5
-		add	%2, 0x100, %2
-		cmp	%2, %4
-		bne,pt	%%xcc, 1b
-		 nop
-	
-		rd	%%tick, %1"
-		: "=&r" (tick1), "=&r" (tick2), "=&r" (flush_base)
-		: "2" (flush_base), "r" (flush_base + ecache_size)
-		: "g1", "g2", "g3", "g5");
+		if (!SPARC64_USE_STICK) {
+		__asm__ __volatile__("b,pt	%%xcc, 1f\n\t"
+				     " rd	%%tick, %0\n\t"
+				     ".align	64\n"
+				     "1:\tldx	[%2 + 0x000], %%g1\n\t"
+				     "ldx	[%2 + 0x040], %%g2\n\t"
+				     "ldx	[%2 + 0x080], %%g3\n\t"
+				     "ldx	[%2 + 0x0c0], %%g5\n\t"
+				     "add	%2, 0x100, %2\n\t"
+				     "cmp	%2, %4\n\t"
+				     "bne,pt	%%xcc, 1b\n\t"
+				     " nop\n\t"
+				     "rd	%%tick, %1\n\t"
+				     : "=&r" (tick1), "=&r" (tick2), "=&r" (flush_base)
+				     : "2" (flush_base), "r" (flush_base + ecache_size)
+				     : "g1", "g2", "g3", "g5");
+		} else {
+		__asm__ __volatile__("b,pt	%%xcc, 1f\n\t"
+				     " rd	%%asr24, %0\n\t"
+				     ".align	64\n"
+				     "1:\tldx	[%2 + 0x000], %%g1\n\t"
+				     "ldx	[%2 + 0x040], %%g2\n\t"
+				     "ldx	[%2 + 0x080], %%g3\n\t"
+				     "ldx	[%2 + 0x0c0], %%g5\n\t"
+				     "add	%2, 0x100, %2\n\t"
+				     "cmp	%2, %4\n\t"
+				     "bne,pt	%%xcc, 1b\n\t"
+				     " nop\n\t"
+				     "rd	%%asr24, %1\n\t"
+				     : "=&r" (tick1), "=&r" (tick2), "=&r" (flush_base)
+				     : "2" (flush_base), "r" (flush_base + ecache_size)
+				     : "g1", "g2", "g3", "g5");
+		}
 
 		__restore_flags(flags);
 
@@ -1230,10 +1258,8 @@
 				   (ecache_size << 1));
 	}
 report:
-	/* Convert cpu ticks to jiffie ticks. */
-	cache_decay_ticks = ((long)cacheflush_time * timer_ticks_per_usec_quotient);
-	cache_decay_ticks >>= 32UL;
-	cache_decay_ticks = (cache_decay_ticks * HZ) / 1000;
+	/* Convert ticks/sticks to jiffies. */
+	cache_decay_ticks = cacheflush_time / timer_tick_offset;
 
 	printk("Using heuristic of %ld cycles, %ld ticks.\n",
 	       cacheflush_time, cache_decay_ticks);
diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
--- a/arch/sparc64/kernel/sparc64_ksyms.c	Thu May  2 17:22:16 2002
+++ b/arch/sparc64/kernel/sparc64_ksyms.c	Thu May  2 17:22:16 2002
@@ -42,6 +42,7 @@
 #include <asm/checksum.h>
 #include <asm/fpumacro.h>
 #include <asm/pgalloc.h>
+#include <asm/cacheflush.h>
 #ifdef CONFIG_SBUS
 #include <asm/sbus.h>
 #include <asm/dma.h>
diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	Thu May  2 17:22:17 2002
+++ b/arch/sparc64/kernel/sys_sparc32.c	Thu May  2 17:22:17 2002
@@ -4160,7 +4160,7 @@
 	u32 __unused[4];
 };
 
-extern asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
+asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
 {
 	struct __sysctl_args32 tmp;
 	int error;
@@ -4196,4 +4196,54 @@
 		copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
 	}
 	return error;
+}
+
+extern asmlinkage int sys_sched_setaffinity(pid_t pid, unsigned int len,
+					    unsigned long *user_mask_ptr);
+
+asmlinkage int sys32_sched_setaffinity(__kernel_pid_t32 pid, unsigned int len,
+				       u32 *user_mask_ptr)
+{
+	unsigned long kernel_mask;
+	mm_segment_t old_fs;
+	int ret;
+
+	if (get_user(kernel_mask, user_mask_ptr))
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_sched_setaffinity(pid,
+				    /* XXX Nice api... */
+				    sizeof(kernel_mask),
+				    &kernel_mask);
+	set_fs(old_fs);
+
+	return ret;
+}
+
+extern asmlinkage int sys_sched_getaffinity(pid_t pid, unsigned int len,
+					    unsigned long *user_mask_ptr);
+
+asmlinkage int sys32_sched_getaffinity(__kernel_pid_t32 pid, unsigned int len,
+				       u32 *user_mask_ptr)
+{
+	unsigned long kernel_mask;
+	mm_segment_t old_fs;
+	int ret;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_sched_getaffinity(pid,
+				    /* XXX Nice api... */
+				    sizeof(kernel_mask),
+				    &kernel_mask);
+	set_fs(old_fs);
+
+	if (ret == 0) {
+		if (put_user(kernel_mask, user_mask_ptr))
+			ret = -EFAULT;
+	}
+
+	return ret;
 }
diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
--- a/arch/sparc64/kernel/systbls.S	Thu May  2 17:22:16 2002
+++ b/arch/sparc64/kernel/systbls.S	Thu May  2 17:22:16 2002
@@ -51,7 +51,7 @@
 	.word sys32_setrlimit, sys_pivot_root, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
 /*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 sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
+/*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
 /*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys32_getdents
 	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
@@ -110,7 +110,7 @@
 	.word sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/	.word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 	.word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
-/*160*/	.word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install
+/*160*/	.word sys_sched_setaffinity, sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_utrap_install
 	.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_setxattr
 /*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
 	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
--- a/arch/sparc64/kernel/traps.c	Thu May  2 17:22:17 2002
+++ b/arch/sparc64/kernel/traps.c	Thu May  2 17:22:17 2002
@@ -16,6 +16,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/mm.h>
+#include <linux/init.h>
 
 #include <asm/delay.h>
 #include <asm/system.h>
@@ -397,7 +398,7 @@
 extern unsigned int cheetah_cee_trap_vector[], cheetah_cee_trap_vector_tl1[];
 extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector_tl1[];
 
-void cheetah_ecache_flush_init(void)
+void __init cheetah_ecache_flush_init(void)
 {
 	unsigned long largest_size, smallest_linesize, order;
 	char type[16];
@@ -528,12 +529,39 @@
 }
 
 #ifdef CONFIG_SMP
-unsigned long cheetah_tune_scheduling(void)
+unsigned long __init cheetah_tune_scheduling(void)
 {
 	unsigned long tick1, tick2, raw;
+	unsigned long flush_base = ecache_flush_physbase;
+	unsigned long flush_linesize = ecache_flush_linesize;
+	unsigned long flush_size = ecache_flush_size;
+
+	/* Run through the whole cache to guarentee the timed loop
+	 * is really displacing cache lines.
+	 */
+	__asm__ __volatile__("1: subcc	%0, %4, %0\n\t"
+			     "   bne,pt	%%xcc, 1b\n\t"
+			     "    ldxa	[%2 + %0] %3, %%g0\n\t"
+			     : "=&r" (flush_size)
+			     : "0" (flush_size), "r" (flush_base),
+			       "i" (ASI_PHYS_USE_EC), "r" (flush_linesize));
+
+	/* The flush area is 2 X Ecache-size, so cut this in half for
+	 * the timed loop.
+	 */
+	flush_base = ecache_flush_physbase;
+	flush_linesize = ecache_flush_linesize;
+	flush_size = ecache_flush_size >> 1;
 
 	__asm__ __volatile__("rd %%tick, %0" : "=r" (tick1));
-	cheetah_flush_ecache();
+
+	__asm__ __volatile__("1: subcc	%0, %4, %0\n\t"
+			     "   bne,pt	%%xcc, 1b\n\t"
+			     "    ldxa	[%2 + %0] %3, %%g0\n\t"
+			     : "=&r" (flush_size)
+			     : "0" (flush_size), "r" (flush_base),
+			       "i" (ASI_PHYS_USE_EC), "r" (flush_linesize));
+
 	__asm__ __volatile__("rd %%tick, %0" : "=r" (tick2));
 
 	raw = (tick2 - tick1);
@@ -1257,7 +1285,7 @@
 	/* "Recoverable" here means we try to yank the page from ever
 	 * being newly used again.  This depends upon a few things:
 	 * 1) Must be main memory, and AFAR must be valid.
-	 * 2) If we trapped from use, OK.
+	 * 2) If we trapped from user, OK.
 	 * 3) Else, if we trapped from kernel we must find exception
 	 *    table entry (ie. we have to have been accessing user
 	 *    space).
@@ -1678,7 +1706,7 @@
 extern void thread_info_offsets_are_bolixed_dave(void);
 
 /* Only invoked on boot processor. */
-void trap_init(void)
+void __init trap_init(void)
 {
 	/* Compile time sanity check. */
 	if (TI_TASK != offsetof(struct thread_info, task) ||
diff -Nru a/arch/sparc64/math-emu/math.c b/arch/sparc64/math-emu/math.c
--- a/arch/sparc64/math-emu/math.c	Thu May  2 17:22:17 2002
+++ b/arch/sparc64/math-emu/math.c	Thu May  2 17:22:17 2002
@@ -1,4 +1,4 @@
-/* $Id: math.c,v 1.12 2002/02/09 19:49:31 davem Exp $
+/* $Id: math.c,v 1.11 1999/12/20 05:02:25 davem Exp $
  * arch/sparc64/math-emu/math.c
  *
  * Copyright (C) 1997,1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -58,6 +58,12 @@
 #define FSTOD	0x0c9
 #define FSTOI	0x0d1
 #define FDTOI	0x0d2
+#define FXTOS	0x084 /* Only Ultra-III generates this. */
+#define FXTOD	0x088 /* Only Ultra-III generates this. */
+#if 0	/* Optimized inline in sparc64/kernel/entry.S */
+#define FITOS	0x0c4 /* Only Ultra-III generates this. */
+#endif
+#define FITOD	0x0c8 /* Only Ultra-III generates this. */
 /* FPOP2 */
 #define FCMPQ	0x053
 #define FCMPEQ	0x057
@@ -98,18 +104,18 @@
 	would_trap = (fsr & ((long)eflag << FSR_TEM_SHIFT)) != 0UL;
 
 	/* If trapping, we only want to signal one bit. */
-	if (would_trap != 0) {
+	if(would_trap != 0) {
 		eflag &= ((fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT);
-		if ((eflag & (eflag - 1)) != 0) {
-			if (eflag & FP_EX_INVALID)
+		if((eflag & (eflag - 1)) != 0) {
+			if(eflag & FP_EX_INVALID)
 				eflag = FP_EX_INVALID;
-			else if (eflag & FP_EX_OVERFLOW)
+			else if(eflag & FP_EX_OVERFLOW)
 				eflag = FP_EX_OVERFLOW;
-			else if (eflag & FP_EX_UNDERFLOW)
+			else if(eflag & FP_EX_UNDERFLOW)
 				eflag = FP_EX_UNDERFLOW;
-			else if (eflag & FP_EX_DIVZERO)
+			else if(eflag & FP_EX_DIVZERO)
 				eflag = FP_EX_DIVZERO;
-			else if (eflag & FP_EX_INEXACT)
+			else if(eflag & FP_EX_INEXACT)
 				eflag = FP_EX_INEXACT;
 		}
 	}
@@ -129,11 +135,11 @@
 	 *    CEXC just generated is OR'd into the
 	 *    existing value of AEXC.
 	 */
-	if (would_trap == 0)
+	if(would_trap == 0)
 		fsr |= ((long)eflag << FSR_AEXC_SHIFT);
 
 	/* If trapping, indicate fault trap type IEEE. */
-	if (would_trap != 0)
+	if(would_trap != 0)
 		fsr |= (1UL << 14);
 
 	current_thread_info()->xfsr[0] = fsr;
@@ -141,7 +147,7 @@
 	/* If we will not trap, advance the program counter over
 	 * the instruction being handled.
 	 */
-	if (would_trap == 0) {
+	if(would_trap == 0) {
 		regs->tpc = regs->tnpc;
 		regs->tnpc += 4;
 	}
@@ -176,9 +182,9 @@
 	long XR, xfsr;
 
 	if (tstate & TSTATE_PRIV)
-		die_if_kernel("FPQuad from kernel", regs);
+		die_if_kernel("unfinished/unimplemented FPop from kernel", regs);
 	if (test_thread_flag(TIF_32BIT))
-		pc &= 0xffffffff;
+		pc = (u32)pc;
 	if (get_user(insn, (u32 *)pc) != -EFAULT) {
 		if ((insn & 0xc1f80000) == 0x81a00000) /* FPOP1 */ {
 			switch ((insn >> 5) & 0x1ff) {
@@ -218,6 +224,14 @@
 			case FSTOD: TYPE(2,2,1,1,1,0,0); break;
 			case FSTOI: TYPE(2,1,0,1,1,0,0); break;
 			case FDTOI: TYPE(2,1,0,2,1,0,0); break;
+
+			/* Only Ultra-III generates these */
+			case FXTOS: TYPE(2,1,1,2,0,0,0); break;
+			case FXTOD: TYPE(2,2,1,2,0,0,0); break;
+#if 0			/* Optimized inline in sparc64/kernel/entry.S */
+			case FITOS: TYPE(2,1,1,1,0,0,0); break;
+#endif
+			case FITOD: TYPE(2,2,1,1,0,0,0); break;
 			}
 		}
 		else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ {
@@ -421,6 +435,13 @@
 		/* int to float */
 		case FITOQ: IR = rs2->s; FP_FROM_INT_Q (QR, IR, 32, int); break;
 		case FXTOQ: XR = rs2->d; FP_FROM_INT_Q (QR, XR, 64, long); break;
+		/* Only Ultra-III generates these */
+		case FXTOS: XR = rs2->d; FP_FROM_INT_S (SR, XR, 64, long); break;
+		case FXTOD: XR = rs2->d; FP_FROM_INT_D (DR, XR, 64, long); break;
+#if 0		/* Optimized inline in sparc64/kernel/entry.S */
+		case FITOS: IR = rs2->s; FP_FROM_INT_S (SR, IR, 32, int); break;
+#endif
+		case FITOD: IR = rs2->s; FP_FROM_INT_D (DR, IR, 32, int); break;
 		/* float to float */
 		case FSTOD: FP_CONV (D, S, 1, 1, DR, SB); break;
 		case FSTOQ: FP_CONV (Q, S, 2, 1, QR, SB); break;
@@ -459,7 +480,7 @@
 			}
 		}
 
-		if (_fex != 0)
+		if(_fex != 0)
 			return record_exception(regs, _fex);
 
 		/* Success and no exceptions detected. */
diff -Nru a/arch/sparc64/mm/generic.c b/arch/sparc64/mm/generic.c
--- a/arch/sparc64/mm/generic.c	Thu May  2 17:22:16 2002
+++ b/arch/sparc64/mm/generic.c	Thu May  2 17:22:16 2002
@@ -13,6 +13,7 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
+#include <asm/tlbflush.h>
 
 static inline void forget_pte(pte_t page)
 {
diff -Nru a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
--- a/arch/sparc64/mm/ultra.S	Thu May  2 17:22:17 2002
+++ b/arch/sparc64/mm/ultra.S	Thu May  2 17:22:17 2002
@@ -201,6 +201,23 @@
 	retl
 /*IC19*/ wrpr		%g5, 0x0, %pstate
 
+	.align		32
+	.globl		__flush_tlb_kernel_range
+__flush_tlb_kernel_range:	/* %o0=start, %o1=end */
+	cmp		%o0, %o1
+	be,pn		%xcc, 2f
+	 sethi		%hi(PAGE_SIZE), %o4
+	sub		%o1, %o0, %o3
+	sub		%o3, %o4, %o3
+	or		%o0, 0x20, %o0		! Nucleus
+1:	stxa		%g0, [%o0 + %o3] ASI_DMMU_DEMAP
+	stxa		%g0, [%o0 + %o3] ASI_IMMU_DEMAP
+	membar		#Sync
+	brnz,pt		%o3, 1b
+	 sub		%o3, %o4, %o3
+2:	retl
+	 flush		%g6
+
 __spitfire_flush_tlb_mm_slow:
 	rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
@@ -482,6 +499,26 @@
 	 sub		%g3, %g2, %g3
 	stxa		%g7, [%g4] ASI_DMMU
 	retry
+	nop
+	nop
+
+	.globl		xcall_flush_tlb_kernel_range
+xcall_flush_tlb_kernel_range:
+	sethi		%hi(PAGE_SIZE - 1), %g2
+	or		%g2, %lo(PAGE_SIZE - 1), %g2
+	andn		%g1, %g2, %g1
+	andn		%g7, %g2, %g7
+	sub		%g7, %g1, %g3
+	add		%g2, 1, %g2
+	sub		%g3, %g2, %g3
+	or		%g1, 0x20, %g1		! Nucleus
+1:	stxa		%g0, [%g1 + %g3] ASI_DMMU_DEMAP
+	stxa		%g0, [%g1 + %g3] ASI_IMMU_DEMAP
+	membar		#Sync
+	brnz,pt		%g3, 1b
+	 sub		%g3, %g2, %g3
+	retry
+	nop
 	nop
 	nop
 
diff -Nru a/arch/sparc64/solaris/signal.c b/arch/sparc64/solaris/signal.c
--- a/arch/sparc64/solaris/signal.c	Thu May  2 17:22:17 2002
+++ b/arch/sparc64/solaris/signal.c	Thu May  2 17:22:17 2002
@@ -6,6 +6,7 @@
 
 #include <linux/types.h>
 #include <linux/smp_lock.h>
+#include <linux/errno.h>
 
 #include <asm/uaccess.h>
 #include <asm/svr4.h>
diff -Nru a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
--- a/drivers/acorn/block/fd1772.c	Thu May  2 17:22:16 2002
+++ b/drivers/acorn/block/fd1772.c	Thu May  2 17:22:16 2002
@@ -202,7 +202,6 @@
 #define MAX_DISK_SIZE 720
 
 static int floppy_sizes[256];
-static int floppy_blocksizes[256];
 
 /* current info on each unit */
 static struct archy_floppy_struct {
@@ -1614,7 +1613,6 @@
 			floppy_sizes[i] = MAX_DISK_SIZE;
 
 	blk_size[MAJOR_NR] = floppy_sizes;
-	blksize_size[MAJOR_NR] = floppy_blocksizes;
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request);
 
 	config_types();
diff -Nru a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
--- a/drivers/acorn/block/mfmhd.c	Thu May  2 17:22:16 2002
+++ b/drivers/acorn/block/mfmhd.c	Thu May  2 17:22:16 2002
@@ -195,7 +195,6 @@
 
 static struct hd_struct mfm[MFM_MAXDRIVES << 6];
 static int mfm_sizes[MFM_MAXDRIVES << 6];
-static int mfm_blocksizes[MFM_MAXDRIVES << 6];
 static DECLARE_WAIT_QUEUE_HEAD(mfm_wait_open);
 
 /* Stuff from the assembly routines */
@@ -1314,12 +1313,6 @@
 static void mfm_geninit (void)
 {
 	int i;
-
-	for (i = 0; i < (MFM_MAXDRIVES << 6); i++) {
-		/* Can't increase this - if you do all hell breaks loose */
-		mfm_blocksizes[i] = 1024;
-	}
-	blksize_size[MAJOR_NR] = mfm_blocksizes;
 
 	mfm_drives = mfm_initdrives();
 
diff -Nru a/drivers/acorn/net/etherh.c b/drivers/acorn/net/etherh.c
--- a/drivers/acorn/net/etherh.c	Thu May  2 17:22:17 2002
+++ b/drivers/acorn/net/etherh.c	Thu May  2 17:22:17 2002
@@ -513,7 +513,7 @@
 		if (i == 6)
 			return 0;
 	}
-	return ENODEV;
+	return -ENODEV;
 }
 
 /*
@@ -524,7 +524,7 @@
 	unsigned int serial;
 
 	if (system_serial_low == 0 && system_serial_high == 0)
-		return ENODEV;
+		return -ENODEV;
 
 	serial = system_serial_low | system_serial_high;
 
diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c
--- a/drivers/block/DAC960.c	Thu May  2 17:22:17 2002
+++ b/drivers/block/DAC960.c	Thu May  2 17:22:17 2002
@@ -1962,7 +1962,6 @@
       Controller->MaxBlocksPerCommand;
   Controller->GenericDiskInfo.part = Controller->DiskPartitions;
   Controller->GenericDiskInfo.sizes = Controller->PartitionSizes;
-  blksize_size[MajorNumber] = Controller->BlockSizes;
   /*
     Complete initialization of the Generic Disk Information structure.
   */
@@ -2044,10 +2043,6 @@
 	      LogicalDeviceInfo->ConfigurableDeviceSize;
 	  else GenericDiskInfo->part[MinorNumber].nr_sects = 0;
 	}
-      for (i = 0; i < DAC960_MaxPartitions; i++)
-	if (GenericDiskInfo->part[MinorNumber].nr_sects > 0)
-	  Controller->BlockSizes[MinorNumber + i] = BLOCK_SIZE;
-	else Controller->BlockSizes[MinorNumber + i] = 0;
     }
 }
 
diff -Nru a/drivers/block/DAC960.h b/drivers/block/DAC960.h
--- a/drivers/block/DAC960.h	Thu May  2 17:22:17 2002
+++ b/drivers/block/DAC960.h	Thu May  2 17:22:17 2002
@@ -2474,7 +2474,6 @@
   } FW;
   DiskPartition_T DiskPartitions[DAC960_MinorCount];
   int PartitionSizes[DAC960_MinorCount];
-  int BlockSizes[DAC960_MinorCount];
   unsigned char ProgressBuffer[DAC960_ProgressBufferSize];
   unsigned char UserStatusBuffer[DAC960_UserMessageSize];
 }
diff -Nru a/drivers/block/acsi.c b/drivers/block/acsi.c
--- a/drivers/block/acsi.c	Thu May  2 17:22:17 2002
+++ b/drivers/block/acsi.c	Thu May  2 17:22:17 2002
@@ -243,7 +243,6 @@
 
 static int				NDevices = 0;
 static int				acsi_sizes[MAX_DEV<<4] = { 0, };
-static int				acsi_blocksizes[MAX_DEV<<4] = { 0, };
 static struct hd_struct	acsi_part[MAX_DEV<<4] = { {0,0}, };
 static int 				access_count[MAX_DEV] = { 0, };
 static char 			busy[MAX_DEV] = { 0, };
@@ -1738,9 +1737,6 @@
 			NDevices, n_slm );
 #endif
 					 
-	for( i = 0; i < (MAX_DEV << 4); i++ )
-		acsi_blocksizes[i] = 1024;
-	blksize_size[MAJOR_NR] = acsi_blocksizes;
 	for( i = 0; i < NDevices; ++i )
 		register_disk(&acsi_gendisk, mk_kdev(MAJOR_NR,i<<4),
 				(acsi_info[i].type==HARDDISK)?1<<4:1,
diff -Nru a/drivers/block/amiflop.c b/drivers/block/amiflop.c
--- a/drivers/block/amiflop.c	Thu May  2 17:22:17 2002
+++ b/drivers/block/amiflop.c	Thu May  2 17:22:17 2002
@@ -141,7 +141,6 @@
 
 /* defaults for 3 1/2" HD-Disks */
 static int floppy_sizes[256]={880,880,880,880,720,720,720,720,};
-static int floppy_blocksizes[256];
 /* hardsector size assumed to be 512 */
 
 static int amiga_read(int), dos_read(int);
@@ -1858,7 +1857,6 @@
 	post_write_timer.function = post_write;
   
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &amiflop_lock);
-	blksize_size[MAJOR_NR] = floppy_blocksizes;
 	blk_size[MAJOR_NR] = floppy_sizes;
 
 	for (i = 0; i < 128; i++)
diff -Nru a/drivers/block/ataflop.c b/drivers/block/ataflop.c
--- a/drivers/block/ataflop.c	Thu May  2 17:22:16 2002
+++ b/drivers/block/ataflop.c	Thu May  2 17:22:16 2002
@@ -220,7 +220,6 @@
 static struct atari_disk_type default_params[FD_MAX_UNITS];
 
 static int floppy_sizes[256];
-static int floppy_blocksizes[256];
 
 /* current info on each unit */
 static struct atari_floppy_struct {
@@ -2012,7 +2011,6 @@
 			floppy_sizes[i] = MAX_DISK_SIZE;
 
 	blk_size[MAJOR_NR] = floppy_sizes;
-	blksize_size[MAJOR_NR] = floppy_blocksizes;
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &ataflop_lock);
 
 	printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n",
diff -Nru a/drivers/block/blkpg.c b/drivers/block/blkpg.c
--- a/drivers/block/blkpg.c	Thu May  2 17:22:15 2002
+++ b/drivers/block/blkpg.c	Thu May  2 17:22:15 2002
@@ -241,7 +241,7 @@
 		case BLKFRASET:
 			if(!capable(CAP_SYS_ADMIN))
 				return -EACCES;
-			ra_pages = blk_get_ra_pages(dev);
+			ra_pages = blk_get_ra_pages(bdev);
 			if (ra_pages == NULL)
 				return -ENOTTY;
 			*ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
@@ -251,7 +251,7 @@
 		case BLKFRAGET:
 			if (!arg)
 				return -EINVAL;
-			ra_pages = blk_get_ra_pages(dev);
+			ra_pages = blk_get_ra_pages(bdev);
 			if (ra_pages == NULL)
 				return -ENOTTY;
 			return put_user((*ra_pages * PAGE_CACHE_SIZE) / 512,
@@ -304,7 +304,7 @@
 
 		case BLKBSZGET:
 			/* get the logical block size (cf. BLKSSZGET) */
-			intval = block_size(dev);
+			intval = block_size(bdev);
 			return put_user(intval, (int *) arg);
 
 		case BLKBSZSET:
@@ -320,7 +320,7 @@
 				return -EINVAL;
 			if (bd_claim(bdev, &holder) < 0)
 				return -EBUSY;
-			set_blocksize(dev, intval);
+			set_blocksize(bdev, intval);
 			bd_release(bdev);
 			return 0;
 
diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c	Thu May  2 17:22:17 2002
+++ b/drivers/block/cciss.c	Thu May  2 17:22:17 2002
@@ -349,11 +349,6 @@
 			continue;
 		hba[ctlr]->hd[i << NWD_SHIFT].nr_sects = 
 		hba[ctlr]->sizes[i << NWD_SHIFT] = drv->nr_blocks;
-
-		/* for each partition */ 
-		for(j=0; j<MAX_PART; j++)
-			hba[ctlr]->blocksizes[(i<<NWD_SHIFT) + j] = 1024; 
-
 		//hba[ctlr]->gendisk.nr_real++;
 		(BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->block_size;
 	}
@@ -834,7 +829,6 @@
          */
 	memset(hba[ctlr]->hd,         0, sizeof(struct hd_struct) * 256);
         memset(hba[ctlr]->sizes,      0, sizeof(int) * 256);
-        memset(hba[ctlr]->blocksizes, 0, sizeof(int) * 256);
         memset(hba[ctlr]->drv,        0, sizeof(drive_info_struct)
 						* CISS_MAX_LUN);
         hba[ctlr]->gendisk.nr_real = 0;
@@ -1343,9 +1337,6 @@
                 invalidate_device(kdev, 1);
                 gdev->part[minor].start_sect = 0;
                 gdev->part[minor].nr_sects = 0;
-
-                /* reset the blocksize so we can read the partition table */
-                blksize_size[MAJOR_NR+ctlr][minor] = 1024;
         }
 
 	++hba[ctlr]->num_luns;
@@ -2539,9 +2530,6 @@
 	blk_queue_max_phys_segments(q, MAXSGENTRIES);
 
 	blk_queue_max_sectors(q, 512);
-
-	/* fill in the other Kernel structs */
-	blksize_size[MAJOR_NR+i] = hba[i]->blocksizes;
 
 	/* Fill in the gendisk data */ 	
 	hba[i]->gendisk.major = MAJOR_NR + i;
diff -Nru a/drivers/block/cciss.h b/drivers/block/cciss.h
--- a/drivers/block/cciss.h	Thu May  2 17:22:15 2002
+++ b/drivers/block/cciss.h	Thu May  2 17:22:15 2002
@@ -85,7 +85,6 @@
 	   // indexed by minor numbers
 	struct hd_struct hd[256];
 	int		 sizes[256];
-	int              blocksizes[256];
 #ifdef CONFIG_CISS_SCSI_TAPE
 	void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
 #endif
diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
--- a/drivers/block/cpqarray.c	Thu May  2 17:22:16 2002
+++ b/drivers/block/cpqarray.c	Thu May  2 17:22:16 2002
@@ -102,7 +102,6 @@
 
 static struct hd_struct * ida;
 static int * ida_sizes;
-static int * ida_blocksizes;
 static struct gendisk ida_gendisk[MAX_CTLR];
 
 static struct proc_dir_entry *proc_array;
@@ -178,10 +177,6 @@
 		ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)] =
 				drv->nr_blks;
 
-		for(j=0; j<16; j++)
-			ida_blocksizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =
-				1024;
-
 		(BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->blk_size;
 		ida_gendisk[ctlr].nr_real++;
 	}
@@ -343,7 +338,6 @@
 	remove_proc_entry("cpqarray", proc_root_driver);
 	kfree(ida);
 	kfree(ida_sizes);
-	kfree(ida_blocksizes);
 }
 #endif /* MODULE */
 
@@ -384,18 +378,8 @@
 		return(num_cntlrs_reg);
 	}
 
-	ida_blocksizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
-	if(ida_blocksizes==NULL)
-	{
-		kfree(ida);
-		kfree(ida_sizes); 
-		printk( KERN_ERR "cpqarray: out of memory");
-		return(num_cntlrs_reg);
-	}
-
 	memset(ida, 0, sizeof(struct hd_struct)*nr_ctlr*NWD*16);
 	memset(ida_sizes, 0, sizeof(int)*nr_ctlr*NWD*16);
-	memset(ida_blocksizes, 0, sizeof(int)*nr_ctlr*NWD*16);
 	memset(ida_gendisk, 0, sizeof(struct gendisk)*MAX_CTLR);
 
 		/* 
@@ -453,7 +437,6 @@
 			{
 				kfree(ida);
 				kfree(ida_sizes);
-				kfree(ida_blocksizes);
 			}
                 	return(num_cntlrs_reg);
 	
@@ -481,8 +464,6 @@
 		/* This is a driver limit and could be eliminated. */
 		blk_queue_max_phys_segments(q, SG_MAX);
 
-		blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256);
-
 		ida_gendisk[i].major = MAJOR_NR + i;
 		ida_gendisk[i].major_name = "ida";
 		ida_gendisk[i].minor_shift = NWD_SHIFT;
@@ -1512,7 +1493,6 @@
 	 */
 	memset(ida+(ctlr*256),            0, sizeof(struct hd_struct)*NWD*16);
 	memset(ida_sizes+(ctlr*256),      0, sizeof(int)*NWD*16);
-	memset(ida_blocksizes+(ctlr*256), 0, sizeof(int)*NWD*16);
 	memset(hba[ctlr]->drv,            0, sizeof(drv_info_t)*NWD);
 	ida_gendisk[ctlr].nr_real = 0;
 
diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c
--- a/drivers/block/floppy.c	Thu May  2 17:22:16 2002
+++ b/drivers/block/floppy.c	Thu May  2 17:22:16 2002
@@ -478,7 +478,6 @@
 static struct floppy_struct user_params[N_DRIVE];
 
 static int floppy_sizes[256];
-static int floppy_blocksizes[256];
 
 /*
  * The driver is trying to determine the correct media format
@@ -3881,6 +3880,12 @@
 		if (cf)
 			UDRS->generation++;
 		if (NO_GEOM){
+#if 0
+	/*
+	 * What the devil is going on here?  We are not guaranteed to do
+	 * any IO and ENXIO case is nothing but ENOMEM in disguise - it
+	 * happens if and only if buffer cache is out of memory.  WTF?
+	 */
 			/* auto-sensing */
 			int size = floppy_blocksizes[minor(dev)];
 			if (!size)
@@ -3895,6 +3900,9 @@
 			wait_on_buffer(bh);
 			brelse(bh);
 			return 0;
+#endif
+			process_fd_request();
+			return 0;
 		}
 		if (cf)
 			poll_drive(0, FD_RAW_NEED_DISK);
@@ -4183,7 +4191,6 @@
 			floppy_sizes[i] = MAX_DISK_SIZE;
 
 	blk_size[MAJOR_NR] = floppy_sizes;
-	blksize_size[MAJOR_NR] = floppy_blocksizes;
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &floppy_lock);
 	reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
 	config_types();
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Thu May  2 17:22:16 2002
+++ b/drivers/block/ll_rw_blk.c	Thu May  2 17:22:16 2002
@@ -71,15 +71,6 @@
 int * blk_size[MAX_BLKDEV];
 
 /*
- * blksize_size contains the size of all block-devices:
- *
- * blksize_size[MAJOR][MINOR]
- *
- * if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
- */
-int * blksize_size[MAX_BLKDEV];
-
-/*
  * How many reqeusts do we allocate per queue,
  * and how many do we "batch" on freeing them?
  */
@@ -117,10 +108,10 @@
  *
  * Will return NULL if the request queue cannot be located.
  */
-unsigned long *blk_get_ra_pages(kdev_t dev)
+unsigned long *blk_get_ra_pages(struct block_device *bdev)
 {
 	unsigned long *ret = NULL;
-	request_queue_t *q = blk_get_queue(dev);
+	request_queue_t *q = blk_get_queue(to_kdev_t(bdev->bd_dev));
 
 	if (q)
 		ret = &q->ra_pages;
@@ -311,9 +302,203 @@
 	q->queue_lock = lock;
 }
 
+/**
+ * blk_queue_free_tags - release tag maintenance info
+ * @q:  the request queue for the device
+ *
+ *  Notes:
+ *    blk_cleanup_queue() will take care of calling this function, if tagging
+ *    has been used. So there's usually no need to call this directly, unless
+ *    tagging is just being disabled but the queue remains in function.
+ **/
+void blk_queue_free_tags(request_queue_t *q)
+{
+	struct blk_queue_tag *bqt = q->queue_tags;
+
+	if (!bqt)
+		return;
+
+	BUG_ON(bqt->busy);
+	BUG_ON(!list_empty(&bqt->busy_list));
+
+	kfree(bqt->tag_index);
+	bqt->tag_index = NULL;
+
+	kfree(bqt->tag_map);
+	bqt->tag_map = NULL;
+
+	kfree(bqt);
+	q->queue_tags = NULL;
+	q->queue_flags &= ~(1 << QUEUE_FLAG_QUEUED);
+}
+
+/**
+ * blk_queue_init_tags - initialize the queue tag info
+ * @q:  the request queue for the device
+ * @depth:  the maximum queue depth supported
+ **/
+int blk_queue_init_tags(request_queue_t *q, int depth)
+{
+	struct blk_queue_tag *tags;
+	int bits, i;
+
+	if (depth > queue_nr_requests)
+		depth = queue_nr_requests;
+
+	tags = kmalloc(sizeof(struct blk_queue_tag),GFP_ATOMIC);
+	if (!tags)
+		goto fail;
+
+	tags->tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC);
+	if (!tags->tag_index)
+		goto fail_index;
+
+	bits = (depth / BLK_TAGS_PER_LONG) + 1;
+	tags->tag_map = kmalloc(bits * sizeof(unsigned long), GFP_ATOMIC);
+	if (!tags->tag_map)
+		goto fail_map;
+
+	memset(tags->tag_index, depth * sizeof(struct request *), 0);
+	memset(tags->tag_map, bits * sizeof(unsigned long), 0);
+	INIT_LIST_HEAD(&tags->busy_list);
+	tags->busy = 0;
+	tags->max_depth = depth;
+
+	/*
+	 * set the upper bits if the depth isn't a multiple of the word size
+	 */
+	for (i = depth; i < bits * BLK_TAGS_PER_LONG; i++)
+		set_bit(i, tags->tag_map);
+
+	/*
+	 * assign it, all done
+	 */
+	q->queue_tags = tags;
+	q->queue_flags |= (1 << QUEUE_FLAG_QUEUED);
+	return 0;
+
+fail_map:
+	kfree(tags->tag_index);
+fail_index:
+	kfree(tags);
+fail:
+	return -ENOMEM;
+}
+
+/**
+ * blk_queue_end_tag - end tag operations for a request
+ * @q:  the request queue for the device
+ * @tag:  the tag that has completed
+ *
+ *  Description:
+ *    Typically called when end_that_request_first() returns 0, meaning
+ *    all transfers have been done for a request. It's important to call
+ *    this function before end_that_request_last(), as that will put the
+ *    request back on the free list thus corrupting the internal tag list.
+ *
+ *  Notes:
+ *   queue lock must be held.
+ **/
+void blk_queue_end_tag(request_queue_t *q, struct request *rq)
+{
+	struct blk_queue_tag *bqt = q->queue_tags;
+	int tag = rq->tag;
+
+	BUG_ON(tag == -1);
+
+	if (unlikely(tag >= bqt->max_depth))
+		return;
+
+	if (unlikely(!__test_and_clear_bit(tag, bqt->tag_map))) {
+		printk("attempt to clear non-busy tag (%d)\n", tag);
+		return;
+	}
+
+	list_del(&rq->queuelist);
+	rq->flags &= ~REQ_QUEUED;
+	rq->tag = -1;
+
+	if (unlikely(bqt->tag_index[tag] == NULL))
+		printk("tag %d is missing\n", tag);
+
+	bqt->tag_index[tag] = NULL;
+	bqt->busy--;
+}
+
+/**
+ * blk_queue_start_tag - find a free tag and assign it
+ * @q:  the request queue for the device
+ * @rq:  the block request that needs tagging
+ *
+ *  Description:
+ *    This can either be used as a stand-alone helper, or possibly be
+ *    assigned as the queue &prep_rq_fn (in which case &struct request
+ *    automagically gets a tag assigned). Note that this function assumes
+ *    that only REQ_CMD requests can be queued! The request will also be
+ *    removed from the request queue, so it's the drivers responsibility to
+ *    readd it if it should need to be restarted for some reason.
+ *
+ *  Notes:
+ *   queue lock must be held.
+ **/
+int blk_queue_start_tag(request_queue_t *q, struct request *rq)
+{
+	struct blk_queue_tag *bqt = q->queue_tags;
+	unsigned long *map = bqt->tag_map;
+	int tag = 0;
+
+	if (unlikely(!(rq->flags & REQ_CMD)))
+		return 1;
+
+	for (map = bqt->tag_map; *map == -1UL; map++) {
+		tag += BLK_TAGS_PER_LONG;
+
+		if (tag >= bqt->max_depth)
+			return 1;
+	}
+
+	tag += ffz(*map);
+	__set_bit(tag, bqt->tag_map);
+
+	rq->flags |= REQ_QUEUED;
+	rq->tag = tag;
+	bqt->tag_index[tag] = rq;
+	blkdev_dequeue_request(rq);
+	list_add(&rq->queuelist, &bqt->busy_list);
+	bqt->busy++;
+	return 0;
+}
+
+/**
+ * blk_queue_invalidate_tags - invalidate all pending tags
+ * @q:  the request queue for the device
+ *
+ *  Description:
+ *   Hardware conditions may dictate a need to stop all pending requests.
+ *   In this case, we will safely clear the block side of the tag queue and
+ *   readd all requests to the request queue in the right order.
+ *
+ *  Notes:
+ *   queue lock must be held.
+ **/
+void blk_queue_invalidate_tags(request_queue_t *q)
+{
+	struct blk_queue_tag *bqt = q->queue_tags;
+	struct list_head *tmp;
+	struct request *rq;
+
+	list_for_each(tmp, &bqt->busy_list) {
+		rq = list_entry_rq(tmp);
+
+		blk_queue_end_tag(q, rq);
+		rq->flags &= ~REQ_STARTED;
+		elv_add_request(q, rq, 0);
+	}
+}
+
 static char *rq_flags[] = { "REQ_RW", "REQ_RW_AHEAD", "REQ_BARRIER",
 			   "REQ_CMD", "REQ_NOMERGE", "REQ_STARTED",
-			   "REQ_DONTPREP", "REQ_DRIVE_CMD",
+			   "REQ_DONTPREP", "REQ_QUEUED", "REQ_DRIVE_CMD",
 			   "REQ_DRIVE_ACB", "REQ_PC", "REQ_BLOCK_PC",
 			   "REQ_SENSE", "REQ_SPECIAL" };
 
@@ -619,7 +804,7 @@
 	total_hw_segments = req->nr_hw_segments + next->nr_hw_segments;
 	if (blk_hw_contig_segment(q, req->biotail, next->bio))
 		total_hw_segments--;
-    
+
 	if (total_hw_segments > q->max_hw_segments)
 		return 0;
 
@@ -719,7 +904,7 @@
  *     when a block device is being de-registered.  Currently, its
  *     primary task it to free all the &struct request structures that
  *     were allocated to the queue.
- * Caveat: 
+ * Caveat:
  *     Hopefully the low level driver will have finished any
  *     outstanding requests first...
  **/
@@ -733,6 +918,9 @@
 	if (count)
 		printk("blk_cleanup_queue: leaked requests (%d)\n", count);
 
+	if (blk_queue_tagged(q))
+		blk_queue_free_tags(q);
+
 	elevator_exit(q, &q->elevator);
 
 	memset(q, 0, sizeof(*q));
@@ -1599,7 +1787,7 @@
  * Description:
  *     Ends I/O on the first buffer attached to @req, and sets it up
  *     for the next buffer_head (if any) in the cluster.
- *     
+ *
  * Return:
  *     0 - we are done with this request, call end_that_request_last()
  *     1 - still buffers pending for this request
@@ -1753,3 +1941,9 @@
 
 EXPORT_SYMBOL(ll_10byte_cmd_build);
 EXPORT_SYMBOL(blk_queue_prep_rq);
+
+EXPORT_SYMBOL(blk_queue_init_tags);
+EXPORT_SYMBOL(blk_queue_free_tags);
+EXPORT_SYMBOL(blk_queue_start_tag);
+EXPORT_SYMBOL(blk_queue_end_tag);
+EXPORT_SYMBOL(blk_queue_invalidate_tags);
diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c	Thu May  2 17:22:15 2002
+++ b/drivers/block/loop.c	Thu May  2 17:22:15 2002
@@ -81,7 +81,6 @@
 static int max_loop = 8;
 static struct loop_device *loop_dev;
 static int *loop_sizes;
-static int *loop_blksizes;
 static devfs_handle_t devfs_handle;      /*  For the directory */
 
 /*
@@ -284,7 +283,7 @@
 
 static inline int loop_get_bs(struct loop_device *lo)
 {
-	return block_size(to_kdev_t(lo->lo_device->bd_dev));
+	return block_size(lo->lo_device);
 }
 
 static inline unsigned long loop_get_iv(struct loop_device *lo,
@@ -649,7 +648,7 @@
 	lo->old_gfp_mask = inode->i_mapping->gfp_mask;
 	inode->i_mapping->gfp_mask = GFP_NOIO;
 
-	set_blocksize(dev, block_size(to_kdev_t(lo_device->bd_dev)));
+	set_blocksize(bdev, block_size(lo_device));
 
 	lo->lo_bio = lo->lo_biotail = NULL;
 	kernel_thread(loop_thread, lo, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
@@ -989,10 +988,6 @@
 	if (!loop_sizes)
 		goto out_mem;
 
-	loop_blksizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL);
-	if (!loop_blksizes)
-		goto out_mem;
-
 	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), loop_make_request);
 	blk_queue_bounce_limit(BLK_DEFAULT_QUEUE(MAJOR_NR), BLK_BOUNCE_HIGH);
 
@@ -1007,9 +1002,7 @@
 	}
 
 	memset(loop_sizes, 0, max_loop * sizeof(int));
-	memset(loop_blksizes, 0, max_loop * sizeof(int));
 	blk_size[MAJOR_NR] = loop_sizes;
-	blksize_size[MAJOR_NR] = loop_blksizes;
 	for (i = 0; i < max_loop; i++)
 		register_disk(NULL, mk_kdev(MAJOR_NR, i), 1, &lo_fops, 0);
 
@@ -1031,7 +1024,6 @@
 
 	kfree(loop_dev);
 	kfree(loop_sizes);
-	kfree(loop_blksizes);
 }
 
 module_init(loop_init);
diff -Nru a/drivers/block/nbd.c b/drivers/block/nbd.c
--- a/drivers/block/nbd.c	Thu May  2 17:22:16 2002
+++ b/drivers/block/nbd.c	Thu May  2 17:22:16 2002
@@ -518,7 +518,6 @@
 #ifdef MODULE
 	printk("nbd: registered device at major %d\n", MAJOR_NR);
 #endif
-	blksize_size[MAJOR_NR] = nbd_blksizes;
 	blk_size[MAJOR_NR] = nbd_sizes;
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_nbd_request, &nbd_lock);
 	for (i = 0; i < MAX_NBD; i++) {
diff -Nru a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
--- a/drivers/block/paride/pcd.c	Thu May  2 17:22:16 2002
+++ b/drivers/block/paride/pcd.c	Thu May  2 17:22:16 2002
@@ -223,8 +223,6 @@
 static void 	do_pcd_request(request_queue_t * q);
 static void 	do_pcd_read(void);
 
-static int pcd_blocksizes[PCD_UNITS];
-
 struct pcd_unit {
 	struct pi_adapter pia;		/* interface to paride layer */
 	struct pi_adapter *pi;
@@ -356,9 +354,6 @@
 	}
 
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_pcd_request, &pcd_lock);
-
-	for (i=0;i<PCD_UNITS;i++) pcd_blocksizes[i] = 1024;
-        blksize_size[MAJOR_NR] = pcd_blocksizes;
 
 	return 0;
 }
diff -Nru a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
--- a/drivers/block/paride/pd.c	Thu May  2 17:22:16 2002
+++ b/drivers/block/paride/pd.c	Thu May  2 17:22:16 2002
@@ -286,7 +286,6 @@
 
 static struct hd_struct pd_hd[PD_DEVS];
 static int pd_sizes[PD_DEVS];
-static int pd_blocksizes[PD_DEVS];
 
 #define PD_NAMELEN	8
 
@@ -399,9 +398,6 @@
 	pd_gendisk.major = major;
 	pd_gendisk.major_name = name;
 	add_gendisk(&pd_gendisk);
-
-	for(i=0;i<PD_DEVS;i++) pd_blocksizes[i] = 1024;
-	blksize_size[MAJOR_NR] = pd_blocksizes;
 
 	printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
 		name,name,PD_VERSION,major,cluster,nice);
diff -Nru a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
--- a/drivers/block/paride/pf.c	Thu May  2 17:22:16 2002
+++ b/drivers/block/paride/pf.c	Thu May  2 17:22:16 2002
@@ -265,8 +265,6 @@
 static void pf_eject(int unit);
 static int pf_check_media(kdev_t dev);
 
-static int pf_blocksizes[PF_UNITS];
-
 #define PF_NM           0
 #define PF_RO           1
 #define PF_RW           2
@@ -362,8 +360,6 @@
 	blk_queue_max_phys_segments(q, cluster);
 	blk_queue_max_hw_segments(q, cluster);
 
-	for (i=0;i<PF_UNITS;i++) pf_blocksizes[i] = 1024;
-	blksize_size[MAJOR_NR] = pf_blocksizes;
 	for (i=0;i<PF_UNITS;i++)
 		register_disk(NULL, mk_kdev(MAJOR_NR, i), 1, &pf_fops, 0);
 
diff -Nru a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
--- a/drivers/block/ps2esdi.c	Thu May  2 17:22:15 2002
+++ b/drivers/block/ps2esdi.c	Thu May  2 17:22:15 2002
@@ -115,7 +115,6 @@
 static int access_count[MAX_HD];
 static char ps2esdi_valid[MAX_HD];
 static int ps2esdi_sizes[MAX_HD << 6];
-static int ps2esdi_blocksizes[MAX_HD << 6];
 static int ps2esdi_drives;
 static struct hd_struct ps2esdi[MAX_HD << 6];
 static u_short io_base;
@@ -413,12 +412,8 @@
 
 	ps2esdi_gendisk.nr_real = ps2esdi_drives;
 
-	for (i = 0; i < (MAX_HD << 6); i++)
-		ps2esdi_blocksizes[i] = 1024;
-
 	request_dma(dma_arb_level, "ed");
 	request_region(io_base, 4, "ed");
-	blksize_size[MAJOR_NR] = ps2esdi_blocksizes;
 	blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 128);
 
 	for (i = 0; i < ps2esdi_drives; i++) {
diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c
--- a/drivers/block/rd.c	Thu May  2 17:22:17 2002
+++ b/drivers/block/rd.c	Thu May  2 17:22:17 2002
@@ -73,8 +73,6 @@
  */
 
 static unsigned long rd_length[NUM_RAMDISKS];	/* Size of RAM disks in bytes   */
-static int rd_hardsec[NUM_RAMDISKS];		/* Size of real blocks in bytes */
-static int rd_blocksizes[NUM_RAMDISKS];		/* Size of 1024 byte blocks :)  */
 static int rd_kbsize[NUM_RAMDISKS];	/* Size in blocks of 1024 bytes */
 static devfs_handle_t devfs_handle;
 static struct block_device *rd_bdev[NUM_RAMDISKS];/* Protected device data */
@@ -430,8 +428,6 @@
 	for (i = 0; i < NUM_RAMDISKS; i++) {
 		/* rd_size is given in kB */
 		rd_length[i] = rd_size << 10;
-		rd_hardsec[i] = rd_blocksize;
-		rd_blocksizes[i] = rd_blocksize;
 		rd_kbsize[i] = rd_size;
 	}
 	devfs_handle = devfs_mk_dir (NULL, "rd", NULL);
@@ -451,7 +447,6 @@
 			INITRD_MINOR, S_IFBLK | S_IRUSR, &rd_bd_op, NULL);
 #endif
 
-	blksize_size[MAJOR_NR] = rd_blocksizes;	/* Avoid set_blocksize() check */
 	blk_size[MAJOR_NR] = rd_kbsize;		/* Size of the RAM disk in kB  */
 
 	/* rd_size is given in kB */
diff -Nru a/drivers/block/swim3.c b/drivers/block/swim3.c
--- a/drivers/block/swim3.c	Thu May  2 17:22:16 2002
+++ b/drivers/block/swim3.c	Thu May  2 17:22:16 2002
@@ -35,7 +35,6 @@
 #include <linux/blk.h>
 #include <linux/devfs_fs_kernel.h>
 
-static int floppy_blocksizes[2] = {512,512};
 static int floppy_sizes[2] = {2880,2880};
 
 #define MAX_FLOPPIES	2
@@ -1034,7 +1033,6 @@
 		}
 		blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request,
 				&swim3_lock);
-		blksize_size[MAJOR_NR] = floppy_blocksizes;
 		blk_size[MAJOR_NR] = floppy_sizes;
 	}
 
diff -Nru a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
--- a/drivers/block/swim_iop.c	Thu May  2 17:22:15 2002
+++ b/drivers/block/swim_iop.c	Thu May  2 17:22:15 2002
@@ -81,7 +81,6 @@
 
 static struct floppy_state floppy_states[MAX_FLOPPIES];
 
-static int floppy_blocksizes[2] = {512,512};
 static int floppy_sizes[2] = {2880,2880};
 
 static spinlock_t swim_iop_lock = SPIN_LOCK_UNLOCKED;
@@ -151,7 +150,6 @@
 	}
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request,
 			&swim_iop_lock);
-	blksize_size[MAJOR_NR] = floppy_blocksizes;
 	blk_size[MAJOR_NR] = floppy_sizes;
 
 	printk("SWIM-IOP: %s by Joshua M. Thompson (funaho@jurai.org)\n",
diff -Nru a/drivers/block/xd.c b/drivers/block/xd.c
--- a/drivers/block/xd.c	Thu May  2 17:22:16 2002
+++ b/drivers/block/xd.c	Thu May  2 17:22:16 2002
@@ -120,7 +120,6 @@
 
 static struct hd_struct xd_struct[XD_MAXDRIVES << 6];
 static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES];
-static int xd_blocksizes[XD_MAXDRIVES << 6];
 
 static spinlock_t xd_lock = SPIN_LOCK_UNLOCKED;
 
@@ -206,9 +205,6 @@
 {
 	u_char i,controller;
 	unsigned int address;
-
-	for(i=0;i<(XD_MAXDRIVES << 6);i++) xd_blocksizes[i] = 1024;
-	blksize_size[MAJOR_NR] = xd_blocksizes;
 
 	if (xd_detect(&controller,&address)) {
 
diff -Nru a/drivers/block/z2ram.c b/drivers/block/z2ram.c
--- a/drivers/block/z2ram.c	Thu May  2 17:22:17 2002
+++ b/drivers/block/z2ram.c	Thu May  2 17:22:17 2002
@@ -61,7 +61,6 @@
 
 static u_long *z2ram_map    = NULL;
 static u_long z2ram_size    = 0;
-static int z2_blocksizes[Z2MINOR_COUNT];
 static int z2_sizes[Z2MINOR_COUNT];
 static int z2_count         = 0;
 static int chip_count       = 0;
@@ -361,13 +360,11 @@
 	    int i;
 
 	    for (i = 0; i < Z2MINOR_COUNT; i++) {
-		    z2_blocksizes[ i ] = 1024;
 		    z2_sizes[ i ] = 0;
 	    }
     }    
    
     blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUES, &z2ram_lock);
-    blksize_size[ MAJOR_NR ] = z2_blocksizes;
     blk_size[ MAJOR_NR ] = z2_sizes;
 
     return 0;
diff -Nru a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
--- a/drivers/cdrom/aztcd.c	Thu May  2 17:22:17 2002
+++ b/drivers/cdrom/aztcd.c	Thu May  2 17:22:17 2002
@@ -191,8 +191,6 @@
 #include <asm/io.h>
 
 #include <asm/uaccess.h>
-static int aztcd_blocksizes[1] = { 2048 };
-
 
 /*###########################################################################
   Defines
@@ -1926,7 +1924,7 @@
 		return -EIO;
 	}
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_aztcd_request, &aztSpin);
-	blksize_size[MAJOR_NR] = aztcd_blocksizes;
+	blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048);
 	register_disk(NULL, mk_kdev(MAJOR_NR, 0), 1, &azt_fops, 0);
 
 	if ((azt_port == 0x1f0) || (azt_port == 0x170))
diff -Nru a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
--- a/drivers/cdrom/cdu31a.c	Thu May  2 17:22:16 2002
+++ b/drivers/cdrom/cdu31a.c	Thu May  2 17:22:16 2002
@@ -3301,8 +3301,6 @@
 
 #endif
 
-static int cdu31a_block_size;
-
 /*
  * Initialize the driver.
  */
@@ -3442,9 +3440,6 @@
 		blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR),
 			       do_cdu31a_request,
 			       &cdu31a_lock);
-		cdu31a_block_size = 1024;	/* 1kB default block size */
-		/* use 'mount -o block=2048' */
-		blksize_size[MAJOR_NR] = &cdu31a_block_size;
 
 		init_timer(&cdu31a_abort_timer);
 		cdu31a_abort_timer.function = handle_abort_timeout;
diff -Nru a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
--- a/drivers/cdrom/cm206.c	Thu May  2 17:22:16 2002
+++ b/drivers/cdrom/cm206.c	Thu May  2 17:22:16 2002
@@ -261,8 +261,6 @@
 	uch track, fsm[3], q0;
 };
 
-static int cm206_blocksizes[1] = { 2048 };
-
 struct cm206_struct {
 	volatile ush intr_ds;	/* data status read on last interrupt */
 	volatile ush intr_ls;	/* uart line status read on last interrupt */
@@ -1502,7 +1500,7 @@
 	devfs_plain_cdrom(&cm206_info, &cm206_bdops);
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_cm206_request,
 		       &cm206_lock);
-	blksize_size[MAJOR_NR] = cm206_blocksizes;
+	blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048);
 	init_bh(CM206_BH, cm206_bh);
 
 	memset(cd, 0, sizeof(*cd));	/* give'm some reasonable value */
diff -Nru a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
--- a/drivers/cdrom/gscd.c	Thu May  2 17:22:15 2002
+++ b/drivers/cdrom/gscd.c	Thu May  2 17:22:15 2002
@@ -74,8 +74,6 @@
 #define gscd_port gscd		/* for compatible parameter passing with "insmod" */
 #include "gscd.h"
 
-static int gscd_blocksizes[1] = { 512 };
-
 static int gscdPresent = 0;
 
 static unsigned char gscd_buf[2048];	/* buffer for block size conversion */
@@ -1021,7 +1019,6 @@
 		       S_IFBLK | S_IRUGO | S_IWUGO, &gscd_fops, NULL);
 
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_gscd_request, &gscd_lock);
-	blksize_size[MAJOR_NR] = gscd_blocksizes;
 
 	disk_state = 0;
 	gscdPresent = 1;
diff -Nru a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
--- a/drivers/cdrom/mcd.c	Thu May  2 17:22:15 2002
+++ b/drivers/cdrom/mcd.c	Thu May  2 17:22:15 2002
@@ -107,9 +107,6 @@
 #define mcd_port mcd		/* for compatible parameter passing with "insmod" */
 #include "mcd.h"
 
-static int mcd_blocksizes[1];
-
-
 /* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
 static int mcdDouble;
 
@@ -1072,7 +1069,6 @@
 		return -EIO;
 	}
 
-	blksize_size[MAJOR_NR] = mcd_blocksizes;
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_mcd_request,
 		       &mcd_spinlock);
 
diff -Nru a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
--- a/drivers/cdrom/mcdx.c	Thu May  2 17:22:17 2002
+++ b/drivers/cdrom/mcdx.c	Thu May  2 17:22:17 2002
@@ -285,7 +285,6 @@
 
 /* static variables ************************************************/
 
-static int mcdx_blocksizes[MCDX_NDRIVES];
 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
 static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
 static struct s_drive_stuff *mcdx_irq_map[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
@@ -1086,8 +1085,6 @@
 	int size = sizeof(*stuffp);
 	char msg[80];
 
-	mcdx_blocksizes[drive] = 0;
-
 	xtrace(INIT, "init() try drive %d\n", drive);
 
 	xtrace(INIT, "kmalloc space for stuffpt's\n");
@@ -1184,7 +1181,6 @@
 
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_mcdx_request,
 		       &mcdx_lock);
-	blksize_size[MAJOR_NR] = mcdx_blocksizes;
 
 	xtrace(INIT, "init() subscribe irq and i/o\n");
 	mcdx_irq_map[stuffp->irq] = stuffp;
diff -Nru a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
--- a/drivers/cdrom/optcd.c	Thu May  2 17:22:16 2002
+++ b/drivers/cdrom/optcd.c	Thu May  2 17:22:16 2002
@@ -108,8 +108,6 @@
 #define DEBUG(x)
 #endif
 
-static int blksize = 2048;
-
 
 /* Drive hardware/firmware characteristics
    Identifiers in accordance with Optics Storage documentation */
@@ -2059,9 +2057,9 @@
 	}
 	devfs_register (NULL, "optcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
 			S_IFBLK | S_IRUGO | S_IWUGO, &opt_fops, NULL);
-	blksize_size[MAJOR_NR] = &blksize;
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_optcd_request,
 		       &optcd_lock);
+	blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048);
 	request_region(optcd_port, 4, "optcd");
 	register_disk(NULL, mk_kdev(MAJOR_NR,0), 1, &opt_fops, 0);
 
diff -Nru a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
--- a/drivers/cdrom/sbpcd.c	Thu May  2 17:22:16 2002
+++ b/drivers/cdrom/sbpcd.c	Thu May  2 17:22:16 2002
@@ -674,7 +674,6 @@
 
 static int ndrives;
 static u_char drv_pattern[NR_SBPCD]={speed_auto,speed_auto,speed_auto,speed_auto};
-static int sbpcd_blocksizes[NR_SBPCD];
 
 /*==========================================================================*/
 /*
@@ -5928,12 +5927,8 @@
 		{
                 	printk(" sbpcd: Unable to register with Uniform CD-ROm driver\n");
 		}
-		/*
-		 * set the block size
-		 */
-		sbpcd_blocksizes[j]=CD_FRAMESIZE;
 	}
-	blksize_size[MAJOR_NR]=sbpcd_blocksizes;
+	blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), CD_FRAMESIZE);
 
 #ifndef MODULE
  init_done:
diff -Nru a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
--- a/drivers/cdrom/sjcd.c	Thu May  2 17:22:17 2002
+++ b/drivers/cdrom/sjcd.c	Thu May  2 17:22:17 2002
@@ -1658,8 +1658,6 @@
 	check_media_change:sjcd_disk_change,
 };
 
-static int blksize = 2048;
-
 /*
  * Following stuff is intended for initialization of the cdrom. It
  * first looks for presence of device. If the device is present, it
@@ -1686,8 +1684,6 @@
 	printk("SJCD: sjcd=0x%x: ", sjcd_base);
 #endif
 
-	blksize_size[MAJOR_NR] = &blksize;
-
 	if (devfs_register_blkdev(MAJOR_NR, "sjcd", &sjcd_fops) != 0) {
 		printk("SJCD: Unable to get major %d for Sanyo CD-ROM\n",
 		       MAJOR_NR);
@@ -1695,6 +1691,7 @@
 	}
 
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_sjcd_request, &sjcd_lock);
+	blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048);
 	register_disk(NULL, mk_kdev(MAJOR_NR, 0), 1, &sjcd_fops, 0);
 
 	if (check_region(sjcd_base, 4)) {
diff -Nru a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
--- a/drivers/cdrom/sonycd535.c	Thu May  2 17:22:16 2002
+++ b/drivers/cdrom/sonycd535.c	Thu May  2 17:22:16 2002
@@ -1471,8 +1471,6 @@
 	check_media_change:	cdu535_check_media_change,
 };
 
-static int sonycd535_block_size = CDU535_BLOCK_SIZE;
-
 /*
  * Initialize the driver.
  */
@@ -1549,19 +1547,20 @@
 #endif
 			/* now ready to use interrupts, if available */
 			sony535_irq_used = tmp_irq;
-#ifndef MODULE
-/* This code is not in MODULEs by default, since the autoirq stuff might
- * not be in the module-accessible symbol table.
- */
+
 			/* A negative sony535_irq_used will attempt an autoirq. */
 			if (sony535_irq_used < 0) {
-				autoirq_setup(0);
+				unsigned long irq_mask, delay;
+
+				irq_mask = probe_irq_on();
 				enable_interrupts();
 				outb(0, read_status_reg);	/* does a reset? */
-				sony535_irq_used = autoirq_report(10);
+				delay = jiffies + HZ/10;
+				while (time_before(jiffies, delay)) ;
+
+				sony535_irq_used = probe_irq_off(irq_mask);
 				disable_interrupts();
 			}
-#endif
 			if (sony535_irq_used > 0) {
 			    if (request_irq(sony535_irq_used, cdu535_interrupt,
 								SA_INTERRUPT, CDU535_HANDLE, NULL)) {
@@ -1599,8 +1598,7 @@
 				blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR),
 						do_cdu535_request,
 						&sonycd535_lock);
-				blksize_size[MAJOR_NR] = &sonycd535_block_size;
-
+				blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), CDU535_BLOCK_SIZE);
 				sony_toc = (struct s535_sony_toc *)
 					kmalloc(sizeof *sony_toc, GFP_KERNEL);
 				if (sony_toc == NULL) {
diff -Nru a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
--- a/drivers/char/rocket_int.h	Thu May  2 17:22:16 2002
+++ b/drivers/char/rocket_int.h	Thu May  2 17:22:16 2002
@@ -185,7 +185,7 @@
 
 /* Old clock prescale definition and baud rates associated with it */
 
-#define CLOCK_PRESC 0x19  */        /* mod 9 (divide by 10) prescale */
+#define CLOCK_PRESC 0x19            /* mod 9 (divide by 10) prescale */
 #define BRD50             4607
 #define BRD75             3071
 #define BRD110            2094
diff -Nru a/drivers/char/serial_tx3912.h b/drivers/char/serial_tx3912.h
--- a/drivers/char/serial_tx3912.h	Thu May  2 17:22:16 2002
+++ b/drivers/char/serial_tx3912.h	Thu May  2 17:22:16 2002
@@ -24,7 +24,7 @@
 #define UART_TXOVERRUN_INT  3  /* transmit overrun error          (25, 15) */
 #define UART_EMPTY_INT      2  /* both trans/recv regs empty      (24, 14) */
 #define UART_DMAFULL_INT    1  /* DMA at end of buffer            (23, 13) */
-#define UART_DMAHALF_INT    0  /* DMA halfway through buffer */   (22, 12) */
+#define UART_DMAHALF_INT    0  /* DMA halfway through buffer      (22, 12) */
 
 #define UARTA_SHIFT        22
 #define UARTB_SHIFT        12
diff -Nru a/drivers/ide/ataraid.c b/drivers/ide/ataraid.c
--- a/drivers/ide/ataraid.c	Thu May  2 17:22:17 2002
+++ b/drivers/ide/ataraid.c	Thu May  2 17:22:17 2002
@@ -34,8 +34,6 @@
 
 #include "ataraid.h"
 
-static int ataraid_blksize_size[256];
-
 static struct raid_device_operations* ataraid_ops[16];
 
 static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
@@ -236,14 +234,8 @@
 {
 	int i;
         for(i=0;i<256;i++)
-	{
-		ataraid_blksize_size[i] = 1024;  
 		ataraid_readahead[i] = 1023;
-	}
 	
-	if (blksize_size[ATAMAJOR]==NULL)
-		blksize_size[ATAMAJOR] = ataraid_blksize_size;
-
 	/* setup the gendisk structure */	
 	ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL);
 	if (ataraid_gendisk.part==NULL) {
@@ -281,7 +273,6 @@
 {
 	unregister_blkdev(ATAMAJOR, "ataraid");
 	blk_size[ATAMAJOR] = NULL;
-	blksize_size[ATAMAJOR] = NULL;                       
 
 	del_gendisk(&ataraid_gendisk);
         
diff -Nru a/drivers/ide/hd.c b/drivers/ide/hd.c
--- a/drivers/ide/hd.c	Thu May  2 17:22:16 2002
+++ b/drivers/ide/hd.c	Thu May  2 17:22:16 2002
@@ -107,8 +107,6 @@
 
 static struct hd_struct hd[MAX_HD<<6];
 static int hd_sizes[MAX_HD<<6];
-static int hd_blocksizes[MAX_HD<<6];
-
 
 static struct timer_list device_timer;
 
@@ -727,10 +725,6 @@
 {
 	int drive;
 
-	for(drive=0; drive < (MAX_HD << 6); drive++)
-		hd_blocksizes[drive] = 1024;
-
-	blksize_size[MAJOR_NR] = hd_blocksizes;
 	blk_queue_hardsect_size(QUEUE, 512);
 
 #ifdef __i386__
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Thu May  2 17:22:16 2002
+++ b/drivers/ide/ide-cd.c	Thu May  2 17:22:16 2002
@@ -2677,7 +2677,6 @@
 	 * default to read-only always and fix latter at the bottom
 	 */
 	set_device_ro(mk_kdev(drive->channel->major, minor), 1);
-	set_blocksize(mk_kdev(drive->channel->major, minor), CD_FRAMESIZE);
 	blk_queue_hardsect_size(&drive->queue, CD_FRAMESIZE);
 
 	blk_queue_prep_rq(&drive->queue, ll_10byte_cmd_build);
@@ -2861,13 +2860,7 @@
 	/* for general /dev/cdrom like mounting, one big disc */
 	drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
 	drive->channel->gd->sizes[minor] = toc->capacity * BLOCKS_PER_FRAME;
-
-	/*
-	 * reset block size, ide_revalidate_disk incorrectly sets it to
-	 * 1024 even for CDROM's
-	 */
 	blk_size[drive->channel->major] = drive->channel->gd->sizes;
-	set_blocksize(mk_kdev(drive->channel->major, minor), CD_FRAMESIZE);
 }
 
 static sector_t ide_cdrom_capacity(struct ata_device *drive)
diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
--- a/drivers/ide/ide-dma.c	Thu May  2 17:22:16 2002
+++ b/drivers/ide/ide-dma.c	Thu May  2 17:22:16 2002
@@ -270,16 +270,15 @@
 }
 
 /*
- * ide_build_dmatable() prepares a dma request.
- * Returns 0 if all went okay, returns 1 otherwise.
- * May also be invoked from trm290.c
+ * This prepares a dma request.  Returns 0 if all went okay, returns 1
+ * otherwise.  May also be invoked from trm290.c
  */
-int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
+int ide_build_dmatable(struct ata_device *drive, ide_dma_action_t func)
 {
-	struct ata_channel *hwif = drive->channel;
-	unsigned int *table = hwif->dmatable_cpu;
+	struct ata_channel *ch = drive->channel;
+	unsigned int *table = ch->dmatable_cpu;
 #ifdef CONFIG_BLK_DEV_TRM290
-	unsigned int is_trm290_chipset = (hwif->chipset == ide_trm290);
+	unsigned int is_trm290_chipset = (ch->chipset == ide_trm290);
 #else
 	const int is_trm290_chipset = 0;
 #endif
@@ -287,11 +286,11 @@
 	int i;
 	struct scatterlist *sg;
 
-	hwif->sg_nents = i = build_sglist(hwif, HWGROUP(drive)->rq);
+	ch->sg_nents = i = build_sglist(ch, HWGROUP(drive)->rq);
 	if (!i)
 		return 0;
 
-	sg = hwif->sg_table;
+	sg = ch->sg_table;
 	while (i) {
 		u32 cur_addr;
 		u32 cur_len;
@@ -309,8 +308,8 @@
 			u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
 
 			if (count++ >= PRD_ENTRIES) {
-				printk("ide-dma: req %p\n", HWGROUP(drive)->rq);
-				printk("count %d, sg_nents %d, cur_len %d, cur_addr %u\n", count, hwif->sg_nents, cur_len, cur_addr);
+				printk("ide-dma: count %d, sg_nents %d, cur_len %d, cur_addr %u\n",
+						count, ch->sg_nents, cur_len, cur_addr);
 				BUG();
 			}
 
@@ -328,9 +327,9 @@
 			 * the 64KB entry into two 32KB entries instead.
 			 */
 				if (count++ >= PRD_ENTRIES) {
-					pci_unmap_sg(hwif->pci_dev, sg,
-						     hwif->sg_nents,
-						     hwif->sg_dma_direction);
+					pci_unmap_sg(ch->pci_dev, sg,
+						     ch->sg_nents,
+						     ch->sg_dma_direction);
 					return 0;
 				}
 
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Thu May  2 17:22:15 2002
+++ b/drivers/ide/ide-probe.c	Thu May  2 17:22:15 2002
@@ -745,7 +745,7 @@
 #else
 	printk("%s at %p on irq 0x%08x", ch->name,
 		ch->io_ports[IDE_DATA_OFFSET], ch->irq);
-#endif /* __mc68000__ && CONFIG_APUS */
+#endif
 	if (match)
 		printk(" (%sed with %s)",
 			ch->sharing_irq ? "shar" : "serializ", match->name);
@@ -780,12 +780,6 @@
 	if (!gd->part)
 		goto err_kmalloc_gd_part;
 	memset(gd->part, 0, minors * sizeof(struct hd_struct));
-
-	blksize_size[hwif->major] = kmalloc (minors*sizeof(int), GFP_KERNEL);
-	if (!blksize_size[hwif->major])
-		goto err_kmalloc_bs;
-	for (i = 0; i < minors; ++i)
-	    blksize_size[hwif->major][i] = BLOCK_SIZE;
 
 	for (unit = 0; unit < MAX_DRIVES; ++unit)
 		hwif->drives[unit].part = &gd->part[unit << PARTN_BITS];
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Thu May  2 17:22:16 2002
+++ b/drivers/ide/ide.c	Thu May  2 17:22:16 2002
@@ -1187,12 +1187,12 @@
 {
 	if (timeout > WAIT_WORSTCASE)
 		timeout = WAIT_WORSTCASE;
-	drive->PADAM_sleep = timeout + jiffies;
+	drive->sleep = timeout + jiffies;
 }
 
 
 /*
- * Determine the longes sleep time for the devices in our hwgroup.
+ * Determine the longest sleep time for the devices at this channel.
  */
 static unsigned long longest_sleep(struct ata_channel *channel)
 {
@@ -1218,8 +1218,8 @@
 			/* This device is sleeping and waiting to be serviced
 			 * later than any other device we checked thus far.
 			 */
-			if (drive->PADAM_sleep && (!sleep || time_after(sleep, drive->PADAM_sleep)))
-				sleep = drive->PADAM_sleep;
+			if (drive->sleep && (!sleep || time_after(sleep, drive->sleep)))
+				sleep = drive->sleep;
 		}
 	}
 
@@ -1256,16 +1256,15 @@
 			if (list_empty(&drive->queue.queue_head))
 				continue;
 
-			/* This device still want's to remain idle.
+			/* This device still wants to remain idle.
 			 */
-			if (drive->PADAM_sleep && time_after(jiffies, drive->PADAM_sleep))
+			if (drive->sleep && time_after(jiffies, drive->sleep))
 				continue;
 
 			/* Take this device, if there is no device choosen thus far or
 			 * it's more urgent.
 			 */
-			if (!choice || (drive->PADAM_sleep && (!choice->PADAM_sleep || time_after(choice->PADAM_sleep, drive->PADAM_sleep))))
-			{
+			if (!choice || (drive->sleep && (!choice->sleep || time_after(choice->sleep, drive->sleep)))) {
 				if (!blk_queue_plugged(&drive->queue))
 					choice = drive;
 			}
@@ -1315,7 +1314,6 @@
  * Feed commands to a drive until it barfs.  Called with ide_lock/DRIVE_LOCK
  * held and busy channel.
  */
-
 static void queue_commands(struct ata_device *drive, int masked_irq)
 {
 	ide_hwgroup_t *hwgroup = drive->channel->hwgroup;
@@ -1325,7 +1323,7 @@
 		struct request *rq = NULL;
 
 		if (!test_bit(IDE_BUSY, &hwgroup->flags))
-			printk(KERN_ERR"%s: hwgroup not busy while queueing\n", drive->name);
+			printk(KERN_ERR"%s: error: not busy while queueing!\n", drive->name);
 
 		/* Abort early if we can't queue another command. for non
 		 * tcq, ata_can_queue is always 1 since we never get here
@@ -1337,7 +1335,7 @@
 			break;
 		}
 
-		drive->PADAM_sleep = 0;
+		drive->sleep = 0;
 
 		if (test_bit(IDE_DMA, &hwgroup->flags)) {
 			printk("ide_do_request: DMA in progress...\n");
@@ -1825,10 +1823,9 @@
  * completed. This is again intended for careful use by the ATAPI tape/cdrom
  * driver code.
  */
-int ide_do_drive_cmd(ide_drive_t *drive, struct request *rq, ide_action_t action)
+int ide_do_drive_cmd(struct ata_device *drive, struct request *rq, ide_action_t action)
 {
 	unsigned long flags;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	unsigned int major = drive->channel->major;
 	request_queue_t *q = &drive->queue;
 	struct list_head *queue_head = &q->queue_head;
@@ -1846,7 +1843,7 @@
 	spin_lock_irqsave(&ide_lock, flags);
 	if (blk_queue_empty(&drive->queue) || action == ide_preempt) {
 		if (action == ide_preempt)
-			hwgroup->rq = NULL;
+			HWGROUP(drive)->rq = NULL;
 	} else {
 		if (action == ide_wait || action == ide_end)
 			queue_head = queue_head->prev;
@@ -1873,21 +1870,22 @@
  * usage == 1 (we need an open channel to use an ioctl :-), so this
  * is our limit.
  */
-int ide_revalidate_disk (kdev_t i_rdev)
+int ide_revalidate_disk(kdev_t i_rdev)
 {
-	ide_drive_t *drive;
-	ide_hwgroup_t *hwgroup;
+	struct ata_device *drive;
 	unsigned long flags;
 	int res;
 
 	if ((drive = get_info_ptr(i_rdev)) == NULL)
 		return -ENODEV;
-	hwgroup = HWGROUP(drive);
+
 	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);
@@ -2032,71 +2030,18 @@
 };
 #endif
 
-/*
- * Note that we only release the standard ports, and do not even try to handle
- * any extra ports allocated for weird IDE interface chipsets.
- */
-static void hwif_unregister(struct ata_channel *ch)
-{
-	int i;
-	ide_hwgroup_t *hwgroup = ch->hwgroup;
-
-	/*
-	 * Free the irq if we were the only channel using it.
-	 */
-	int n = 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;
-	}
-	if (n == 1)
-		free_irq(ch->irq, hwgroup);
-
-
-	if (ch->straight8) {
-		release_region(ch->io_ports[IDE_DATA_OFFSET], 8);
-	} else {
-		if (ch->io_ports[IDE_DATA_OFFSET])
-			release_region(ch->io_ports[IDE_DATA_OFFSET], 1);
-		if (ch->io_ports[IDE_ERROR_OFFSET])
-			release_region(ch->io_ports[IDE_ERROR_OFFSET], 1);
-		if (ch->io_ports[IDE_NSECTOR_OFFSET])
-			release_region(ch->io_ports[IDE_NSECTOR_OFFSET], 1);
-		if (ch->io_ports[IDE_SECTOR_OFFSET])
-			release_region(ch->io_ports[IDE_SECTOR_OFFSET], 1);
-		if (ch->io_ports[IDE_LCYL_OFFSET])
-			release_region(ch->io_ports[IDE_LCYL_OFFSET], 1);
-		if (ch->io_ports[IDE_HCYL_OFFSET])
-			release_region(ch->io_ports[IDE_HCYL_OFFSET], 1);
-		if (ch->io_ports[IDE_SELECT_OFFSET])
-			release_region(ch->io_ports[IDE_SELECT_OFFSET], 1);
-		if (ch->io_ports[IDE_STATUS_OFFSET])
-			release_region(ch->io_ports[IDE_STATUS_OFFSET], 1);
-	}
-	if (ch->io_ports[IDE_CONTROL_OFFSET])
-		release_region(ch->io_ports[IDE_CONTROL_OFFSET], 1);
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-	if (ch->io_ports[IDE_IRQ_OFFSET])
-		release_region(ch->io_ports[IDE_IRQ_OFFSET], 1);
-#endif
-}
-
 void ide_unregister(struct ata_channel *ch)
 {
 	struct gendisk *gd;
 	struct ata_device *d;
 	ide_hwgroup_t *hwgroup;
-	int unit, i;
+	int unit;
+	int i;
 	unsigned long flags;
 	unsigned int p, minor;
 	struct ata_channel old;
-	int n = 0;
+	int n_irq;
+	int n_ch;
 
 	spin_lock_irqsave(&ide_lock, flags);
 
@@ -2146,10 +2091,40 @@
 #endif
 	spin_lock_irqsave(&ide_lock, flags);
 
-	hwif_unregister(ch);
+	/*
+	 * 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 {
+		if (ch->io_ports[IDE_DATA_OFFSET])
+			release_region(ch->io_ports[IDE_DATA_OFFSET], 1);
+		if (ch->io_ports[IDE_ERROR_OFFSET])
+			release_region(ch->io_ports[IDE_ERROR_OFFSET], 1);
+		if (ch->io_ports[IDE_NSECTOR_OFFSET])
+			release_region(ch->io_ports[IDE_NSECTOR_OFFSET], 1);
+		if (ch->io_ports[IDE_SECTOR_OFFSET])
+			release_region(ch->io_ports[IDE_SECTOR_OFFSET], 1);
+		if (ch->io_ports[IDE_LCYL_OFFSET])
+			release_region(ch->io_ports[IDE_LCYL_OFFSET], 1);
+		if (ch->io_ports[IDE_HCYL_OFFSET])
+			release_region(ch->io_ports[IDE_HCYL_OFFSET], 1);
+		if (ch->io_ports[IDE_SELECT_OFFSET])
+			release_region(ch->io_ports[IDE_SELECT_OFFSET], 1);
+		if (ch->io_ports[IDE_STATUS_OFFSET])
+			release_region(ch->io_ports[IDE_STATUS_OFFSET], 1);
+	}
+	if (ch->io_ports[IDE_CONTROL_OFFSET])
+		release_region(ch->io_ports[IDE_CONTROL_OFFSET], 1);
+#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 hwgroup
+	 * Remove us from the hwgroup.
 	 */
 
 	hwgroup = ch->hwgroup;
@@ -2177,20 +2152,30 @@
 	if (d->present)
 		hwgroup->XXX_drive = d;
 
-	/* Free the hwgroup if we were the only member.
+
+	/*
+	 * Free the irq if we were the only channel using it.
+	 *
+	 * Free the hwgroup if we were the only member.
 	 */
-	n = 0;
+	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->hwgroup == ch->hwgroup)
-			++n;
+			++n_ch;
 	}
-	if (n == 1)
+	if (n_irq == 1)
+		free_irq(ch->irq, ch->hwgroup);
+	if (n_ch == 1) {
 		kfree(ch->hwgroup);
+		ch->hwgroup = NULL;
+	}
 
 #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
 	ide_release_dma(ch);
@@ -2200,7 +2185,6 @@
 	 * Remove us from the kernel's knowledge.
 	 */
 	unregister_blkdev(ch->major, ch->name);
-	kfree(blksize_size[ch->major]);
 	blk_dev[ch->major].data = NULL;
 	blk_dev[ch->major].queue = NULL;
 	blk_clear(ch->major);
diff -Nru a/drivers/ide/pdcadma.c b/drivers/ide/pdcadma.c
--- a/drivers/ide/pdcadma.c	Thu May  2 17:22:16 2002
+++ b/drivers/ide/pdcadma.c	Thu May  2 17:22:16 2002
@@ -47,18 +47,18 @@
 
 	return p-buffer;	/* => must be less than 4k! */
 }
-#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+#endif
 
 byte pdcadma_proc = 0;
 
 extern char *ide_xfer_verbose (byte xfer_rate);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
+
 /*
- * pdcadma_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ * This initiates/aborts (U)DMA read/write operations on a drive.
  */
-
-int pdcadma_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+int pdcadma_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	switch (func) {
 		case ide_dma_check:
@@ -66,9 +66,9 @@
 		default:
 			break;
 	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+	return ide_dmaproc(func, drive, rq);	/* use standard DMA stuff */
 }
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif
 
 unsigned int __init pci_init_pdcadma(struct pci_dev *dev)
 {
@@ -76,9 +76,9 @@
 	if (!pdcadma_proc) {
 		pdcadma_proc = 1;
 		bmide_dev = dev;
-		pdcadma_display_info = &pdcadma_get_info;
+		pdcadma_display_info = pdcadma_get_info;
 	}
-#endif /* DISPLAY_PDCADMA_TIMINGS && CONFIG_PROC_FS */
+#endif
 	return 0;
 }
 
diff -Nru a/drivers/ide/piix.c b/drivers/ide/piix.c
--- a/drivers/ide/piix.c	Thu May  2 17:22:16 2002
+++ b/drivers/ide/piix.c	Thu May  2 17:22:16 2002
@@ -471,7 +471,9 @@
 				break;
 			}
 
+#ifndef CONFIG_BLK_DEV_PIIX_TRY133
 		case PIIX_UDMA_100:
+#endif
 		case PIIX_UDMA_133:
 			pci_read_config_dword(dev, PIIX_IDECFG, &u);
 			piix_80w = ((u & 0x30) ? 1 : 0) | ((u & 0xc0) ? 2 : 0);
@@ -484,7 +486,7 @@
 
 	if (piix_config->flags & PIIX_PINGPONG) {
 		pci_read_config_dword(dev, PIIX_IDECFG, &u);
-		u |= 0x400; 
+		u |= 0x400;
 		pci_write_config_dword(dev, PIIX_IDECFG, u);
 	}
 
diff -Nru a/drivers/ide/trm290.c b/drivers/ide/trm290.c
--- a/drivers/ide/trm290.c	Thu May  2 17:22:16 2002
+++ b/drivers/ide/trm290.c	Thu May  2 17:22:16 2002
@@ -173,7 +173,7 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+static int trm290_dmaproc (ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	struct ata_channel *hwif = drive->channel;
 	unsigned int count, reading = 2, writing = 0;
@@ -206,12 +206,12 @@
 		case ide_dma_test_irq:
 			return (inw(hwif->dma_base+2) == 0x00ff);
 		default:
-			return ide_dmaproc(func, drive);
+			return ide_dmaproc(func, drive, rq);
 	}
 	trm290_prepare_drive(drive, 0);	/* select PIO xfer */
 	return 1;
 }
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif
 
 /*
  * Invoked from ide-dma.c at boot time.
@@ -263,8 +263,8 @@
 	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->unit ? 0x0080 : 0x0000), 3);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &trm290_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+	hwif->udma = trm290_dmaproc;
+#endif
 
 	hwif->selectproc = &trm290_selectproc;
 	hwif->autodma = 0;				/* play it safe for now */
diff -Nru a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h
--- a/drivers/isdn/hardware/avm/avmcard.h	Thu May  2 17:22:16 2002
+++ b/drivers/isdn/hardware/avm/avmcard.h	Thu May  2 17:22:16 2002
@@ -10,6 +10,8 @@
 #ifndef _AVMCARD_H_
 #define _AVMCARD_H_
 
+#include <linux/spinlock.h>
+
 #define	AVMB1_PORTLEN		0x1f
 #define AVM_MAXVERSION		8
 #define AVM_NCCI_PER_CHANNEL	4
@@ -55,8 +57,24 @@
 	struct pci_dev      *pcidev;
 } avmcard_dmainfo;
 
+typedef	struct avmctrl_info {
+	char cardname[32];
+	
+	int versionlen;
+	char versionbuf[1024];
+	char *version[AVM_MAXVERSION];
+	
+	char infobuf[128];	/* for function procinfo */
+	
+	struct avmcard  *card;
+	struct capi_ctr *capi_ctrl;
+	
+} avmctrl_info;
+
 typedef struct avmcard {
 	char name[32];
+  
+	spinlock_t lock;
 	unsigned int port;
 	unsigned irq;
 	unsigned long membase;
@@ -68,31 +86,15 @@
 	char msgbuf[128];	/* capimsg msg part */
 	char databuf[2048];	/* capimsg data part */
 
-	int interrupt;
-
 	void *mbase;
 	volatile u32 csr;
 	avmcard_dmainfo *dma;
 
-	struct avmctrl_info {
-		char cardname[32];
-
-		int versionlen;
-		char versionbuf[1024];
-		char *version[AVM_MAXVERSION];
-
-		char infobuf[128];	/* for function procinfo */
-
-		struct avmcard  *card;
-		struct capi_ctr *capi_ctrl;
-
-	} *ctrlinfo;
+	struct avmctrl_info *ctrlinfo;
 
 	int nlogcontr;
 } avmcard;
 
-typedef struct avmctrl_info avmctrl_info;
-
 extern int b1_irq_table[16];
 
 /*
@@ -534,6 +536,8 @@
 }
 
 /* b1.c */
+avmcard *b1_alloc_card(int nr_controllers);
+void b1_free_card(avmcard *card);
 int b1_detect(unsigned int base, enum avmcardtype cardtype);
 void b1_getrevision(avmcard *card);
 int b1_load_t4file(avmcard *card, capiloaddatapart * t4file);
@@ -547,7 +551,7 @@
 void b1_release_appl(struct capi_ctr *ctrl, u16 appl);
 void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
 void b1_parse_version(avmctrl_info *card);
-void b1_handle_interrupt(avmcard * card);
+void b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs);
 
 int b1ctl_read_proc(char *page, char **start, off_t off,
         		int count, int *eof, struct capi_ctr *ctrl);
diff -Nru a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
--- a/drivers/isdn/hardware/avm/b1.c	Thu May  2 17:22:16 2002
+++ b/drivers/isdn/hardware/avm/b1.c	Thu May  2 17:22:16 2002
@@ -57,6 +57,44 @@
  112,				/* irq 15 */
 };
 
+/* ------------------------------------------------------------- */	
+
+avmcard *b1_alloc_card(int nr_controllers)
+{
+	avmcard *card;
+	avmctrl_info *cinfo;
+	int i;
+
+	card = kmalloc(sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return 0;
+
+	memset(card, 0, sizeof(*card));
+
+        cinfo = kmalloc(sizeof(*cinfo) * nr_controllers, GFP_KERNEL);
+	if (!cinfo) {
+		kfree(card);
+		return 0;
+	}
+	memset(cinfo, 0, sizeof(*cinfo));
+
+	card->ctrlinfo = cinfo;
+	for (i = 0; i < nr_controllers; i++) {
+		cinfo[i].card = card;
+	}
+	spin_lock_init(&card->lock);
+
+	return card;
+}
+
+/* ------------------------------------------------------------- */
+
+void b1_free_card(avmcard *card)
+{
+	kfree(card->ctrlinfo);
+	kfree(card);
+}
+
 /* ------------------------------------------------------------- */
 
 int b1_detect(unsigned int base, enum avmcardtype cardtype)
@@ -438,8 +476,9 @@
 
 /* ------------------------------------------------------------- */
 
-void b1_handle_interrupt(avmcard * card)
+void b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
 {
+	avmcard *card = devptr;
 	avmctrl_info *cinfo = &card->ctrlinfo[0];
 	struct capi_ctr *ctrl = cinfo->capi_ctrl;
 	unsigned char b1cmd;
@@ -701,6 +740,8 @@
 
 EXPORT_SYMBOL(b1_irq_table);
 
+EXPORT_SYMBOL(b1_alloc_card);
+EXPORT_SYMBOL(b1_free_card);
 EXPORT_SYMBOL(b1_detect);
 EXPORT_SYMBOL(b1_getrevision);
 EXPORT_SYMBOL(b1_load_t4file);
@@ -713,7 +754,7 @@
 EXPORT_SYMBOL(b1_send_message);
 
 EXPORT_SYMBOL(b1_parse_version);
-EXPORT_SYMBOL(b1_handle_interrupt);
+EXPORT_SYMBOL(b1_interrupt);
 
 EXPORT_SYMBOL(b1ctl_read_proc);
 
diff -Nru a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
--- a/drivers/isdn/hardware/avm/b1dma.c	Thu May  2 17:22:17 2002
+++ b/drivers/isdn/hardware/avm/b1dma.c	Thu May  2 17:22:17 2002
@@ -64,7 +64,7 @@
 #	define AVM_FLAG			0x30000000L
 
 #	define ANY_S5933_INT		0x00800000L
-#	define	READ_TC_INT		0x00080000L
+#	define READ_TC_INT		0x00080000L
 #	define WRITE_TC_INT		0x00040000L
 #	define	TX_TC_INT		READ_TC_INT
 #	define	RX_TC_INT		WRITE_TC_INT
@@ -83,12 +83,15 @@
 
 /* ------------------------------------------------------------- */
 
-#define b1dmaoutmeml(addr, value)	writel(value, addr)
-#define b1dmainmeml(addr)	readl(addr)
-#define b1dmaoutmemw(addr, value)	writew(value, addr)
-#define b1dmainmemw(addr)	readw(addr)
-#define b1dmaoutmemb(addr, value)	writeb(value, addr)
-#define b1dmainmemb(addr)	readb(addr)
+static inline void b1dma_writel(avmcard *card, u32 value, int off)
+{
+	writel(value, card->mbase + off);
+}
+
+static inline u32 b1dma_readl(avmcard *card, int off)
+{
+	return readl(card->mbase + off);
+}
 
 /* ------------------------------------------------------------- */
 
@@ -214,26 +217,20 @@
 
 void b1dma_reset(avmcard *card)
 {
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 	card->csr = 0x0;
-	b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
-	b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
-	b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0);
-	b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0);
+	b1dma_writel(card, card->csr, AMCC_INTCSR);
+	b1dma_writel(card, 0, AMCC_MCSR);
+	b1dma_writel(card, 0, AMCC_RXLEN);
+	b1dma_writel(card, 0, AMCC_TXLEN);
 
 	t1outp(card->port, 0x10, 0x00);
 	t1outp(card->port, 0x07, 0x00);
 
-	restore_flags(flags);
-
-	b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+	b1dma_writel(card, 0, AMCC_MCSR);
 	mdelay(10);
-	b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
+	b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */
 	mdelay(10);
-	b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+	b1dma_writel(card, 0, AMCC_MCSR);
 	if (card->cardtype == avm_t1pci)
 		mdelay(42);
 	else
@@ -244,31 +241,31 @@
 
 int b1dma_detect(avmcard *card)
 {
-	b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+	b1dma_writel(card, 0, AMCC_MCSR);
 	mdelay(10);
-	b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
+	b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */
 	mdelay(10);
-	b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+	b1dma_writel(card, 0, AMCC_MCSR);
 	mdelay(42);
 
-	b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0);
-	b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0);
+	b1dma_writel(card, 0, AMCC_RXLEN);
+	b1dma_writel(card, 0, AMCC_TXLEN);
 	card->csr = 0x0;
-	b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+	b1dma_writel(card, card->csr, AMCC_INTCSR);
 
-	if (b1dmainmeml(card->mbase+AMCC_MCSR) != 0x000000E6)
+	if (b1dma_readl(card, AMCC_MCSR) != 0x000000E6)
 		return 1;
 
-	b1dmaoutmeml(card->mbase+AMCC_RXPTR, 0xffffffff);
-	b1dmaoutmeml(card->mbase+AMCC_TXPTR, 0xffffffff);
-	if (   b1dmainmeml(card->mbase+AMCC_RXPTR) != 0xfffffffc
-	    || b1dmainmeml(card->mbase+AMCC_TXPTR) != 0xfffffffc)
+	b1dma_writel(card, 0xffffffff, AMCC_RXPTR);
+	b1dma_writel(card, 0xffffffff, AMCC_TXPTR);
+	if (   b1dma_readl(card, AMCC_RXPTR) != 0xfffffffc
+	    || b1dma_readl(card, AMCC_TXPTR) != 0xfffffffc)
 		return 2;
 
-	b1dmaoutmeml(card->mbase+AMCC_RXPTR, 0x0);
-	b1dmaoutmeml(card->mbase+AMCC_TXPTR, 0x0);
-	if (   b1dmainmeml(card->mbase+AMCC_RXPTR) != 0x0
-	    || b1dmainmeml(card->mbase+AMCC_TXPTR) != 0x0)
+	b1dma_writel(card, 0x0, AMCC_RXPTR);
+	b1dma_writel(card, 0x0, AMCC_TXPTR);
+	if (   b1dma_readl(card, AMCC_RXPTR) != 0x0
+	    || b1dma_readl(card, AMCC_TXPTR) != 0x0)
 		return 3;
 
 	t1outp(card->port, 0x10, 0x00);
@@ -350,37 +347,34 @@
 	return 0;
 }
 
+static void b1dma_queue_tx(avmcard *card, struct sk_buff *skb)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+
+	if (!(card->csr & EN_TX_TC_INT)) {
+		b1dma_dispatch_tx(card);
+		b1dma_writel(card, card->csr, AMCC_INTCSR);
+	}
+
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
 /* ------------------------------------------------------------- */
 
 static void b1dma_dispatch_tx(avmcard *card)
 {
 	avmcard_dmainfo *dma = card->dma;
-	unsigned long flags;
 	struct sk_buff *skb;
 	u8 cmd, subcmd;
 	u16 len;
 	u32 txlen;
-	int inint;
 	void *p;
 	
-	save_flags(flags);
-	cli();
-
-	inint = card->interrupt;
-
-	if (card->csr & EN_TX_TC_INT) { /* tx busy */
-	        restore_flags(flags);
-		return;
-	}
-
 	skb = skb_dequeue(&dma->send_queue);
-	if (!skb) {
-#ifdef CONFIG_B1DMA_DEBUG
-		printk(KERN_DEBUG "tx(%d): underrun\n", inint);
-#endif
-	        restore_flags(flags);
-		return;
-	}
 
 	len = CAPIMSG_LEN(skb->data);
 
@@ -401,8 +395,7 @@
 		}
 		txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf;
 #ifdef CONFIG_B1DMA_DEBUG
-		printk(KERN_DEBUG "tx(%d): put msg len=%d\n",
-				inint, txlen);
+		printk(KERN_DEBUG "tx: put msg len=%d\n", txlen);
 #endif
 	} else {
 		txlen = skb->len-2;
@@ -411,22 +404,18 @@
 			printk(KERN_INFO "%s: send ack\n", card->name);
 #endif
 #ifdef CONFIG_B1DMA_DEBUG
-		printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n",
-				inint, skb->data[2], txlen);
+		printk(KERN_DEBUG "tx: put 0x%x len=%d\n", 
+		       skb->data[2], txlen);
 #endif
 		memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2);
 	}
 	txlen = (txlen + 3) & ~3;
 
-	b1dmaoutmeml(card->mbase+AMCC_TXPTR, dma->sendbuf.dmaaddr);
-	b1dmaoutmeml(card->mbase+AMCC_TXLEN, txlen);
+	b1dma_writel(card, dma->sendbuf.dmaaddr, AMCC_TXPTR);
+	b1dma_writel(card, txlen, AMCC_TXLEN);
 
 	card->csr |= EN_TX_TC_INT;
 
-	if (!inint)
-		b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
-
-	restore_flags(flags);
 	dev_kfree_skb_any(skb);
 }
 
@@ -449,8 +438,7 @@
 	_put_byte(&p, SEND_POLLACK);
 	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
-	skb_queue_tail(&card->dma->send_queue, skb);
-	b1dma_dispatch_tx(card);
+	b1dma_queue_tx(card, skb);
 }
 
 /* ------------------------------------------------------------- */
@@ -585,7 +573,7 @@
 
 static void b1dma_handle_interrupt(avmcard *card)
 {
-	u32 status = b1dmainmeml(card->mbase+AMCC_INTCSR);
+	u32 status = b1dma_readl(card, AMCC_INTCSR);
 	u32 newcsr;
 
 	if ((status & ANY_S5933_INT) == 0) 
@@ -594,7 +582,7 @@
         newcsr = card->csr | (status & ALL_INT);
 	if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
 	if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
-	b1dmaoutmeml(card->mbase+AMCC_INTCSR, newcsr);
+	b1dma_writel(card, newcsr, AMCC_INTCSR);
 
 	if ((status & RX_TC_INT) != 0) {
 		struct avmcard_dmainfo *dma = card->dma;
@@ -602,45 +590,34 @@
 	   	if (card->dma->recvlen == 0) {
 			dma->recvlen = *((u32 *)dma->recvbuf.dmabuf);
 			rxlen = (dma->recvlen + 3) & ~3;
-			b1dmaoutmeml(card->mbase+AMCC_RXPTR,
-					dma->recvbuf.dmaaddr+4);
-			b1dmaoutmeml(card->mbase+AMCC_RXLEN, rxlen);
+			b1dma_writel(card, dma->recvbuf.dmaaddr+4, AMCC_RXPTR);
+			b1dma_writel(card, rxlen, AMCC_RXLEN);
 		} else {
 			b1dma_handle_rx(card);
 	   		dma->recvlen = 0;
-			b1dmaoutmeml(card->mbase+AMCC_RXPTR,
-					dma->recvbuf.dmaaddr);
-			b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4);
+			b1dma_writel(card, dma->recvbuf.dmaaddr, AMCC_RXPTR);
+			b1dma_writel(card, 4, AMCC_RXLEN);
 		}
 	}
 
+	spin_lock(&card->lock);
+
 	if ((status & TX_TC_INT) != 0) {
-		card->csr &= ~EN_TX_TC_INT;
-	        b1dma_dispatch_tx(card);
+		if (skb_queue_empty(&card->dma->send_queue))
+			card->csr &= ~EN_TX_TC_INT;
+		else
+			b1dma_dispatch_tx(card);
 	}
-	b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+	b1dma_writel(card, card->csr, AMCC_INTCSR);
+
+	spin_unlock(&card->lock);
 }
 
 void b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
 {
-	avmcard *card;
-
-	card = (avmcard *) devptr;
-
-	if (!card) {
-		printk(KERN_WARNING "b1dma: interrupt: wrong device\n");
-		return;
-	}
-	if (card->interrupt) {
-		printk(KERN_ERR "%s: reentering interrupt hander\n", card->name);
-		return;
-	}
-
-	card->interrupt = 1;
+	avmcard *card = devptr;
 
 	b1dma_handle_interrupt(card);
-
-	card->interrupt = 0;
 }
 
 /* ------------------------------------------------------------- */
@@ -697,15 +674,13 @@
 	_put_word(&p, card->cardnr - 1);
 	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
-	skb_queue_tail(&card->dma->send_queue, skb);
-	b1dma_dispatch_tx(card);
+	b1dma_queue_tx(card, skb);
 }
 
 int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
-	unsigned long flags;
 	int retval;
 
 	b1dma_reset(card);
@@ -732,24 +707,19 @@
 		return -EIO;
 	}
 
-	save_flags(flags);
-	cli();
-
 	card->csr = AVM_FLAG;
-	b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
-	b1dmaoutmeml(card->mbase+AMCC_MCSR,
-		EN_A2P_TRANSFERS|EN_P2A_TRANSFERS
-		|A2P_HI_PRIORITY|P2A_HI_PRIORITY
-		|RESET_A2P_FLAGS|RESET_P2A_FLAGS);
+	b1dma_writel(card, card->csr, AMCC_INTCSR);
+	b1dma_writel(card, EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|A2P_HI_PRIORITY|
+		     P2A_HI_PRIORITY|RESET_A2P_FLAGS|RESET_P2A_FLAGS, 
+		     AMCC_MCSR);
 	t1outp(card->port, 0x07, 0x30);
 	t1outp(card->port, 0x10, 0xF0);
 
 	card->dma->recvlen = 0;
-	b1dmaoutmeml(card->mbase+AMCC_RXPTR, card->dma->recvbuf.dmaaddr);
-	b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4);
+	b1dma_writel(card, card->dma->recvbuf.dmaaddr, AMCC_RXPTR);
+	b1dma_writel(card, 4, AMCC_RXLEN);
 	card->csr |= EN_RX_TC_INT;
-	b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
-	restore_flags(flags);
+	b1dma_writel(card, card->csr, AMCC_INTCSR);
 
         b1dma_send_init(card);
 
@@ -803,8 +773,7 @@
 	_put_word(&p, rp->datablklen);
 	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
-	skb_queue_tail(&card->dma->send_queue, skb);
-	b1dma_dispatch_tx(card);
+	b1dma_queue_tx(card, skb);
 
 	ctrl->appl_registered(ctrl, appl);
 }
@@ -831,8 +800,8 @@
 	_put_word(&p, appl);
 
 	skb_put(skb, (u8 *)p - (u8 *)skb->data);
-	skb_queue_tail(&card->dma->send_queue, skb);
-	b1dma_dispatch_tx(card);
+
+	b1dma_queue_tx(card, skb);
 }
 
 /* ------------------------------------------------------------- */
@@ -841,8 +810,8 @@
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
-	skb_queue_tail(&card->dma->send_queue, skb);
-	b1dma_dispatch_tx(card);
+
+	b1dma_queue_tx(card, skb);
 }
 
 /* ------------------------------------------------------------- */
@@ -852,7 +821,6 @@
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
-	unsigned long flags;
 	u8 flag;
 	int len = 0;
 	char *s;
@@ -909,18 +877,13 @@
 	}
 	len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
 
-	save_flags(flags);
-	cli();
-
-	txoff = (dma_addr_t)b1dmainmeml(card->mbase+0x2c)-card->dma->sendbuf.dmaaddr;
-	txlen = b1dmainmeml(card->mbase+0x30);
-
-	rxoff = (dma_addr_t)b1dmainmeml(card->mbase+0x24)-card->dma->recvbuf.dmaaddr;
-	rxlen = b1dmainmeml(card->mbase+0x28);
+	txoff = (dma_addr_t)b1dma_readl(card, AMCC_TXPTR)-card->dma->sendbuf.dmaaddr;
+	txlen = b1dma_readl(card, AMCC_TXLEN);
 
-	csr  = b1dmainmeml(card->mbase+AMCC_INTCSR);
+	rxoff = (dma_addr_t)b1dma_readl(card, AMCC_RXPTR)-card->dma->recvbuf.dmaaddr;
+	rxlen = b1dma_readl(card, AMCC_RXLEN);
 
-	restore_flags(flags);
+	csr  = b1dma_readl(card, AMCC_INTCSR);
 
         len += sprintf(page+len, "%-16s 0x%lx\n",
 				"csr (cached)", (unsigned long)card->csr);
diff -Nru a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c
--- a/drivers/isdn/hardware/avm/b1isa.c	Thu May  2 17:22:16 2002
+++ b/drivers/isdn/hardware/avm/b1isa.c	Thu May  2 17:22:16 2002
@@ -34,29 +34,6 @@
 
 /* ------------------------------------------------------------- */
 
-static void b1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
-{
-	avmcard *card;
-
-	card = (avmcard *) devptr;
-
-	if (!card) {
-		printk(KERN_WARNING "b1_interrupt: wrong device\n");
-		return;
-	}
-	if (card->interrupt) {
-		printk(KERN_ERR "b1_interrupt: reentering interrupt hander (%s)\n", card->name);
-		return;
-	}
-
-	card->interrupt = 1;
-
-	b1_handle_interrupt(card);
-
-	card->interrupt = 0;
-}
-/* ------------------------------------------------------------- */
-
 static struct capi_driver_interface *di;
 
 /* ------------------------------------------------------------- */
@@ -73,8 +50,7 @@
 	di->detach_ctr(ctrl);
 	free_irq(card->irq, card);
 	release_region(card->port, AVMB1_PORTLEN);
-	kfree(card->ctrlinfo);
-	kfree(card);
+	b1_free_card(card);
 
 	MOD_DEC_USE_COUNT;
 }
@@ -89,86 +65,57 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	card = b1_alloc_card(1);
 	if (!card) {
 		printk(KERN_WARNING "b1isa: no memory.\n");
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		retval = -ENOMEM;
+		goto err;
 	}
-	memset(card, 0, sizeof(avmcard));
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
-	if (!cinfo) {
-		printk(KERN_WARNING "b1isa: no memory.\n");
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
-	}
-	memset(cinfo, 0, sizeof(avmctrl_info));
-	card->ctrlinfo = cinfo;
-	cinfo->card = card;
+
+	cinfo = card->ctrlinfo;
+
 	sprintf(card->name, "b1isa-%x", p->port);
 	card->port = p->port;
 	card->irq = p->irq;
 	card->cardtype = avm_b1isa;
 
-	if (check_region(card->port, AVMB1_PORTLEN)) {
-		printk(KERN_WARNING
-		       "b1isa: ports 0x%03x-0x%03x in use.\n",
-		       card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+	if (   card->port != 0x150 && card->port != 0x250
+	    && card->port != 0x300 && card->port != 0x340) {
+		printk(KERN_WARNING "b1isa: illegal port 0x%x.\n", card->port);
+		retval = -EINVAL;
+		goto err_free;
 	}
 	if (b1_irq_table[card->irq & 0xf] == 0) {
 		printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EINVAL;
+		retval = -EINVAL;
+		goto err_free;
 	}
-	if (   card->port != 0x150 && card->port != 0x250
-	    && card->port != 0x300 && card->port != 0x340) {
-		printk(KERN_WARNING "b1isa: illegal port 0x%x.\n", card->port);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EINVAL;
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
+		printk(KERN_WARNING "b1isa: ports 0x%03x-0x%03x in use.\n",
+		       card->port, card->port + AVMB1_PORTLEN);
+		retval = -EBUSY;
+		goto err_free;
+	}
+	retval = request_irq(card->irq, b1_interrupt, 0, card->name, card);
+	if (retval) {
+		printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq);
+		goto err_release_region;
 	}
 	b1_reset(card->port);
 	if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
 		printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n",
-					card->port, retval);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		       card->port, retval);
+		retval = -ENODEV;
+		goto err_free_irq;
 	}
 	b1_reset(card->port);
 	b1_getrevision(card);
 
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
-	retval = request_irq(card->irq, b1isa_interrupt, 0, card->name, card);
-	if (retval) {
-		printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
-	}
-
 	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "b1isa: attach controller failed.\n");
-		free_irq(card->irq, card);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_free_irq;
 	}
 
 	printk(KERN_INFO
@@ -176,6 +123,16 @@
 		driver->name, card->port, card->irq, card->revision);
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_free:
+	b1_free_card(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
 }
 
 static char *b1isa_procinfo(struct capi_ctr *ctrl)
diff -Nru a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c
--- a/drivers/isdn/hardware/avm/b1pci.c	Thu May  2 17:22:15 2002
+++ b/drivers/isdn/hardware/avm/b1pci.c	Thu May  2 17:22:15 2002
@@ -46,30 +46,6 @@
 
 /* ------------------------------------------------------------- */
 
-static void b1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
-{
-	avmcard *card;
-
-	card = (avmcard *) devptr;
-
-	if (!card) {
-		printk(KERN_WARNING "b1pci: interrupt: wrong device\n");
-		return;
-	}
-	if (card->interrupt) {
-		printk(KERN_ERR "%s: reentering interrupt hander.\n", card->name);
-		return;
-	}
-
-	card->interrupt = 1;
-
-	b1_handle_interrupt(card);
-
-	card->interrupt = 0;
-}
-
-/* ------------------------------------------------------------- */
-
 static char *b1pci_procinfo(struct capi_ctr *ctrl)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -98,22 +74,14 @@
 
 	MOD_INC_USE_COUNT;
 
-	retval = -ENOMEM;
-	card = kmalloc(sizeof(avmcard), GFP_KERNEL);
+	card = b1_alloc_card(1);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		retval = -ENOMEM;
 		goto err;
 	}
-	memset(card, 0, sizeof(avmcard));
 
-        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
-	if (!cinfo) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		goto err_kfree;
-	}
-	memset(cinfo, 0, sizeof(avmctrl_info));
-	card->ctrlinfo = cinfo;
-	cinfo->card = card;
+	cinfo = card->ctrlinfo;
 	sprintf(card->name, "b1pci-%x", p->port);
 	card->port = p->port;
 	card->irq = p->irq;
@@ -123,20 +91,21 @@
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-		goto err_kfree_ctrlinfo;
+		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);
-		retval = -EIO;
+		retval = -ENODEV;
 		goto err_release_region;
 	}
 	b1_reset(card->port);
 	b1_getrevision(card);
 	
-	retval = request_irq(card->irq, b1pci_interrupt, SA_SHIRQ, card->name, card);
+	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);
@@ -168,10 +137,8 @@
 	free_irq(card->irq, card);
  err_release_region:
 	release_region(card->port, AVMB1_PORTLEN);
- err_kfree_ctrlinfo:
-	kfree(card->ctrlinfo);
- err_kfree:
-	kfree(card);
+ err_free:
+	b1_free_card(card);
  err:
 	MOD_DEC_USE_COUNT;
 	return retval;
@@ -190,8 +157,7 @@
 	free_irq(card->irq, card);
 	release_region(card->port, AVMB1_PORTLEN);
 	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
-	kfree(card);
+	b1_free_card(card);
 
 	MOD_DEC_USE_COUNT;
 }
@@ -251,27 +217,21 @@
 
 	MOD_INC_USE_COUNT;
 
-	retval = -ENOMEM;
-	card = kmalloc(sizeof(avmcard), GFP_KERNEL);
+	card = b1_alloc_card(1);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		retval = -ENOMEM;
 		goto err;
 	}
-	memset(card, 0, sizeof(avmcard));
 
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: dma alloc.\n", driver->name);
-		goto err_kfree;
+		retval = -ENOMEM;
+		goto err_free;
 	}
-        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
-	if (!cinfo) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		goto err_dma_free;
-	}
-	memset(cinfo, 0, sizeof(avmctrl_info));
-	card->ctrlinfo = cinfo;
-	cinfo->card = card;
+
+	cinfo = card->ctrlinfo;
 	sprintf(card->name, "b1pciv4-%x", p->port);
 	card->port = p->port;
 	card->irq = p->irq;
@@ -283,14 +243,14 @@
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
 		retval = -EBUSY;
-		goto err_kfree_ctrlinfo;
+		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);
-		retval = -EIO;
+		retval = -ENOMEM;
 		goto err_release_region;
 	}
 
@@ -300,7 +260,7 @@
 	if (retval) {
 		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
 					driver->name, card->port, retval);
-		retval = -EIO;
+		retval = -ENODEV;
 		goto err_unmap;
 	}
 	b1dma_reset(card);
@@ -335,12 +295,10 @@
 	iounmap(card->mbase);
  err_release_region:
 	release_region(card->port, AVMB1_PORTLEN);
- err_kfree_ctrlinfo:
-	kfree(card->ctrlinfo);
- err_dma_free:
+ err_free_dma:
 	avmcard_dma_free(card->dma);
- err_kfree:
-	kfree(card);
+ err_free:
+	b1_free_card(card);
  err:
 	MOD_DEC_USE_COUNT;
 	return retval;
@@ -359,9 +317,8 @@
 	iounmap(card->mbase);
 	release_region(card->port, AVMB1_PORTLEN);
 	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
         avmcard_dma_free(card->dma);
-	kfree(card);
+	b1_free_card(card);
 
 	MOD_DEC_USE_COUNT;
 }
diff -Nru a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c
--- a/drivers/isdn/hardware/avm/b1pcmcia.c	Thu May  2 17:22:15 2002
+++ b/drivers/isdn/hardware/avm/b1pcmcia.c	Thu May  2 17:22:15 2002
@@ -39,30 +39,6 @@
 
 /* ------------------------------------------------------------- */
 
-static void b1pcmcia_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
-{
-	avmcard *card;
-
-	card = (avmcard *) devptr;
-
-	if (!card) {
-		printk(KERN_WARNING "b1pcmcia: interrupt: wrong device\n");
-		return;
-	}
-	if (card->interrupt) {
-		printk(KERN_ERR "%s: reentering interrupt hander.\n",
-			card->name);
-		return;
-	}
-
-	card->interrupt = 1;
-
-	b1_handle_interrupt(card);
-
-	card->interrupt = 0;
-}
-/* ------------------------------------------------------------- */
-
 static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -74,10 +50,7 @@
 
 	di->detach_ctr(ctrl);
 	free_irq(card->irq, card);
-	/* io addrsses managent by CardServices 
-	 * release_region(card->port, AVMB1_PORTLEN);
-	 */
-	kfree(card);
+	b1_free_card(card);
 
 	MOD_DEC_USE_COUNT;
 }
@@ -96,24 +69,14 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	card = b1_alloc_card(1);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		retval = -ENOMEM;
+		goto err;
 	}
-	memset(card, 0, sizeof(avmcard));
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
-	if (!cinfo) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
-	}
-	memset(cinfo, 0, sizeof(avmctrl_info));
-	card->ctrlinfo = cinfo;
-	cinfo->card = card;
+	cinfo = card->ctrlinfo;
+
 	switch (cardtype) {
 		case avm_m1: sprintf(card->name, "m1-%x", port); break;
 		case avm_m2: sprintf(card->name, "m2-%x", port); break;
@@ -123,37 +86,29 @@
 	card->irq = irq;
 	card->cardtype = cardtype;
 
+	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);
+		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);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -ENODEV;
+		goto err_free_irq;
 	}
 	b1_reset(card->port);
 	b1_getrevision(card);
 
-	retval = request_irq(card->irq, b1pcmcia_interrupt, 0, card->name, card);
-	if (retval) {
-		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
-				driver->name, card->irq);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
-	}
-
 	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n",
 				driver->name);
-		free_irq(card->irq, card);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_free_irq;
 	}
 	switch (cardtype) {
 		case avm_m1: cardname = "M1"; break;
@@ -166,6 +121,14 @@
 		driver->name, cardname, card->port, card->irq, card->revision);
 
 	return cinfo->capi_ctrl->cnr;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_free:
+	b1_free_card(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
 }
 
 /* ------------------------------------------------------------- */
diff -Nru a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
--- a/drivers/isdn/hardware/avm/c4.c	Thu May  2 17:22:15 2002
+++ b/drivers/isdn/hardware/avm/c4.c	Thu May  2 17:22:15 2002
@@ -719,25 +719,9 @@
 
 static void c4_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
 {
-	avmcard *card;
-
-	card = (avmcard *) devptr;
-
-	if (!card) {
-		printk(KERN_WARNING "%s: interrupt: wrong device\n", card->name);
-		return;
-	}
-	if (card->interrupt) {
-		printk(KERN_ERR "%s: reentering interrupt hander\n",
-				card->name);
-		return;
-	}
-
-	card->interrupt = 1;
+	avmcard *card = devptr;
 
 	c4_handle_interrupt(card);
-
-	card->interrupt = 0;
 }
 
 /* ------------------------------------------------------------- */
@@ -943,9 +927,8 @@
 	iounmap(card->mbase);
 	release_region(card->port, AVMB1_PORTLEN);
 	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
         avmcard_dma_free(card->dma);
-	kfree(card);
+	b1_free_card(card);
 
 	MOD_DEC_USE_COUNT;
 }
@@ -1124,51 +1107,40 @@
 static int c4_add_card(struct capi_driver *driver,
 		       struct capicardparams *p,
                        struct pci_dev *dev,
-		       int nr)
+		       int nr_controllers)
 {
-	avmctrl_info *cinfo;
 	avmcard *card;
+	avmctrl_info *cinfo;
 	int retval;
 	int i;
 
 	MOD_INC_USE_COUNT;
 
-	retval = -ENOMEM;
-	card = kmalloc(sizeof(avmcard), GFP_ATOMIC);
+	card = b1_alloc_card(nr_controllers);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		retval = -ENOMEM;
 		goto err;
 	}
-	memset(card, 0, sizeof(avmcard));
-
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		goto err_kfree;
-	}
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
-	if (!cinfo) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		goto err_dma_free;
-	}
-	memset(cinfo, 0, sizeof(avmctrl_info)*4);
-	card->ctrlinfo = cinfo;
-	for (i=0; i < 4; i++) {
-		cinfo = &card->ctrlinfo[i];
-		cinfo->card = card;
+		retval = -ENOMEM;
+		goto err_free;
 	}
+
 	sprintf(card->name, "%s-%x", driver->name, p->port);
 	card->port = p->port;
 	card->irq = p->irq;
 	card->membase = p->membase;
-	card->cardtype = nr == 4 ? avm_c4 : avm_c2;
+	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);
 		retval = -EBUSY;
-		goto err_kfree_ctrlinfo;
+		goto err_free_dma;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 128);
@@ -1196,9 +1168,8 @@
 		goto err_unmap;
 	}
 
-	for (i=0; i < nr ; i++) {
+	for (i=0; i < nr_controllers ; i++) {
 		cinfo = &card->ctrlinfo[i];
-		cinfo->card = card;
 		cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
 		if (!cinfo->capi_ctrl) {
 			printk(KERN_ERR "%s: attach controller failed (%d).\n",
@@ -1213,9 +1184,9 @@
 			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, card->port, card->irq, card->membase);
+	printk(KERN_INFO "%s: AVM C%d at i/o %#x, irq %d, mem %#lx\n",
+		driver->name, nr_controllers, card->port, card->irq,
+	       card->membase);
 
 	return 0;
 
@@ -1225,12 +1196,10 @@
 	iounmap(card->mbase);
  err_release_region:
 	release_region(card->port, AVMB1_PORTLEN);
- err_kfree_ctrlinfo:
-	kfree(card->ctrlinfo);
- err_dma_free:
+ err_free_dma:
 	avmcard_dma_free(card->dma);
- err_kfree:
-	kfree(card);
+ err_free:
+	b1_free_card(card);
  err:
 	MOD_DEC_USE_COUNT;
 	return retval;
diff -Nru a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
--- a/drivers/isdn/hardware/avm/t1isa.c	Thu May  2 17:22:17 2002
+++ b/drivers/isdn/hardware/avm/t1isa.c	Thu May  2 17:22:17 2002
@@ -128,8 +128,9 @@
         return 0;
 }
 
-static void t1_handle_interrupt(avmcard * card)
+static void t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
 {
+	avmcard *card = devptr;
 	avmctrl_info *cinfo = &card->ctrlinfo[0];
 	struct capi_ctr *ctrl = cinfo->capi_ctrl;
 	unsigned char b1cmd;
@@ -261,30 +262,6 @@
 
 /* ------------------------------------------------------------- */
 
-static void t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
-{
-	avmcard *card;
-
-	card = (avmcard *) devptr;
-
-	if (!card) {
-		printk(KERN_WARNING "t1isa: interrupt: wrong device\n");
-		return;
-	}
-	if (card->interrupt) {
-		printk(KERN_ERR "%s: reentering interrupt hander.\n",
-				 card->name);
-		return;
-	}
-
-	card->interrupt = 1;
-
-	t1_handle_interrupt(card);
-
-	card->interrupt = 0;
-}
-/* ------------------------------------------------------------- */
-
 static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -357,8 +334,7 @@
 	di->detach_ctr(ctrl);
 	free_irq(card->irq, card);
 	release_region(card->port, AVMB1_PORTLEN);
-	kfree(card->ctrlinfo);
-	kfree(card);
+	b1_free_card(card);
 
 	MOD_DEC_USE_COUNT;
 }
@@ -374,24 +350,14 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	card = b1_alloc_card(1);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		retval = -ENOMEM;
+		goto err;
 	}
-	memset(card, 0, sizeof(avmcard));
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
-	if (!cinfo) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
-	}
-	memset(cinfo, 0, sizeof(avmctrl_info));
-	card->ctrlinfo = cinfo;
-	cinfo->card = card;
+
+	cinfo = card->ctrlinfo;
 	sprintf(card->name, "t1isa-%x", p->port);
 	card->port = p->port;
 	card->irq = p->irq;
@@ -401,74 +367,53 @@
 	if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) {
 		printk(KERN_WARNING "%s: illegal port 0x%x.\n",
 				driver->name, card->port);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EINVAL;
+		retval = -EINVAL;
+		goto err_free;
         }
-
-	if (check_region(card->port, AVMB1_PORTLEN)) {
-		printk(KERN_WARNING
-		       "%s: ports 0x%03x-0x%03x in use.\n",
-		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
-	}
 	if (hema_irq_table[card->irq & 0xf] == 0) {
 		printk(KERN_WARNING "%s: irq %d not valid.\n",
-				driver->name, card->irq);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EINVAL;
+		       driver->name, card->irq);
+		retval = -EINVAL;
+		goto err_free;
 	}
 	for (ctrl = driver->controller; ctrl; ctrl = ctrl->next) {
 	        avmcard *cardp = ((avmctrl_info *)(ctrl->driverdata))->card;
 		if (cardp->cardnr == card->cardnr) {
 			printk(KERN_WARNING "%s: card with number %d already installed at 0x%x.\n",
 					driver->name, card->cardnr, cardp->port);
-	                kfree(card->ctrlinfo);
-			kfree(card);
-	        	MOD_DEC_USE_COUNT;
-			return -EBUSY;
+			retval = -EINVAL;
+			goto err_free;
 		}
 	}
-        if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) {
-		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
-					driver->name, card->port, retval);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-		MOD_DEC_USE_COUNT;
-		return -EIO;
+	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);
+		retval = -EBUSY;
+		goto err_free;
 	}
-	t1_disable_irq(card->port);
-	b1_reset(card->port);
-
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
 	retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
-				driver->name, card->irq);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-		MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		       driver->name, card->irq);
+		retval = -EBUSY;
+		goto err_release_region;
 	}
 
+        if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) {
+		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+		       driver->name, card->port, retval);
+		retval = -ENODEV;
+		goto err_free_irq;
+	}
+	t1_disable_irq(card->port);
+	b1_reset(card->port);
+
 	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n",
 				driver->name);
-		free_irq(card->irq, card);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-		MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_free_irq;
 	}
 
 	printk(KERN_INFO
@@ -476,6 +421,16 @@
 		driver->name, card->port, card->irq, card->cardnr);
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_free:
+	b1_free_card(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
 }
 
 static void t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
diff -Nru a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c
--- a/drivers/isdn/hardware/avm/t1pci.c	Thu May  2 17:22:16 2002
+++ b/drivers/isdn/hardware/avm/t1pci.c	Thu May  2 17:22:16 2002
@@ -59,26 +59,21 @@
 
 	MOD_INC_USE_COUNT;
 
-	retval = -ENOMEM;
-	card = kmalloc(sizeof(avmcard), GFP_KERNEL);
+	card = b1_alloc_card(1);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		retval = -ENOMEM;
 		goto err;
 	}
-	memset(card, 0, sizeof(avmcard));
+
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		goto err_kfree;
-	}
-        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
-	if (!cinfo) {
-		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		goto err_dma_free;
+		retval = -ENOMEM;
+		goto err_free;
 	}
-	memset(cinfo, 0, sizeof(avmctrl_info));
-	card->ctrlinfo = cinfo;
-	cinfo->card = card;
+
+	cinfo = card->ctrlinfo;
 	sprintf(card->name, "t1pci-%x", p->port);
 	card->port = p->port;
 	card->irq = p->irq;
@@ -90,7 +85,7 @@
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
 		retval = -EBUSY;
-		goto err_kfree_ctrlinfo;
+		goto err_free_dma;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 64);
@@ -144,12 +139,10 @@
 	iounmap(card->mbase);
  err_release_region:
 	release_region(card->port, AVMB1_PORTLEN);
- err_kfree_ctrlinfo:
-	kfree(card->ctrlinfo);
- err_dma_free:
+ err_free_dma:
 	avmcard_dma_free(card->dma);
- err_kfree:
-	kfree(card);
+ err_free:
+	b1_free_card(card);
  err:
 	MOD_DEC_USE_COUNT;
 	return retval;
@@ -169,9 +162,8 @@
 	iounmap(card->mbase);
 	release_region(card->port, AVMB1_PORTLEN);
 	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
 	avmcard_dma_free(card->dma);
-	kfree(card);
+	b1_free_card(card);
 
 	MOD_DEC_USE_COUNT;
 }
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Thu May  2 17:22:16 2002
+++ b/drivers/md/md.c	Thu May  2 17:22:16 2002
@@ -105,7 +105,6 @@
  * subsystems want to have a pre-defined structure
  */
 struct hd_struct md_hd_struct[MAX_MD_DEVS];
-static int md_blocksizes[MAX_MD_DEVS];
 static int md_maxreadahead[MAX_MD_DEVS];
 static mdk_thread_t *md_recovery_thread;
 
@@ -1521,7 +1520,6 @@
 	mdp_super_t *sb = mddev->sb;
 	struct list_head *tmp;
 	mdk_rdev_t *rdev;
-	unsigned long *ra_pages;
 
 	/*
 	 * Do device size calculation. Bail out if too small.
@@ -1579,9 +1577,6 @@
 		md_size[mdidx(mddev)] = sb->size * data_disks;
 
 	readahead = (VM_MAX_READAHEAD * 1024) / PAGE_SIZE;
-	ra_pages = blk_get_ra_pages(rdev->dev);
-	if (ra_pages)
-		readahead = (*ra_pages * PAGE_CACHE_SIZE) / PAGE_SIZE;
 	if (!sb->level || (sb->level == 4) || (sb->level == 5)) {
 		readahead = (mddev->sb->chunk_size>>PAGE_SHIFT) * 4 * data_disks;
 		if (readahead < data_disks * (MAX_SECTORS>>(PAGE_SHIFT-9))*2)
@@ -1714,9 +1709,18 @@
 		if (rdev->faulty)
 			continue;
 		invalidate_device(rdev->dev, 1);
+#if 0
+	/*
+	 * Aside of obvious breakage (code below results in block size set
+	 * according to the sector size of last component instead of the
+	 * maximal sector size), we have more interesting problem here.
+	 * Namely, we actually ought to set _sector_ size for the array
+	 * and that requires per-array request queues.  Disabled for now.
+	 */
 		md_blocksizes[mdidx(mddev)] = 1024;
 		if (bdev_hardsect_size(rdev->bdev) > md_blocksizes[mdidx(mddev)])
 			md_blocksizes[mdidx(mddev)] = bdev_hardsect_size(rdev->bdev);
+#endif
 	}
 	mddev->pers = pers[pnum];
 
@@ -3613,11 +3617,9 @@
 	int i;
 
 	for(i = 0; i < MAX_MD_DEVS; i++) {
-		md_blocksizes[i] = 1024;
 		md_size[i] = 0;
 		md_maxreadahead[i] = 32;
 	}
-	blksize_size[MAJOR_NR] = md_blocksizes;
 	blk_size[MAJOR_NR] = md_size;
 
 	dprintk("md: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t));
diff -Nru a/drivers/md/multipath.c b/drivers/md/multipath.c
--- a/drivers/md/multipath.c	Thu May  2 17:22:17 2002
+++ b/drivers/md/multipath.c	Thu May  2 17:22:17 2002
@@ -738,43 +738,56 @@
 {
 	multipath_conf_t *conf = mddev_to_conf(mddev);
 	int disks = MD_SB_DISKS;
-	kdev_t dev;
 	struct block_device *bdev;
-	struct buffer_head *bh = NULL;
 	int i, rc = 0;
-	char *buffer = NULL;
+	char *buffer;
+	struct page *page = NULL;
+	int first = 1;
+	int order = PAGE_CACHE_SHIFT-PAGE_SHIFT;
+
+	buffer = (char *) __get_free_pages(GFP_KERNEL, order);
+	if (!buffer)
+		return rc;
 
 	for (i = 0; i < disks; i++) {
+		struct address_space *mapping;
+		char *p;
 		if (!conf->multipaths[i].operational)
 			continue;
 		printk("(checking disk %d)\n",i);
-		dev = conf->multipaths[i].dev;
 		bdev = conf->multipaths[i].bdev;
-		set_blocksize(dev, 4096);
-		if ((bh = __bread(bdev, row / 4, 4096)) == NULL)
+		mapping = bdev->bd_inode->i_mapping;
+		page = read_cache_page(mapping, row/(PAGE_CACHE_SIZE/1024),
+				(filler_t *)mapping->a_ops->readpage, NULL);
+		if (IS_ERR(page)) {
+			page = NULL;
+			break;
+		}
+		wait_on_page_locked(page);
+		if (!PageUptodate(page))
+			break;
+		if (PageError(page))
 			break;
-		if (!buffer) {
-			buffer = (char *) __get_free_page(GFP_KERNEL);
-			if (!buffer)
-				break;
-			memcpy(buffer, bh->b_data, 4096);
-		} else if (memcmp(buffer, bh->b_data, 4096)) {
+		p = page_address(page);
+		if (first) {
+			memcpy(buffer, p, PAGE_CACHE_SIZE);
+			first = 0;
+		} else if (memcmp(buffer, p, PAGE_CACHE_SIZE)) {
 			rc = 1;
 			break;
 		}
-		bforget(bh);
+		page_cache_release(page);
 		fsync_bdev(bdev);
 		invalidate_bdev(bdev, 0);
-		bh = NULL;
+		page = NULL;
 	}
-	if (buffer)
-		free_page((unsigned long) buffer);
-	if (bh) {
-		bdev = bh->b_bdev;
-		bforget(bh);
+	if (page) {
+		bdev = page->mapping->host->i_bdev;
+		page_cache_release(page);
 		fsync_bdev(bdev);
 		invalidate_bdev(bdev, 0);
 	}
+	free_pages((unsigned long) buffer, order);
 	return rc;
 }
 
diff -Nru a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
--- a/drivers/message/i2o/i2o_block.c	Thu May  2 17:22:17 2002
+++ b/drivers/message/i2o/i2o_block.c	Thu May  2 17:22:17 2002
@@ -123,7 +123,6 @@
  *	Some of these can be made smaller later
  */
 
-static int i2ob_blksizes[MAX_I2OB<<4];
 static int i2ob_sizes[MAX_I2OB<<4];
 static int i2ob_media_change_flag[MAX_I2OB];
 
@@ -1815,7 +1814,6 @@
 	 *	Now fill in the boiler plate
 	 */
 	 
-	blksize_size[MAJOR_NR] = i2ob_blksizes;
 	blk_size[MAJOR_NR] = i2ob_sizes;
 	blk_dev[MAJOR_NR].queue = i2ob_get_queue;
 	
@@ -1830,7 +1828,6 @@
 		i2ob_dev[i].head = NULL;
 		i2ob_dev[i].tail = NULL;
 		i2ob_dev[i].depth = MAX_I2OB_DEPTH;
-		i2ob_blksizes[i] = 1024;
 	}
 	
 	/*
diff -Nru a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c
--- a/drivers/mtd/devices/blkmtd.c	Thu May  2 17:22:15 2002
+++ b/drivers/mtd/devices/blkmtd.c	Thu May  2 17:22:15 2002
@@ -1062,6 +1062,7 @@
   int readonly = 0;
   int erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
   kdev_t rdev;
+  struct block_device *bdev;
   int err;
   int mode;
   int regions;
@@ -1127,11 +1128,16 @@
     printk("blkmtd: attempting to use an MTD device as a block device\n");
     return 1;
   }
+  /* get the block device */
+  bdev = bdget(kdev_t_to_nr(mk_kdev(maj, min)));
+  err = blkdev_get(bdev, mode, 0, BDEV_RAW);
+  if (err)
+    return 1;
 
-  DEBUG(1, "blkmtd: devname = %s\n", __bdevname(rdev));
+  DEBUG(1, "blkmtd: devname = %s\n", bdevname(bdev));
   blocksize = BLOCK_SIZE;
 
-  blocksize = bs ? bs : block_size(rdev);
+  blocksize = bs ? bs : block_size(bdev);
   i = blocksize;
   blocksize_bits = 0;
   while(i != 1) {
@@ -1139,27 +1145,24 @@
     i >>= 1;
   }
 
-  size = (count ? count*blocksize : blkdev_size_in_bytes(rdev));
+  size = count ? count*blocksize : bdev->bd_inode->i_size;
 
   DEBUG(1, "blkmtd: size = %ld\n", (long int)size);
 
   if(size == 0) {
     printk("blkmtd: cant determine size\n");
+    blkdev_put(bdev, BDEV_RAW);
     return 1;
   }
 
   mtd_rawdevice = (mtd_raw_dev_data_t *)kmalloc(sizeof(mtd_raw_dev_data_t), GFP_KERNEL);
   if(mtd_rawdevice == NULL) {
+    blkdev_put(bdev, BDEV_RAW);
     err = -ENOMEM;
     goto init_err;
   }
   memset(mtd_rawdevice, 0, sizeof(mtd_raw_dev_data_t));
-  /* get the block device */
-  mtd_rawdevice->binding = bdget(kdev_t_to_nr(mk_kdev(maj, min)));
-  err = blkdev_get(mtd_rawdevice->binding, mode, 0, BDEV_RAW);
-  if (err) {
-    goto init_err;
-  }
+  mtd_rawdevice->binding = bdev;
   mtd_rawdevice->totalsize = size;
   mtd_rawdevice->sector_size = blocksize;
   mtd_rawdevice->sector_bits = blocksize_bits;
diff -Nru a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
--- a/drivers/mtd/ftl.c	Thu May  2 17:22:16 2002
+++ b/drivers/mtd/ftl.c	Thu May  2 17:22:16 2002
@@ -177,7 +177,6 @@
 
 static struct hd_struct ftl_hd[MINOR_NR(MAX_DEV, 0, 0)];
 static int ftl_sizes[MINOR_NR(MAX_DEV, 0, 0)];
-static int ftl_blocksizes[MINOR_NR(MAX_DEV, 0, 0)];
 
 static struct gendisk ftl_gendisk = {
     major:		FTL_MAJOR,
@@ -1345,13 +1344,10 @@
 	return -EAGAIN;
     }
     
-    for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0); i++)
-	ftl_blocksizes[i] = 1024;
     for (i = 0; i < MAX_DEV*MAX_PART; i++) {
 	ftl_hd[i].nr_sects = 0;
 	ftl_hd[i].start_sect = 0;
     }
-    blksize_size[FTL_MAJOR] = ftl_blocksizes;
     ftl_gendisk.major = FTL_MAJOR;
     blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR), &do_ftl_request);
     add_gendisk(&ftl_gendisk);
diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
--- a/drivers/mtd/mtdblock.c	Thu May  2 17:22:16 2002
+++ b/drivers/mtd/mtdblock.c	Thu May  2 17:22:16 2002
@@ -55,8 +55,6 @@
 static spinlock_t mtdblks_lock;
 
 static int mtd_sizes[MAX_MTD_DEVICES];
-static int mtd_blksizes[MAX_MTD_DEVICES];
-
 
 /*
  * Cache stuff...
@@ -346,10 +344,6 @@
 
 	mtdblks[dev] = mtdblk;
 	mtd_sizes[dev] = mtdblk->mtd->size/1024;
-	if (mtdblk->mtd->erasesize)
-		mtd_blksizes[dev] = mtdblk->mtd->erasesize;
-	if (mtd_blksizes[dev] > PAGE_SIZE)
-		mtd_blksizes[dev] = PAGE_SIZE;
 	set_device_ro (inode->i_rdev, !(mtdblk->mtd->flags & MTD_WRITEABLE));
 	
 	spin_unlock(&mtdblks_lock);
@@ -626,13 +620,9 @@
 #endif
 	
 	/* We fill it in at open() time. */
-	for (i=0; i< MAX_MTD_DEVICES; i++) {
+	for (i=0; i< MAX_MTD_DEVICES; i++)
 		mtd_sizes[i] = 0;
-		mtd_blksizes[i] = BLOCK_SIZE;
-	}
 	init_waitqueue_head(&thr_wq);
-	/* Allow the block size to default to BLOCK_SIZE. */
-	blksize_size[MAJOR_NR] = mtd_blksizes;
 	blk_size[MAJOR_NR] = mtd_sizes;
 	
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request, &mtddev_lock);
@@ -653,7 +643,6 @@
 	unregister_blkdev(MAJOR_NR,DEVICE_NAME);
 #endif
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-	blksize_size[MAJOR_NR] = NULL;
 	blk_size[MAJOR_NR] = NULL;
 }
 
diff -Nru a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
--- a/drivers/mtd/mtdblock_ro.c	Thu May  2 17:22:17 2002
+++ b/drivers/mtd/mtdblock_ro.c	Thu May  2 17:22:17 2002
@@ -258,7 +258,7 @@
 	if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
 		printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
 		       MTD_BLOCK_MAJOR);
-		return EAGAIN;
+		return -EAGAIN;
 	}
 	
 	/* We fill it in at open() time. */
@@ -267,7 +267,6 @@
 	}
 	
 	/* Allow the block size to default to BLOCK_SIZE. */
-	blksize_size[MAJOR_NR] = NULL;
 	blk_size[MAJOR_NR] = mtd_sizes;
 	
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
@@ -277,7 +276,6 @@
 static void __exit cleanup_mtdblock(void)
 {
 	unregister_blkdev(MAJOR_NR,DEVICE_NAME);
-	blksize_size[MAJOR_NR] = NULL;
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 }
 
diff -Nru a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
--- a/drivers/mtd/nftlcore.c	Thu May  2 17:22:15 2002
+++ b/drivers/mtd/nftlcore.c	Thu May  2 17:22:15 2002
@@ -53,7 +53,6 @@
  */
 
 static int nftl_sizes[256];
-static int nftl_blocksizes[256];
 
 /* .. for the Linux partition table handling. */
 struct hd_struct part_table[256];
@@ -146,7 +145,6 @@
 	NFTLs[firstfree] = nftl;
 	/* Finally, set up the block device sizes */
 	nftl_sizes[firstfree * 16] = nftl->nr_sects;
-	//nftl_blocksizes[firstfree*16] = 512;
 	part_table[firstfree * 16].nr_sects = nftl->nr_sects;
 
 	nftl_gendisk.nr_real++;
@@ -1027,13 +1025,6 @@
 		return -EBUSY;
 	} else {
 		blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
-
-		/* set block size to 1kB each */
-		for (i = 0; i < 256; i++) {
-			nftl_blocksizes[i] = 1024;
-		}
-		blksize_size[MAJOR_NR] = nftl_blocksizes;
-
 		add_gendisk(&nftl_gendisk);
 	}
 	
diff -Nru a/drivers/net/3c501.c b/drivers/net/3c501.c
--- a/drivers/net/3c501.c	Thu May  2 17:22:15 2002
+++ b/drivers/net/3c501.c	Thu May  2 17:22:15 2002
@@ -323,14 +323,18 @@
 
 	if (dev->irq < 2)
 	{
-		autoirq_setup(2);
+		unsigned long irq_mask, delay;
+
+		irq_mask = probe_irq_on();
 		inb(RX_STATUS);		/* Clear pending interrupts. */
 		inb(TX_STATUS);
 		outb(AX_LOOP + 1, AX_CMD);
 
 		outb(0x00, AX_CMD);
 
-		autoirq = autoirq_report(1);
+		delay = jiffies + HZ/50;
+		while (time_before(jiffies, delay)) ;
+		autoirq = probe_irq_off(irq_mask);
 
 		if (autoirq == 0)
 		{
diff -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c
--- a/drivers/net/3c509.c	Thu May  2 17:22:15 2002
+++ b/drivers/net/3c509.c	Thu May  2 17:22:15 2002
@@ -45,11 +45,13 @@
 			- Reviewed against 1.18 from scyld.com
 		v1.18a 17Nov2001 Jeff Garzik <jgarzik@mandrakesoft.com>
 			- ethtool support
+		v1.18b 1Mar2002 Zwane Mwaikambo <zwane@commfireservices.com>
+			- Power Management support
 */
 
 #define DRV_NAME	"3c509"
-#define DRV_VERSION	"1.18a"
-#define DRV_RELDATE	"17Nov2001"
+#define DRV_VERSION	"1.18b"
+#define DRV_RELDATE	"1Mar2002"
 
 /* A few values that may be tweaked. */
 
@@ -82,8 +84,9 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <linux/pm.h>
 
-static char versionA[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE "becker@scyld.com\n";
+static char versionA[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n";
 static char versionB[] __initdata = "http://www.scyld.com/network/3c509.html\n";
 
 #ifdef EL3_DEBUG
@@ -116,7 +119,8 @@
 	FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
 	SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
 	SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
-	StatsDisable = 22<<11, StopCoax = 23<<11,};
+	StatsDisable = 22<<11, StopCoax = 23<<11, PowerUp = 27<<11,
+	PowerDown = 28<<11, PowerAuto = 29<<11};
 
 enum c509status {
 	IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
@@ -152,6 +156,9 @@
 	int head, size;
 	struct sk_buff *queue[SKB_QUEUE_SIZE];
 	char mca_slot;
+#ifdef CONFIG_PM
+	struct pm_dev *pmdev;
+#endif
 };
 static int id_port __initdata = 0x110;	/* Start with 0x110 to avoid new sound cards.*/
 static struct net_device *el3_root_dev;
@@ -168,6 +175,13 @@
 static void set_multicast_list(struct net_device *dev);
 static void el3_tx_timeout (struct net_device *dev);
 static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static void el3_down(struct net_device *dev);
+static void el3_up(struct net_device *dev);
+#ifdef CONFIG_PM
+static int el3_suspend(struct pm_dev *pdev);
+static int el3_resume(struct pm_dev *pdev);
+static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data);
+#endif
 
 #ifdef CONFIG_MCA
 struct el3_mca_adapters_struct {
@@ -219,7 +233,7 @@
 #endif /* __ISAPNP__ */
 static int nopnp;
 
-int __init el3_probe(struct net_device *dev)
+int __init el3_probe(struct net_device *dev, int card_idx)
 {
 	struct el3_private *lp;
 	short lrs_state = 0xff, i;
@@ -525,6 +539,16 @@
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->do_ioctl = netdev_ioctl;
 
+#ifdef CONFIG_PM
+	/* register power management */
+	lp->pmdev = pm_register(PM_ISA_DEV, card_idx, el3_pm_callback);
+	if (lp->pmdev) {
+		struct pm_dev *p;
+		p = lp->pmdev;
+		p->data = (struct net_device *)dev;
+	}
+#endif
+
 	/* Fill in the generic fields of the device structure. */
 	ether_setup(dev);
 	return 0;
@@ -581,53 +605,7 @@
 		printk("%s: Opening, IRQ %d	 status@%x %4.4x.\n", dev->name,
 			   dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS));
 
-	/* Activate board: this is probably unnecessary. */
-	outw(0x0001, ioaddr + 4);
-
-	/* Set the IRQ line. */
-	outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ);
-
-	/* Set the station address in window 2 each time opened. */
-	EL3WINDOW(2);
-
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + i);
-
-	if (dev->if_port == 3)
-		/* Start the thinnet transceiver. We should really wait 50ms...*/
-		outw(StartCoax, ioaddr + EL3_CMD);
-	else if (dev->if_port == 0) {
-		/* 10baseT interface, enabled link beat and jabber check. */
-		EL3WINDOW(4);
-		outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA);
-	}
-
-	/* Switch to the stats window, and clear all stats by reading. */
-	outw(StatsDisable, ioaddr + EL3_CMD);
-	EL3WINDOW(6);
-	for (i = 0; i < 9; i++)
-		inb(ioaddr + i);
-	inw(ioaddr + 10);
-	inw(ioaddr + 12);
-
-	/* Switch to register set 1 for normal use. */
-	EL3WINDOW(1);
-
-	/* Accept b-case and phys addr only. */
-	outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
-	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
-
-	netif_start_queue(dev);
-
-	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
-	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
-	/* Allow status bits to be seen. */
-	outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
-	/* Ack all pending events, and set active indicator mask. */
-	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
-		 ioaddr + EL3_CMD);
-	outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull,
-		 ioaddr + EL3_CMD);
+	el3_up(dev);
 
 	if (el3_debug > 3)
 		printk("%s: Opened 3c509  IRQ %d  status %4.4x.\n",
@@ -986,23 +964,7 @@
 	if (el3_debug > 2)
 		printk("%s: Shutting down ethercard.\n", dev->name);
 
-	netif_stop_queue(dev);
-
-	/* Turn off statistics ASAP.  We update lp->stats below. */
-	outw(StatsDisable, ioaddr + EL3_CMD);
-
-	/* Disable the receiver and transmitter. */
-	outw(RxDisable, ioaddr + EL3_CMD);
-	outw(TxDisable, ioaddr + EL3_CMD);
-
-	if (dev->if_port == 3)
-		/* Turn off thinnet power.  Green! */
-		outw(StopCoax, ioaddr + EL3_CMD);
-	else if (dev->if_port == 0) {
-		/* Disable link beat and jabber, if_port may change ere next open(). */
-		EL3WINDOW(4);
-		outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);
-	}
+	el3_down(dev);
 
 	free_irq(dev->irq, dev);
 	/* Switching back to window 0 disables the IRQ. */
@@ -1010,7 +972,6 @@
 	/* But we explicitly zero the IRQ line select anyway. */
 	outw(0x0f00, ioaddr + WN0_IRQ);
 
-	update_stats(dev);
 	return 0;
 }
 
@@ -1092,7 +1053,157 @@
 
 	return rc;
 }
- 
+
+static void el3_down(struct net_device *dev)
+{
+	int ioaddr = dev->base_addr;
+
+	netif_stop_queue(dev);
+
+	/* Turn off statistics ASAP.  We update lp->stats below. */
+	outw(StatsDisable, ioaddr + EL3_CMD);
+
+	/* Disable the receiver and transmitter. */
+	outw(RxDisable, ioaddr + EL3_CMD);
+	outw(TxDisable, ioaddr + EL3_CMD);
+
+	if (dev->if_port == 3)
+		/* Turn off thinnet power.  Green! */
+		outw(StopCoax, ioaddr + EL3_CMD);
+	else if (dev->if_port == 0) {
+		/* Disable link beat and jabber, if_port may change ere next open(). */
+		EL3WINDOW(4);
+		outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);
+	}
+
+	outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
+
+	update_stats(dev);
+}
+
+static void el3_up(struct net_device *dev)
+{
+	int i;
+	int ioaddr = dev->base_addr;
+	
+	/* Activating the board required and does no harm otherwise */
+	outw(0x0001, ioaddr + 4);
+
+	/* Set the IRQ line. */
+	outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ);
+
+	/* Set the station address in window 2 each time opened. */
+	EL3WINDOW(2);
+
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + i);
+
+	if (dev->if_port == 3)
+		/* Start the thinnet transceiver. We should really wait 50ms...*/
+		outw(StartCoax, ioaddr + EL3_CMD);
+	else if (dev->if_port == 0) {
+		/* 10baseT interface, enabled link beat and jabber check. */
+		EL3WINDOW(4);
+		outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA);
+	}
+
+	/* Switch to the stats window, and clear all stats by reading. */
+	outw(StatsDisable, ioaddr + EL3_CMD);
+	EL3WINDOW(6);
+	for (i = 0; i < 9; i++)
+		inb(ioaddr + i);
+	inw(ioaddr + 10);
+	inw(ioaddr + 12);
+
+	/* Switch to register set 1 for normal use. */
+	EL3WINDOW(1);
+
+	/* Accept b-case and phys addr only. */
+	outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
+
+	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
+	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
+	/* Allow status bits to be seen. */
+	outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
+	/* Ack all pending events, and set active indicator mask. */
+	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+		 ioaddr + EL3_CMD);
+	outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull,
+		 ioaddr + EL3_CMD);
+
+	netif_start_queue(dev);
+}
+
+/* Power Management support functions */
+#ifdef CONFIG_PM
+
+static int el3_suspend(struct pm_dev *pdev)
+{
+	unsigned long flags;
+	struct net_device *dev;
+	struct el3_private *lp;
+	int ioaddr;
+	
+	if (!pdev && !pdev->data)
+		return -EINVAL;
+
+	dev = (struct net_device *)pdev->data;
+	lp = (struct el3_private *)dev->priv;
+	ioaddr = dev->base_addr;
+
+	spin_lock_irqsave(&lp->lock, flags);
+
+	if (netif_running(dev))
+		netif_device_detach(dev);
+
+	el3_down(dev);
+	outw(PowerDown, ioaddr + EL3_CMD);
+
+	spin_unlock_irqrestore(&lp->lock, flags);
+	return 0;
+}
+
+static int el3_resume(struct pm_dev *pdev)
+{
+	unsigned long flags;
+	struct net_device *dev;
+	struct el3_private *lp;
+	int ioaddr;
+	
+	if (!pdev && !pdev->data)
+		return -EINVAL;
+
+	dev = (struct net_device *)pdev->data;
+	lp = (struct el3_private *)dev->priv;
+	ioaddr = dev->base_addr;
+
+	spin_lock_irqsave(&lp->lock, flags);
+
+	outw(PowerUp, ioaddr + EL3_CMD);
+	el3_up(dev);
+
+	if (netif_running(dev))
+		netif_device_attach(dev);
+		
+	spin_unlock_irqrestore(&lp->lock, flags);
+	return 0;
+}
+
+static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data)
+{
+	switch (rqst) {
+		case PM_SUSPEND:
+			return el3_suspend(pdev);
+
+		case PM_RESUME:
+			return el3_resume(pdev);
+	}
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
 #ifdef MODULE
 /* Parameters that may be passed into the module. */
 static int debug = -1;
@@ -1122,7 +1233,7 @@
 		el3_debug = debug;
 
 	el3_root_dev = NULL;
-	while (el3_probe(0) == 0) {
+	while (el3_probe(0, el3_cards) == 0) {
 		if (irq[el3_cards] > 1)
 			el3_root_dev->irq = irq[el3_cards];
 		if (xcvr[el3_cards] >= 0)
@@ -1144,7 +1255,12 @@
 #ifdef CONFIG_MCA		
 		if(lp->mca_slot!=-1)
 			mca_mark_as_unused(lp->mca_slot);
-#endif			
+#endif
+
+#ifdef CONFIG_PM
+		if (lp->pmdev)
+			pm_unregister(lp->pmdev);
+#endif
 		next_dev = lp->next_dev;
 		unregister_netdev(el3_root_dev);
 		release_region(el3_root_dev->base_addr, EL3_IO_EXTENT);
diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c
--- a/drivers/net/8139cp.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/8139cp.c	Thu May  2 17:22:17 2002
@@ -37,8 +37,8 @@
 	* Investigate using High Priority Tx Queue with skb->priority
 	* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
 	* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
-        * Implement Tx software interrupt mitigation via
-	          Tx descriptor bit
+	* Implement Tx software interrupt mitigation via
+	  Tx descriptor bit
 	* The real minimum of CP_MIN_MTU is 4 bytes.  However,
 	  for this to be supported, one must(?) turn on packet padding.
 
diff -Nru a/drivers/net/8390.h b/drivers/net/8390.h
--- a/drivers/net/8390.h	Thu May  2 17:22:17 2002
+++ b/drivers/net/8390.h	Thu May  2 17:22:17 2002
@@ -39,12 +39,6 @@
 #define ei_debug 1
 #endif
 
-#ifndef HAVE_AUTOIRQ
-/* From auto_irq.c */
-extern void autoirq_setup(int waittime);
-extern unsigned long autoirq_report(int waittime);
-#endif
-
 extern int ethdev_init(struct net_device *dev);
 extern void NS8390_init(struct net_device *dev, int startp);
 extern int ei_open(struct net_device *dev);
diff -Nru a/drivers/net/Config.in b/drivers/net/Config.in
--- a/drivers/net/Config.in	Thu May  2 17:22:15 2002
+++ b/drivers/net/Config.in	Thu May  2 17:22:15 2002
@@ -3,7 +3,6 @@
 #
 
 source drivers/net/arcnet/Config.in
-source drivers/net/appletalk/Config.in
 
 tristate 'Dummy net driver support' CONFIG_DUMMY
 tristate 'Bonding driver support' CONFIG_BONDING
diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile	Thu May  2 17:22:16 2002
+++ b/drivers/net/Makefile	Thu May  2 17:22:16 2002
@@ -41,7 +41,7 @@
 subdir-$(CONFIG_WAN) += wan
 subdir-$(CONFIG_NET_FC) += fc
 subdir-$(CONFIG_ARCNET) += arcnet
-subdir-$(CONFIG_APPLETALK) += appletalk
+subdir-$(CONFIG_DEV_APPLETALK) += appletalk
 subdir-$(CONFIG_SK98LIN) += sk98lin
 subdir-$(CONFIG_SKFP) += skfp
 
@@ -219,16 +219,6 @@
 mod-subdirs	+= ../acorn/net
 subdir-y	+= ../acorn/net
 obj-y		+= ../acorn/net/acorn-net.o
-endif
-
-#
-# HIPPI adapters
-#
-
-ifneq ($(ARCH),s390)
-ifneq ($(ARCH),s390x)
-obj-y += auto_irq.o
-endif
 endif
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/net/Space.c b/drivers/net/Space.c
--- a/drivers/net/Space.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/Space.c	Thu May  2 17:22:16 2002
@@ -697,37 +697,37 @@
 	next:		NEXT_DEV,
 	init:		sbni_probe,
 };
-static struct net_device sbni6_dev =
+static struct net_device sbni6_dev = {
 	name:		"sbni6",
 	next:		&sbni7_dev,
 	init:		sbni_probe,
 };
-static struct net_device sbni5_dev =
+static struct net_device sbni5_dev = {
 	name:		"sbni5",
 	next:		&sbni6_dev,
 	init:		sbni_probe,
 };
-static struct net_device sbni4_dev =
+static struct net_device sbni4_dev = {
 	name:		"sbni4",
 	next:		&sbni5_dev,
 	init:		sbni_probe,
 };
-static struct net_device sbni3_dev =
+static struct net_device sbni3_dev = {
 	name:		"sbni3",
 	next:		&sbni4_dev,
 	init:		sbni_probe,
 };
-static struct net_device sbni2_dev =
+static struct net_device sbni2_dev = {
 	name:		"sbni2",
 	next:		&sbni3_dev,
 	init:		sbni_probe,
 };
-static struct net_device sbni1_dev =
+static struct net_device sbni1_dev = {
 	name:		"sbni1",
 	next:		&sbni2_dev,
 	init:		sbni_probe,
 };
-static struct net_device sbni0_dev =
+static struct net_device sbni0_dev = {
 	name:		"sbni0",
 	next:		&sbni1_dev,
 	init:		sbni_probe,
diff -Nru a/drivers/net/apne.c b/drivers/net/apne.c
--- a/drivers/net/apne.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/apne.c	Thu May  2 17:22:17 2002
@@ -54,19 +54,19 @@
 #define NE_BASE	 (dev->base_addr)
 #define NE_CMD	 		0x00
 #define NE_DATAPORT		0x10            /* NatSemi-defined port window offset. */
-#define NE_RESET		0x1f+GAYLE_ODD  /* Issue a read to reset, a write to clear. */
-#define NE_IO_EXTENT	0x20
+#define NE_RESET		0x1f            /* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT	        0x20
 
-#define NE_EN0_ISR		0x07+GAYLE_ODD
+#define NE_EN0_ISR		0x07
 #define NE_EN0_DCFG		0x0e
 
-#define NE_EN0_RSARLO	0x08
-#define NE_EN0_RSARHI	0x09+GAYLE_ODD
-#define NE_EN0_RCNTLO	0x0a
+#define NE_EN0_RSARLO	        0x08
+#define NE_EN0_RSARHI	        0x09
+#define NE_EN0_RCNTLO	        0x0a
 #define NE_EN0_RXCR		0x0c
-#define NE_EN0_TXCR		0x0d+GAYLE_ODD
-#define NE_EN0_RCNTHI	0x0b+GAYLE_ODD
-#define NE_EN0_IMR		0x0f+GAYLE_ODD
+#define NE_EN0_TXCR		0x0d
+#define NE_EN0_RCNTHI	        0x0b
+#define NE_EN0_IMR		0x0f
 
 #define NE1SM_START_PG	0x20	/* First page of TX buffer */
 #define NE1SM_STOP_PG 	0x40	/* Last page +1 of RX ring */
@@ -157,7 +157,7 @@
 	printk("ethernet PCMCIA card inserted\n");
 
 	if (init_pcmcia())
-		return apne_probe1(dev, IOBASE+GAYLE_IO);
+		return apne_probe1(dev, IOBASE);
 	else
 		return (-ENODEV);
 
@@ -174,12 +174,7 @@
     int neX000, ctron;
 #endif
     static unsigned version_printed;
-    static u32 pcmcia_offsets[16]={
-                0,   1+GAYLE_ODD,   2,   3+GAYLE_ODD,
-                4,   5+GAYLE_ODD,   6,   7+GAYLE_ODD,
-                8,   9+GAYLE_ODD, 0xa, 0xb+GAYLE_ODD,
-              0xc, 0xd+GAYLE_ODD, 0xe, 0xf+GAYLE_ODD };
-
+ 
     if (ei_debug  &&  version_printed++ == 0)
 	printk(version);
 
@@ -188,15 +183,15 @@
     /* Reset card. Who knows what dain-bramaged state it was left in. */
     {	unsigned long reset_start_time = jiffies;
 
-	writeb(readb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+	outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
 
-	while ((readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
+	while ((inb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
 		if (jiffies - reset_start_time > 2*HZ/100) {
 			printk(" not found (no reset ack).\n");
 			return -ENODEV;
 		}
 
-	writeb(0xff, ioaddr + NE_EN0_ISR);		/* Ack all intr. */
+	outb(0xff, ioaddr + NE_EN0_ISR);		/* Ack all intr. */
     }
 
 #ifndef MANUAL_HWADDR0
@@ -222,13 +217,13 @@
 	    {E8390_RREAD+E8390_START, NE_CMD},
 	};
 	for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
-	    writeb(program_seq[i].value, ioaddr + program_seq[i].offset);
+	    outb(program_seq[i].value, ioaddr + program_seq[i].offset);
 	}
 
     }
     for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
-	SA_prom[i] = readb(ioaddr + NE_DATAPORT);
-	SA_prom[i+1] = readb(ioaddr + NE_DATAPORT);
+	SA_prom[i] = inb(ioaddr + NE_DATAPORT);
+	SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
 	if (SA_prom[i] != SA_prom[i+1])
 	    wordlength = 1;
     }
@@ -244,7 +239,7 @@
     
     if (wordlength == 2) {
 	/* We must set the 8390 for word mode. */
-	writeb(0x49, ioaddr + NE_EN0_DCFG);
+	outb(0x49, ioaddr + NE_EN0_DCFG);
 	start_page = NESM_START_PG;
 	stop_page = NESM_STOP_PG;
     } else {
@@ -271,7 +266,7 @@
 #else
     wordlength = 2;
     /* We must set the 8390 for word mode. */
-    writeb(0x49, ioaddr + NE_EN0_DCFG);
+    outb(0x49, ioaddr + NE_EN0_DCFG);
     start_page = NESM_START_PG;
     stop_page = NESM_STOP_PG;
 
@@ -314,7 +309,6 @@
     ei_status.block_input = &apne_block_input;
     ei_status.block_output = &apne_block_output;
     ei_status.get_8390_hdr = &apne_get_8390_hdr;
-    ei_status.reg_offset = pcmcia_offsets;
     dev->open = &apne_open;
     dev->stop = &apne_close;
     NS8390_init(dev, 0);
@@ -354,18 +348,18 @@
 
     if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies);
 
-    writeb(readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+    outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
 
     ei_status.txing = 0;
     ei_status.dmaing = 0;
 
     /* This check _should_not_ be necessary, omit eventually. */
-    while ((readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
+    while ((inb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
 	if (jiffies - reset_start_time > 2*HZ/100) {
 	    printk("%s: ne_reset_8390() did not complete.\n", dev->name);
 	    break;
 	}
-    writeb(ENISR_RESET, NE_BASE + NE_EN0_ISR);	/* Ack intr. */
+    outb(ENISR_RESET, NE_BASE + NE_EN0_ISR);	/* Ack intr. */
 }
 
 /* Grab the 8390 specific header. Similar to the block_input routine, but
@@ -390,25 +384,25 @@
     }
 
     ei_status.dmaing |= 0x01;
-    writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
-    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
-    writeb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);
-    writeb(0, nic_base + NE_EN0_RCNTHI);
-    writeb(0, nic_base + NE_EN0_RSARLO);		/* On page boundary */
-    writeb(ring_page, nic_base + NE_EN0_RSARHI);
-    writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+    outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+    outb(ENISR_RDC, nic_base + NE_EN0_ISR);
+    outb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);
+    outb(0, nic_base + NE_EN0_RCNTHI);
+    outb(0, nic_base + NE_EN0_RSARLO);		/* On page boundary */
+    outb(ring_page, nic_base + NE_EN0_RSARHI);
+    outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
 
     if (ei_status.word16) {
         ptrs = (short*)hdr;
         for(cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++)
-            *ptrs++ = readw(NE_BASE + NE_DATAPORT);
+            *ptrs++ = inw(NE_BASE + NE_DATAPORT);
     } else {
         ptrc = (char*)hdr;
         for(cnt = 0; cnt < sizeof(struct e8390_pkt_hdr); cnt++)
-            *ptrc++ = readb(NE_BASE + NE_DATAPORT);
+            *ptrc++ = inb(NE_BASE + NE_DATAPORT);
     }
 
-    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
+    outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
 
     hdr->count = WORDSWAP(hdr->count);
 
@@ -418,7 +412,7 @@
 /* Block input and output, similar to the Crynwr packet driver.  If you
    are porting to a new ethercard, look at the packet driver source for hints.
    The NEx000 doesn't share the on-board packet memory -- you have to put
-   the packet out through the "remote DMA" dataport using writeb. */
+   the packet out through the "remote DMA" dataport using outb. */
 
 static void
 apne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
@@ -437,27 +431,27 @@
 	return;
     }
     ei_status.dmaing |= 0x01;
-    writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
-    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
-    writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
-    writeb(count >> 8, nic_base + NE_EN0_RCNTHI);
-    writeb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
-    writeb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
-    writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+    outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+    outb(ENISR_RDC, nic_base + NE_EN0_ISR);
+    outb(count & 0xff, nic_base + NE_EN0_RCNTLO);
+    outb(count >> 8, nic_base + NE_EN0_RCNTHI);
+    outb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
+    outb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
+    outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
     if (ei_status.word16) {
       ptrs = (short*)buf;
       for (cnt = 0; cnt < (count>>1); cnt++)
-        *ptrs++ = readw(NE_BASE + NE_DATAPORT);
+        *ptrs++ = inw(NE_BASE + NE_DATAPORT);
       if (count & 0x01) {
-	buf[count-1] = readb(NE_BASE + NE_DATAPORT);
+	buf[count-1] = inb(NE_BASE + NE_DATAPORT);
       }
     } else {
       ptrc = (char*)buf;
       for (cnt = 0; cnt < count; cnt++)
-        *ptrc++ = readb(NE_BASE + NE_DATAPORT);
+        *ptrc++ = inb(NE_BASE + NE_DATAPORT);
     }
 
-    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
+    outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
     ei_status.dmaing &= ~0x01;
 }
 
@@ -486,30 +480,30 @@
     }
     ei_status.dmaing |= 0x01;
     /* We should already be in page 0, but to be safe... */
-    writeb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+    outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
 
-    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+    outb(ENISR_RDC, nic_base + NE_EN0_ISR);
 
    /* Now the normal output. */
-    writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
-    writeb(count >> 8,   nic_base + NE_EN0_RCNTHI);
-    writeb(0x00, nic_base + NE_EN0_RSARLO);
-    writeb(start_page, nic_base + NE_EN0_RSARHI);
+    outb(count & 0xff, nic_base + NE_EN0_RCNTLO);
+    outb(count >> 8,   nic_base + NE_EN0_RCNTHI);
+    outb(0x00, nic_base + NE_EN0_RSARLO);
+    outb(start_page, nic_base + NE_EN0_RSARHI);
 
-    writeb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+    outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
     if (ei_status.word16) {
         ptrs = (short*)buf;
         for (cnt = 0; cnt < count>>1; cnt++)
-            writew(*ptrs++, NE_BASE+NE_DATAPORT);
+            outw(*ptrs++, NE_BASE+NE_DATAPORT);
     } else {
         ptrc = (char*)buf;
         for (cnt = 0; cnt < count; cnt++)
-	    writeb(*ptrc++, NE_BASE + NE_DATAPORT);
+	    outb(*ptrc++, NE_BASE + NE_DATAPORT);
     }
 
     dma_start = jiffies;
 
-    while ((readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
+    while ((inb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
 	if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
 		printk("%s: timeout waiting for Tx RDC.\n", dev->name);
 		apne_reset_8390(dev);
@@ -517,7 +511,7 @@
 		break;
 	}
 
-    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
+    outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
     ei_status.dmaing &= ~0x01;
     return;
 }
@@ -611,7 +605,9 @@
 	}
 #endif
 
-	writeb(config, GAYLE_ATTRIBUTE+offset);
+	out_8(GAYLE_ATTRIBUTE+offset, config);
 
 	return 1;
 }
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/net/appletalk/Config.help b/drivers/net/appletalk/Config.help
--- a/drivers/net/appletalk/Config.help	Thu May  2 17:22:16 2002
+++ b/drivers/net/appletalk/Config.help	Thu May  2 17:22:16 2002
@@ -1,8 +1,9 @@
-CONFIG_APPLETALK
-  AppleTalk is the way Apple computers speak to each other on a
-  network. If your Linux box is connected to such a network and you
-  want to join the conversation, say Y.
-
+CONFIG_DEV_APPLETALK
+  AppleTalk is the protocol that Apple computers can use to communicate
+  on a network.  If your Linux box is connected to such a network, and wish
+  to do IP over it, or you have a LocalTalk card and wish to use it to
+  connect to the AppleTalk network, say Y.
+ 
 CONFIG_IPDDP
   This allows IP networking for users who only have AppleTalk
   networking available. This feature is experimental. With this
diff -Nru a/drivers/net/appletalk/Config.in b/drivers/net/appletalk/Config.in
--- a/drivers/net/appletalk/Config.in	Thu May  2 17:22:15 2002
+++ b/drivers/net/appletalk/Config.in	Thu May  2 17:22:15 2002
@@ -2,22 +2,20 @@
 # Appletalk driver configuration
 #
 
-if [ "$CONFIG_ATALK" != "n" ]; then
-   mainmenu_option next_comment
-   comment 'Appletalk devices'
-   bool 'Appletalk interfaces support' CONFIG_APPLETALK
-   if [ "$CONFIG_ATALK" != "n" ]; then
-      dep_tristate '  Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_DEV_APPLETALK
-      dep_tristate '  COPS LocalTalk PC support' CONFIG_COPS $CONFIG_DEV_APPLETALK
-      if [ "$CONFIG_COPS" != "n" ]; then
-	 bool '    Dayna firmware support' CONFIG_COPS_DAYNA
-	 bool '    Tangent firmware support' CONFIG_COPS_TANGENT
-      fi
-      dep_tristate '  Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_DEV_APPLETALK
-      if [ "$CONFIG_IPDDP" != "n" ]; then
-	 bool '    IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
-	 bool '    Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
-      fi
+mainmenu_option next_comment
+comment 'Appletalk devices'
+dep_mbool 'Appletalk interfaces support' CONFIG_DEV_APPLETALK $CONFIG_ATALK
+if [ "$CONFIG_DEV_APPLETALK" = "y" ]; then
+   tristate '  Apple/Farallon LocalTalk PC support' CONFIG_LTPC
+   tristate '  COPS LocalTalk PC support' CONFIG_COPS
+   if [ "$CONFIG_COPS" != "n" ]; then
+      bool '    Dayna firmware support' CONFIG_COPS_DAYNA $CONFIG_COPS
+      bool '    Tangent firmware support' CONFIG_COPS_TANGENT $CONFIG_COPS
+   fi
+   dep_tristate '  Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK
+   if [ "$CONFIG_IPDDP" != "n" ]; then
+      bool '    IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP $CONFIG_IPDDP
+      bool '    Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP $CONFIG_IPDDP
    fi
-   endmenu
 fi
+endmenu
diff -Nru a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
--- a/drivers/net/appletalk/ltpc.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/appletalk/ltpc.c	Thu May  2 17:22:16 2002
@@ -1092,15 +1092,18 @@
 
 	/* probe for the IRQ line */
 	if (irq < 2) {
-		autoirq_setup(2);
+		unsigned long irq_mask, delay;
 
+		irq_mask = probe_irq_on();
 		/* reset the interrupt line */
 		inb_p(io+7);
 		inb_p(io+7);
 		/* trigger an interrupt (I hope) */
 		inb_p(io+6);
 
-		autoirq = autoirq_report(1);
+		delay = jiffies + HZ/50;
+		while (time_before(jiffies, delay)) ;
+		autoirq = probe_irq_off(irq_mask);
 
 		if (autoirq == 0) {
 			printk("ltpc: probe at %#x failed to detect IRQ line.\n",
diff -Nru a/drivers/net/ariadne.c b/drivers/net/ariadne.c
--- a/drivers/net/ariadne.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/ariadne.c	Thu May  2 17:22:17 2002
@@ -54,7 +54,7 @@
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
 #include <linux/zorro.h>
-#include <asm/io.h>
+
 #include <asm/irq.h>
 
 #include "ariadne.h"
diff -Nru a/drivers/net/depca.c b/drivers/net/depca.c
--- a/drivers/net/depca.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/depca.c	Thu May  2 17:22:17 2002
@@ -682,7 +682,9 @@
 	if (dev->irq < 2) {
 #ifndef MODULE
 		unsigned char irqnum;
-		autoirq_setup(0);
+		unsigned long irq_mask, delay;
+
+		irq_mask = probe_irq_on();
 
 		/* Assign the correct irq list */
 		switch (lp->adapter) {
@@ -706,7 +708,10 @@
 		/* Trigger an initialization just for the interrupt. */
 		outw(INEA | INIT, DEPCA_DATA);
 	  
-		irqnum = autoirq_report(1);
+		delay = jiffies + HZ/50;
+		while (time_before(jiffies, delay)) ;
+		irqnum = probe_irq_off(irq_mask);
+
 		status = -ENXIO;
 		if (!irqnum) {
 			printk(" and failed to detect IRQ line.\n");
diff -Nru a/drivers/net/dgrs.c b/drivers/net/dgrs.c
--- a/drivers/net/dgrs.c	Thu May  2 17:22:15 2002
+++ b/drivers/net/dgrs.c	Thu May  2 17:22:15 2002
@@ -1153,9 +1153,7 @@
 	 */
 	rc = dgrs_download(dev);
 	if (rc)
-	{
-		return rc;
-	}
+		goto err_out;
 
 	/*
 	 * Get ether address of board
@@ -1169,7 +1167,8 @@
 	if (dev->dev_addr[0] & 1)
 	{
 		printk("%s: Illegal Ethernet Address\n", dev->name);
-		return (-ENXIO);
+		rc = -ENXIO;
+		goto err_out;
 	}
 
 	/*
@@ -1178,9 +1177,10 @@
 	 */
 	if (priv->plxreg)
 		OUTL(dev->base_addr + PLX_LCL2PCI_DOORBELL, 1);
+	
 	rc = request_irq(dev->irq, &dgrs_intr, SA_SHIRQ, "RightSwitch", dev);
 	if (rc)
-		return (rc);
+		goto err_out;
 
 	priv->intrcnt = 0;
 	for (i = jiffies + 2*HZ + HZ/2; time_after(i, jiffies); )
@@ -1191,16 +1191,22 @@
 	}
 	if (priv->intrcnt < 2)
 	{
-		printk("%s: Not interrupting on IRQ %d (%d)\n",
+		printk(KERN_ERR "%s: Not interrupting on IRQ %d (%d)\n",
 				dev->name, dev->irq, priv->intrcnt);
-		return (-ENXIO);
+		rc = -ENXIO;
+		goto err_free_irq;
 	}
 
 	/*
 	 *	Register the /proc/ioports information...
 	 */
-	request_region(dev->base_addr, 256, "RightSwitch");
-
+	if (!request_region(dev->base_addr, 256, "RightSwitch")) {
+		printk(KERN_ERR "%s: io 0x%3lX, which is busy.\n", dev->name,
+				dev->base_addr);
+		rc = -EBUSY;
+		goto err_free_irq;
+	}
+	
 	/*
 	 *	Entry points...
 	 */
@@ -1211,7 +1217,12 @@
 	dev->set_multicast_list = &dgrs_set_multicast_list;
 	dev->do_ioctl = &dgrs_ioctl;
 
-	return (0);
+	return rc;
+
+err_free_irq:
+	free_irq(dev->irq, dev);
+err_out:
+       	return rc;
 }
 
 int __init 
diff -Nru a/drivers/net/e100/e100_phy.c b/drivers/net/e100/e100_phy.c
--- a/drivers/net/e100/e100_phy.c	Thu May  2 17:22:15 2002
+++ b/drivers/net/e100/e100_phy.c	Thu May  2 17:22:15 2002
@@ -873,7 +873,7 @@
 	e100_set_fc(bdp);
 }
 
-void __devexit
+void
 e100_phy_reset(struct e100_private *bdp)
 {
 	u16 ctrl_reg;
diff -Nru a/drivers/net/eepro.c b/drivers/net/eepro.c
--- a/drivers/net/eepro.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/eepro.c	Thu May  2 17:22:17 2002
@@ -896,12 +896,16 @@
 		eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
 
 		if (request_irq (*irqp, NULL, SA_SHIRQ, "bogus", dev) != EBUSY) {
+			unsigned long irq_mask, delay;
 			/* Twinkle the interrupt, and check if it's seen */
-			autoirq_setup(0);
+			irq_mask = probe_irq_on();
 
 			eepro_diag(ioaddr); /* RESET the 82595 */
 
-			if (*irqp == autoirq_report(2))  /* It's a good IRQ line */
+			delay = jiffies + HZ/50;
+			while (time_before(jiffies, delay)) ;
+
+			if (*irqp == probe_irq_off(irq_mask))  /* It's a good IRQ line */
 				break;
 
 			/* clear all interrupts */
diff -Nru a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
--- a/drivers/net/ewrk3.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/ewrk3.c	Thu May  2 17:22:16 2002
@@ -555,8 +555,10 @@
 								if (dev->irq < 2) {
 #ifndef MODULE
 									u_char irqnum;
+									unsigned long irq_mask, delay;
+			
 
-									autoirq_setup(0);
+									irq_mask = probe_irq_on();
 
 									/*
 									   ** Trigger a TNE interrupt.
@@ -567,7 +569,9 @@
 
 									irqnum = irq[((icr & IRQ_SEL) >> 4)];
 
-									dev->irq = autoirq_report(1);
+									delay = jiffies + HZ/50;
+									while (time_before(jiffies, delay)) ;
+									dev->irq = probe_irq_off(irq_mask);
 									if ((dev->irq) && (irqnum == dev->irq)) {
 										printk(" and uses IRQ%d.\n", dev->irq);
 									} else {
diff -Nru a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c
--- a/drivers/net/gt96100eth.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/gt96100eth.c	Thu May  2 17:22:17 2002
@@ -1624,8 +1624,9 @@
 	if (!options || !*options)
 		return 0;
 
-        for(this_opt=strtok(options, ",");
-	    this_opt; this_opt=strtok(NULL, ",")) {
+	while ((this_opt = strsep (&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
 		if (!strncmp(this_opt, "mac0:", 5)) {
 			memcpy(mac0, this_opt+5, 17);
 			mac0[17]= '\0';
diff -Nru a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
--- a/drivers/net/hamradio/baycom_ser_fdx.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/hamradio/baycom_ser_fdx.c	Thu May  2 17:22:17 2002
@@ -417,21 +417,27 @@
 		return -ENXIO;
 	if (bc->baud < 300 || bc->baud > 4800)
 		return -EINVAL;
-	if (check_region(dev->base_addr, SER12_EXTENT))
+	if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) {
+		printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy \n", 
+		       dev->base_addr);
 		return -EACCES;
+	}
 	memset(&bc->modem, 0, sizeof(bc->modem));
 	bc->hdrv.par.bitrate = bc->baud;
 	bc->baud_us = 1000000/bc->baud;
 	bc->baud_uartdiv = (115200/8)/bc->baud;
-	if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown)
+	if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown){
+		release_region(dev->base_addr, SER12_EXTENT);
 		return -EIO;
+	}
 	outb(0, FCR(dev->base_addr));  /* disable FIFOs */
 	outb(0x0d, MCR(dev->base_addr));
 	outb(0, IER(dev->base_addr));
 	if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT | SA_SHIRQ,
-			"baycom_ser_fdx", dev))
+			"baycom_ser_fdx", dev)) {
+		release_region(dev->base_addr, SER12_EXTENT);
 		return -EBUSY;
-	request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx");
+	}
 	/*
 	 * set the SIO to 6 Bits/character; during receive,
 	 * the baud rate is set to produce 100 ints/sec
diff -Nru a/drivers/net/irda/Config.help b/drivers/net/irda/Config.help
--- a/drivers/net/irda/Config.help	Thu May  2 17:22:15 2002
+++ b/drivers/net/irda/Config.help	Thu May  2 17:22:15 2002
@@ -138,6 +138,18 @@
   used by IrTTY.  To activate support for Parallax dongles you will
   have to start irattach like this "irattach -d litelink".
 
+Microchip MCP2120 dongle
+CONFIG_MCP2120_DONGLE
+  Say Y here if you want to build support for the Microchip MCP2120
+  dongle.  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The MCP2120 dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  used by IrTTY.  To activate support for MCP2120 dongles you will
+  have to insert "irattach -d mcp2120" in the /etc/irda/drivers script.
+
+  You must build this dongle yourself.  For more information see:
+  <http://www.eyetap.org/~tangf/irda_sir_linux.html>
+
 CONFIG_OLD_BELKIN_DONGLE
   Say Y here if you want to build support for the Adaptec Airport 1000
   and 2000 dongles.  If you want to compile it as a module, say M here
diff -Nru a/drivers/net/irda/Config.in b/drivers/net/irda/Config.in
--- a/drivers/net/irda/Config.in	Thu May  2 17:22:16 2002
+++ b/drivers/net/irda/Config.in	Thu May  2 17:22:16 2002
@@ -13,6 +13,7 @@
    dep_tristate '  Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRDA
    dep_tristate '  Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA
    dep_tristate '  Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA
+   dep_tristate '  Microchip MCP2120' CONFIG_MCP2120_DONGLE $CONFIG_IRDA
    dep_tristate '  Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA   
    if [ "$CONFIG_ARCH_EP7211" = "y" ]; then
       dep_tristate '  EP7211 I/R support' CONFIG_EP7211_IR $CONFIG_IRDA
diff -Nru a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
--- a/drivers/net/irda/Makefile	Thu May  2 17:22:17 2002
+++ b/drivers/net/irda/Makefile	Thu May  2 17:22:17 2002
@@ -28,5 +28,6 @@
 obj-$(CONFIG_LITELINK_DONGLE)	+= litelink.o
 obj-$(CONFIG_OLD_BELKIN_DONGLE)	+= old_belkin.o
 obj-$(CONFIG_EP7211_IR)		+= ep7211_ir.o
+obj-$(CONFIG_MCP2120_DONGLE)	+= mcp2120.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c
--- a/drivers/net/irda/irtty.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/irda/irtty.c	Thu May  2 17:22:16 2002
@@ -970,9 +970,14 @@
 
 	IRDA_DEBUG(3, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
+	/* Locking :
+	 * irda_device_dongle_init() can't be locked.
+	 * irda_task_execute() doesn't need to be locked (but
+	 * irtty_change_speed() should protect itself).
+	 * As this driver doesn't have spinlock protection, keep
+	 * old fashion locking :-(
+	 * Jean II
+	 */
 	
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
@@ -998,14 +1003,17 @@
 		dongle->write       = irtty_raw_write;
 		dongle->set_dtr_rts = irtty_set_dtr_rts;
 		
-		self->dongle = dongle;
-
-		/* Now initialize the dongle!  */
+		/* Now initialize the dongle!
+		 * Safe to do unlocked : self->dongle is still NULL. */ 
 		dongle->issue->open(dongle, &self->qos);
 		
 		/* Reset dongle */
 		irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, 
 				  NULL);	
+
+		/* Make dongle available to driver only now to avoid
+		 * race conditions - Jean II */
+		self->dongle = dongle;
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		if (!capable(CAP_NET_ADMIN))
@@ -1019,20 +1027,26 @@
 	case SIOCSDTRRTS:
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
-		else
+		else {
+			save_flags(flags);
+			cli();
 			irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+			restore_flags(flags);
+		}
 		break;
 	case SIOCSMODE:
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
-		else
+		else {
+			save_flags(flags);
+			cli();
 			irtty_set_mode(dev, irq->ifr_mode);
+			restore_flags(flags);
+		}
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
-	
-	restore_flags(flags);
 	
 	return ret;
 }
diff -Nru a/drivers/net/irda/mcp2120.c b/drivers/net/irda/mcp2120.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/mcp2120.c	Thu May  2 17:22:17 2002
@@ -0,0 +1,252 @@
+/*********************************************************************
+ *            
+ *    
+ * Filename:      mcp2120.c
+ * Version:       1.0
+ * Description:   Implementation for the MCP2120 (Microchip)
+ * Status:        Experimental.
+ * Author:        Felix Tang (tangf@eyetap.org)
+ * Created at:    Sun Mar 31 19:32:12 EST 2002
+ * Based on code by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 2002 Felix Tang, All Rights Reserved.
+ *      
+ *     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/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irda_device.h>
+#include <net/irda/irtty.h>
+
+static int  mcp2120_reset(struct irda_task *task);
+static void mcp2120_open(dongle_t *self, struct qos_info *qos);
+static void mcp2120_close(dongle_t *self);
+static int  mcp2120_change_speed(struct irda_task *task);
+
+#define MCP2120_9600    0x87
+#define MCP2120_19200   0x8B
+#define MCP2120_38400   0x85
+#define MCP2120_57600   0x83
+#define MCP2120_115200  0x81
+
+#define MCP2120_COMMIT  0x11
+
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_MCP2120_DONGLE,
+	mcp2120_open,
+	mcp2120_close,
+	mcp2120_reset,
+	mcp2120_change_speed,
+};
+
+int __init mcp2120_init(void)
+{
+	return irda_device_register_dongle(&dongle);
+}
+
+void mcp2120_cleanup(void)
+{
+	irda_device_unregister_dongle(&dongle);
+}
+
+static void mcp2120_open(dongle_t *self, struct qos_info *qos)
+{
+	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+	qos->min_turn_time.bits = 0x01;
+
+	MOD_INC_USE_COUNT;
+}
+
+static void mcp2120_close(dongle_t *self)
+{
+	/* Power off dongle */
+        /* reset and inhibit mcp2120 */
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
+	//self->set_dtr_rts(self->dev, FALSE, FALSE);
+
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Function mcp2120_change_speed (dev, speed)
+ *
+ *    Set the speed for the MCP2120.
+ *
+ */
+static int mcp2120_change_speed(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	__u32 speed = (__u32) task->param;
+	__u8 control[2];
+	int ret = 0;
+
+	self->speed_task = task;
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		/* Need to reset the dongle and go to 9600 bps before
+                   programming */
+                //printk("Dmcp2120_change_speed irda_task_init\n");
+		if (irda_task_execute(self, mcp2120_reset, NULL, task, 
+				      (void *) speed))
+		{
+			/* Dongle need more time to reset */
+			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
+
+			/* Give reset 1 sec to finish */
+			ret = MSECS_TO_JIFFIES(1000);
+		}
+		break;
+	case IRDA_TASK_CHILD_WAIT:
+		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		ret = -1;
+		break;
+	case IRDA_TASK_CHILD_DONE:
+		/* Set DTR to enter command mode */
+		self->set_dtr_rts(self->dev, TRUE, FALSE);
+                udelay(500);
+
+		switch (speed) {
+		case 9600:
+		default:
+			control[0] = MCP2120_9600;
+                        //printk("mcp2120 9600\n");
+			break;
+		case 19200:
+			control[0] = MCP2120_19200;
+                        //printk("mcp2120 19200\n");
+			break;
+		case 34800:
+			control[0] = MCP2120_38400;
+                        //printk("mcp2120 38400\n");
+			break;
+		case 57600:
+			control[0] = MCP2120_57600;
+                        //printk("mcp2120 57600\n");
+			break;
+		case 115200:
+                        control[0] = MCP2120_115200;
+                        //printk("mcp2120 115200\n");
+			break;
+		}
+	        control[1] = MCP2120_COMMIT;
+	
+		/* Write control bytes */
+                self->write(self->dev, control, 2);
+ 
+                irda_task_next_state(task, IRDA_TASK_WAIT);
+		ret = MSECS_TO_JIFFIES(100);
+                //printk("mcp2120_change_speed irda_child_done\n");
+		break;
+	case IRDA_TASK_WAIT:
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, FALSE, FALSE);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+                //printk("mcp2120_change_speed irda_task_wait\n");
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+/*
+ * Function mcp2120_reset (driver)
+ *
+ *      This function resets the mcp2120 dongle.
+ *      
+ *      Info: -set RTS to reset mcp2120
+ *            -set DTR to set mcp2120 software command mode
+ *            -mcp2120 defaults to 9600 baud after reset
+ *
+ *      Algorithm:
+ *      0. Set RTS to reset mcp2120.
+ *      1. Clear RTS and wait for device reset timer of 30 ms (max).
+ *      
+ */
+
+
+static int mcp2120_reset(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	int ret = 0;
+
+	self->reset_task = task;
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+                //printk("mcp2120_reset irda_task_init\n");
+		/* Reset dongle by setting RTS*/
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+		irda_task_next_state(task, IRDA_TASK_WAIT1);
+		ret = MSECS_TO_JIFFIES(50);
+		break;
+	case IRDA_TASK_WAIT1:
+                //printk("mcp2120_reset irda_task_wait1\n");
+                /* clear RTS and wait for at least 30 ms. */
+		self->set_dtr_rts(self->dev, FALSE, FALSE);
+		irda_task_next_state(task, IRDA_TASK_WAIT2);
+		ret = MSECS_TO_JIFFIES(50);
+		break;
+	case IRDA_TASK_WAIT2:
+                //printk("mcp2120_reset irda_task_wait2\n");
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, FALSE, FALSE);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>");
+MODULE_DESCRIPTION("Microchip MCP2120");
+MODULE_LICENSE("GPL");
+
+	
+/*
+ * Function init_module (void)
+ *
+ *    Initialize MCP2120 module
+ *
+ */
+int init_module(void)
+{
+	return mcp2120_init();
+}
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    Cleanup MCP2120 module
+ *
+ */
+void cleanup_module(void)
+{
+        mcp2120_cleanup();
+}
+#endif /* MODULE */
diff -Nru a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
--- a/drivers/net/isa-skeleton.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/isa-skeleton.c	Thu May  2 17:22:16 2002
@@ -202,10 +202,10 @@
 	if (dev->irq == -1)
 		;	/* Do nothing: a user-level program will set it. */
 	else if (dev->irq < 2) {	/* "Auto-IRQ" */
-		autoirq_setup(0);
+		unsigned long irq_mask = probe_irq_on();
 		/* Trigger an interrupt here. */
 
-		dev->irq = autoirq_report(0);
+		dev->irq = probe_irq_off(irq_mask);
 		if (net_debug >= 2)
 			printk(" autoirq is %d", dev->irq);
 	} else if (dev->irq == 2)
diff -Nru a/drivers/net/lance.c b/drivers/net/lance.c
--- a/drivers/net/lance.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/lance.c	Thu May  2 17:22:16 2002
@@ -545,15 +545,19 @@
 	if (dev->irq >= 2)
 		printk(" assigned IRQ %d", dev->irq);
 	else if (lance_version != 0)  {	/* 7990 boards need DMA detection first. */
+		unsigned long irq_mask, delay;
+
 		/* To auto-IRQ we enable the initialization-done and DMA error
 		   interrupts. For ISA boards we get a DMA error, but VLB and PCI
 		   boards will work. */
-		autoirq_setup(0);
+		irq_mask = probe_irq_on();
 
 		/* Trigger an initialization just for the interrupt. */
 		outw(0x0041, ioaddr+LANCE_DATA);
 
-		dev->irq = autoirq_report(2);
+		delay = jiffies + HZ/50;
+		while (time_before(jiffies, delay)) ;
+		dev->irq = probe_irq_off(irq_mask);
 		if (dev->irq)
 			printk(", probed IRQ %d", dev->irq);
 		else {
@@ -619,10 +623,14 @@
 	if (lance_version == 0 && dev->irq == 0) {
 		/* We may auto-IRQ now that we have a DMA channel. */
 		/* Trigger an initialization just for the interrupt. */
-		autoirq_setup(0);
+		unsigned long irq_mask, delay;
+
+		irq_mask = probe_irq_on();
 		outw(0x0041, ioaddr+LANCE_DATA);
 
-		dev->irq = autoirq_report(4);
+		delay = jiffies + HZ/25;
+		while (time_before(jiffies, delay)) ;
+		dev->irq = probe_irq_off(irq_mask);
 		if (dev->irq == 0) {
 			printk("  Failed to detect the 7990 IRQ line.\n");
 			return -ENODEV;
diff -Nru a/drivers/net/ni5010.c b/drivers/net/ni5010.c
--- a/drivers/net/ni5010.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/ni5010.c	Thu May  2 17:22:17 2002
@@ -254,11 +254,15 @@
 	if (dev->irq == 0xff)
 		;
 	else if (dev->irq < 2) {
+		unsigned long irq_mask, delay;
+
 		PRINTK2((KERN_DEBUG "%s: I/O #5 passed!\n", dev->name));
 
-		autoirq_setup(0);
+		irq_mask = probe_irq_on();
 		trigger_irq(ioaddr);
-		dev->irq = autoirq_report(2);
+		delay = jiffies + HZ/50;
+		while (time_before(jiffies, delay)) ;
+		dev->irq = probe_irq_off(irq_mask);
 
 		PRINTK2((KERN_DEBUG "%s: I/O #6 passed!\n", dev->name));
 
diff -Nru a/drivers/net/ni52.c b/drivers/net/ni52.c
--- a/drivers/net/ni52.c	Thu May  2 17:22:15 2002
+++ b/drivers/net/ni52.c	Thu May  2 17:22:15 2002
@@ -491,10 +491,16 @@
 
 	if(dev->irq < 2)
 	{
-		autoirq_setup(0);
+		unsigned long irq_mask, delay;
+
+		irq_mask = probe_irq_on();
 		ni_reset586();
 		ni_attn586();
-		if(!(dev->irq = autoirq_report(2)))
+
+		delay = jiffies + HZ/50;
+		while (time_before(jiffies, delay)) ;
+		dev->irq = probe_irq_off(irq_mask);
+		if(!dev->irq)
 		{
 			printk("?autoirq, Failed to detect IRQ line!\n");
 			kfree(dev->priv);
diff -Nru a/drivers/net/ni65.c b/drivers/net/ni65.c
--- a/drivers/net/ni65.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/ni65.c	Thu May  2 17:22:16 2002
@@ -447,11 +447,15 @@
 
 		if(dev->irq < 2)
 		{
+			unsigned long irq_mask, delay;
+
 			ni65_init_lance(p,dev->dev_addr,0,0);
-			autoirq_setup(0);
+			irq_mask = probe_irq_on();
 			writereg(CSR0_INIT|CSR0_INEA,CSR0); /* trigger interrupt */
-
-			if(!(dev->irq = autoirq_report(2)))
+			delay = jiffies + HZ/50;
+			while (time_before(jiffies, delay)) ;
+			dev->irq = probe_irq_off(irq_mask);
+			if(!dev->irq)
 			{
 				printk("Failed to detect IRQ line!\n");
 				ni65_free_buffer(p);
diff -Nru a/drivers/net/pcmcia/ax8390.h b/drivers/net/pcmcia/ax8390.h
--- a/drivers/net/pcmcia/ax8390.h	Thu May  2 17:22:17 2002
+++ b/drivers/net/pcmcia/ax8390.h	Thu May  2 17:22:17 2002
@@ -39,12 +39,6 @@
 #define ei_debug 1
 #endif
 
-#ifndef HAVE_AUTOIRQ
-/* From auto_irq.c */
-extern void autoirq_setup(int waittime);
-extern unsigned long autoirq_report(int waittime);
-#endif
-
 static int ethdev_init(struct net_device *dev);
 static void NS8390_init(struct net_device *dev, int startp);
 static int ei_open(struct net_device *dev);
diff -Nru a/drivers/net/rrunner.c b/drivers/net/rrunner.c
--- a/drivers/net/rrunner.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/rrunner.c	Thu May  2 17:22:16 2002
@@ -75,13 +75,13 @@
 #define rr_mark_net_bh(foo) mark_bh(foo)
 #define rr_if_busy(dev)     dev->tbusy
 #define rr_if_running(dev)  dev->start /* Currently unused. */
-#define rr_if_down(dev)     {do{dev->start = 0;}while (0);}
+#define rr_if_down(dev)     do { dev->start = 0; } while (0)
 #else
 #define NET_BH              0
-#define rr_mark_net_bh(foo) {do{} while(0);}
+#define rr_mark_net_bh(foo) do { } while(0)
 #define rr_if_busy(dev)     netif_queue_stopped(dev)
 #define rr_if_running(dev)  netif_running(dev)
-#define rr_if_down(dev)     {do{} while(0);}
+#define rr_if_down(dev)     do { } while(0)
 #endif
 
 #include "rrunner.h"
diff -Nru a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
--- a/drivers/net/sgiseeq.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/sgiseeq.c	Thu May  2 17:22:17 2002
@@ -1,10 +1,10 @@
-/* $Id: sgiseeq.c,v 1.17 2000/03/27 23:02:57 ralf Exp $
- *
+/*
  * sgiseeq.c: Seeq8003 ethernet driver for SGI machines.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  */
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
@@ -450,20 +450,22 @@
 	unsigned long flags;
 	int err;
 
-	save_flags(flags); cli();
-	if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, (void *) dev)) {
+	__save_and_cli(flags);
+
+	err = -EAGAIN;
+	if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) {
 		printk("Seeq8003: Can't get irq %d\n", dev->irq);
-		restore_flags(flags);
-		return -EAGAIN;
+		goto out;
 	}
-
 	err = init_seeq(dev, sp, sregs);
 	if (err)
-		return err;
+		goto out;
 
 	netif_start_queue(dev);
-	restore_flags(flags);
-	return 0;
+
+out:
+	__restore_flags(flags);
+	return err;
 }
 
 static int sgiseeq_close(struct net_device *dev)
diff -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c
--- a/drivers/net/sis900.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/sis900.c	Thu May  2 17:22:16 2002
@@ -1,6 +1,6 @@
 /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
    Copyright 1999 Silicon Integrated System Corporation 
-   Revision:	1.08.02	Jan. 4 2002
+   Revision:	1.08.04	Apr. 25 2002
    
    Modified from the driver which is originally written by Donald Becker.
    
@@ -18,8 +18,9 @@
    preliminary Rev. 1.0 Jan. 18, 1998
    http://www.sis.com.tw/support/databook.htm
 
+   Rev 1.08.04 Apr. 25 2002 Mufasa Yang <mufasa@sis.com.tw> added SiS962 support
+   Rev 1.08.03 Feb. 1 2002 Matt Domsch <Matt_Domsch@dell.com> update to use library crc32 function
    Rev 1.08.02 Nov. 30 2001 Hui-Fen Hsu workaround for EDB & bug fix for dhcp problem
-               Jan.  4 2002 Matt Domsch <Matt_Domsch@dell.com> update to use library crc32 function
    Rev 1.08.01 Aug. 25 2001 Hui-Fen Hsu update for 630ET & workaround for ICS1893 PHY
    Rev 1.08.00 Jun. 11 2001 Hui-Fen Hsu workaround for RTL8201 PHY and some bug fix
    Rev 1.07.11 Apr.  2 2001 Hui-Fen Hsu updates PCI drivers to use the new pci_set_dma_mask for kernel 2.4.3
@@ -60,8 +61,8 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
-#include <linux/crc32.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 
 #include <asm/processor.h>      /* Processor type for cache alignment. */
 #include <asm/bitops.h>
@@ -71,7 +72,7 @@
 #include "sis900.h"
 
 #define SIS900_MODULE_NAME "sis900"
-#define SIS900_DRV_VERSION "v1.08.02 1/4/2002"
+#define SIS900_DRV_VERSION "v1.08.04 4/25/2002"
 
 static char version[] __devinitdata =
 KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n";
@@ -307,6 +308,40 @@
 	return 1;
 }
 
+/**
+ *	sis962_get_mac_addr: - Get MAC address for SiS962 model
+ *	@pci_dev: the sis900 pci device
+ *	@net_dev: the net device to get address for 
+ *
+ *	SiS962 model, use EEPROM to store MAC address. And EEPROM is shared by
+ *	LAN and 1394. When access EEPROM, send EEREQ signal to hardware first 
+ *	and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access 
+ *	by LAN, otherwise is not. After MAC address is read from EEPROM, send
+ *	EEDONE signal to refuse EEPROM access by LAN. 
+ *	MAC address is read into @net_dev->dev_addr.
+ */
+
+static int __devinit sis962_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
+{
+	long ioaddr = net_dev->base_addr;
+	long ee_addr = ioaddr + mear;
+	u32 waittime = 0;
+	int ret = 0;
+	
+	outl(EEREQ, ee_addr);
+	while(waittime < 2000) {
+		if(inl(ee_addr) & EEGNT) {
+			ret = sis900_get_mac_addr(pci_dev, net_dev);
+			outl(EEDONE, ee_addr);
+			return(ret);
+		} else {
+			udelay(1);	
+			waittime ++;
+		}
+	}
+	outl(EEDONE, ee_addr);
+	return 0;
+}
 
 /**
  *	sis900_probe: - Probe for sis900 device
@@ -408,6 +443,8 @@
 		ret = sis630e_get_mac_addr(pci_dev, net_dev);
 	else if ((revision > 0x81) && (revision <= 0x90) )
 		ret = sis635_get_mac_addr(pci_dev, net_dev);
+	else if (revision == SIS962_900_REV)
+		ret = sis962_get_mac_addr(pci_dev, net_dev);
 	else
 		ret = sis900_get_mac_addr(pci_dev, net_dev);
 
@@ -1983,7 +2020,7 @@
 	u32 crc = ether_crc(6, addr);
 
 	/* leave 8 or 7 most siginifant bits */
-	if ((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV))
+	if ((revision >= SIS635A_900_REV) || (revision == SIS900B_900_REV))
 		return ((int)(crc >> 24));
 	else
 		return ((int)(crc >> 25));
@@ -2009,7 +2046,7 @@
 
 	/* 635 Hash Table entires = 256(2^16) */
 	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
-	if((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV))
+	if((revision >= SIS635A_900_REV) || (revision == SIS900B_900_REV))
 		table_entries = 16;
 	else
 		table_entries = 8;
@@ -2090,7 +2127,7 @@
 	}
 
 	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
-	if( (revision == SIS635A_900_REV) || (revision == SIS900B_900_REV) )
+	if( (revision >= SIS635A_900_REV) || (revision == SIS900B_900_REV) )
 		outl(PESEL | RND_CNT, ioaddr + cfg);
 	else
 		outl(PESEL, ioaddr + cfg);
diff -Nru a/drivers/net/sis900.h b/drivers/net/sis900.h
--- a/drivers/net/sis900.h	Thu May  2 17:22:16 2002
+++ b/drivers/net/sis900.h	Thu May  2 17:22:16 2002
@@ -135,6 +135,11 @@
 	EEaddrMask = 0x013F, EEcmdShift = 16
 };
 
+/* For SiS962, request the eeprom software access */
+enum sis962_eeprom_command {
+	EEREQ = 0x00000400, EEDONE = 0x00000200, EEGNT = 0x00000100
+};
+
 /* Manamgement Data I/O (mdio) frame */
 #define MIIread         0x6000
 #define MIIwrite        0x5002
@@ -240,7 +245,7 @@
 	SIS630A_900_REV = 0x80,		SIS630E_900_REV = 0x81,
 	SIS630S_900_REV = 0x82,		SIS630EA1_900_REV = 0x83,
 	SIS630ET_900_REV = 0x84,	SIS635A_900_REV = 0x90,
-	SIS900B_900_REV = 0x03
+	SIS962_900_REV = 0X91,		SIS900B_900_REV = 0x03
 };
 
 enum sis630_revision_id {
diff -Nru a/drivers/net/smc9194.c b/drivers/net/smc9194.c
--- a/drivers/net/smc9194.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/smc9194.c	Thu May  2 17:22:16 2002
@@ -751,15 +751,15 @@
 		timeout--;
 	}
 	/* there is really nothing that I can do here if timeout fails,
-	   as autoirq_report will return a 0 anyway, which is what I
+	   as probe_irq_off will return a 0 anyway, which is what I
 	   want in this case.   Plus, the clean up is needed in both
 	   cases.  */
 
 	/* DELAY HERE!
 	   On a fast machine, the status might change before the interrupt
 	   is given to the processor.  This means that the interrupt was
-	   never detected, and autoirq_report fails to report anything.
-	   This should fix autoirq_* problems.
+	   never detected, and probe_irq_off fails to report anything.
+	   This should fix probe_irq_* problems.
 	*/
 	SMC_DELAY();
 	SMC_DELAY();
diff -Nru a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
--- a/drivers/net/sun3lance.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/sun3lance.c	Thu May  2 17:22:16 2002
@@ -21,7 +21,7 @@
   
 */
 
-static char *version = "sun3lance.c: v1.1 11/17/1999  Sam Creasey (sammy@oh.verio.com)\n";
+static char *version = "sun3lance.c: v1.2 1/12/2001  Sam Creasey (sammy@sammy.net)\n";
 
 #include <linux/module.h>
 
@@ -35,16 +35,24 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/delay.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
 
 #include <asm/bitops.h>
 #include <asm/io.h>
-#include <asm/idprom.h>
 #include <asm/pgtable.h>
-#include <asm/sun3mmu.h>
+#include <asm/pgalloc.h>
 #include <asm/dvma.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+
+#ifdef CONFIG_SUN3
+#include <asm/sun3mmu.h>
+#else
+#include <asm/sun3xprom.h>
+#endif
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -62,7 +70,7 @@
  *  3 = debug, print even more debug infos (packet data)
  */
 
-#define	LANCE_DEBUG	1
+#define	LANCE_DEBUG	0
 
 #ifdef LANCE_DEBUG
 static int lance_debug = LANCE_DEBUG;
@@ -139,7 +147,7 @@
 	struct lance_tx_head	tx_head[TX_RING_SIZE];
 	struct lance_rx_head	rx_head[RX_RING_SIZE];
 	char   rx_data[RX_RING_SIZE][PKT_BUF_SZ];
-	char   tx_data[RX_RING_SIZE][PKT_BUF_SZ];
+	char   tx_data[TX_RING_SIZE][PKT_BUF_SZ];
 };
 
 /* The driver's private device structure */
@@ -151,8 +159,8 @@
 	int old_tx, old_rx;     /* ring entry to be processed */
 	struct net_device_stats stats;
 /* These two must be longs for set_bit() */
-	long					tx_full;
-	long					lock;
+	long	    tx_full;
+	long	    lock;
 };
 
 /* I/O register access macros */
@@ -247,15 +255,27 @@
 {	
 	static int found;
 
+	/* check that this machine has an onboard lance */
+	switch(idprom->id_machtype) {
+	case SM_SUN3|SM_3_50:
+	case SM_SUN3|SM_3_60:
+	case SM_SUN3X|SM_3_80:
+		/* these machines have lance */
+		break;
+
+	default:
+		return(-ENODEV);
+	}
+
 	if(found)
-		return(ENODEV);
+		return(-ENODEV);
 
 	if (lance_probe(dev)) {
 			found = 1;
 			return( 0 );
 	}
 
-	return( ENODEV );
+	return( -ENODEV );
 }
 
 static int __init lance_probe( struct net_device *dev)
@@ -269,6 +289,7 @@
 	volatile unsigned short *ioaddr_probe;
 	unsigned short tmp1, tmp2;
 
+#ifdef CONFIG_SUN3
 	/* LANCE_OBIO can be found within the IO pmeg with some effort */
 	for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 +
 	    SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) {
@@ -286,6 +307,9 @@
 	
 	if(!found)
 		return 0;
+#else
+	ioaddr = SUN3X_LANCE;
+#endif
 
 	/* test to see if there's really a lance here */
 	/* (CSRO_INIT shouldn't be readable) */
@@ -311,8 +335,9 @@
 			return 0;
 	}
 	lp = (struct lance_private *)dev->priv;
-	MEM = (struct lance_memory *)sun3_dvma_malloc(sizeof(struct
-							     lance_memory)); 
+
+	MEM = dvma_malloc_align(sizeof(struct lance_memory), 0x10000);
+
 	lp->iobase = (volatile unsigned short *)ioaddr;
 	dev->base_addr = (unsigned long)ioaddr; /* informational only */
 
@@ -331,7 +356,7 @@
 	/* copy in the ethernet address from the prom */
 	for(i = 0; i < 6 ; i++)
 	     dev->dev_addr[i] = idprom->id_ethaddr[i];
-	
+
 	/* tell the card it's ether address, bytes swapped */
 	MEM->init.hwaddr[0] = dev->dev_addr[1];
 	MEM->init.hwaddr[1] = dev->dev_addr[0];
@@ -346,20 +371,19 @@
 	MEM->init.mode = 0x0000;
 	MEM->init.filter[0] = 0x00000000;
 	MEM->init.filter[1] = 0x00000000;
-	MEM->init.rdra = sun3_dvma_vtop(MEM->rx_head);
+	MEM->init.rdra = dvma_vtob(MEM->rx_head);
 	MEM->init.rlen    = (RX_LOG_RING_SIZE << 13) |
-		(sun3_dvma_vtop(MEM->rx_head) >> 16);
-	MEM->init.tdra = sun3_dvma_vtop(MEM->tx_head);
+		(dvma_vtob(MEM->rx_head) >> 16);
+	MEM->init.tdra = dvma_vtob(MEM->tx_head);
 	MEM->init.tlen    = (TX_LOG_RING_SIZE << 13) |
-		(sun3_dvma_vtop(MEM->tx_head) >> 16);
+		(dvma_vtob(MEM->tx_head) >> 16);
 
 	DPRINTK(2, ("initaddr: %08lx rx_ring: %08lx tx_ring: %08lx\n",
-	       sun3_dvma_vtop(&(MEM->init)), sun3_dvma_vtop(MEM->rx_head),
-	       (sun3_dvma_vtop(MEM->tx_head))));  
-
+	       dvma_vtob(&(MEM->init)), dvma_vtob(MEM->rx_head),
+	       (dvma_vtob(MEM->tx_head))));  
 
 	if (did_version++ == 0)
-		DPRINTK( 1, ( version ));
+		printk( version );
 
 	/* The LANCE-specific entries in the device structure. */
 	dev->open = &lance_open;
@@ -386,16 +410,8 @@
 
 	REGA(CSR0) = CSR0_STOP;
 
-	/* tell the lance the address of its init block */
-	REGA(CSR1) = sun3_dvma_vtop(&(MEM->init));
-	REGA(CSR2) = sun3_dvma_vtop(&(MEM->init)) >> 16;
-
 	lance_init_ring(dev);
 
-	/* Re-initialize the LANCE, and start it when done. */
-
-	REGA(CSR3) = CSR3_BSWP;
-
 	/* From now on, AREG is kept to point to CSR0 */
 	REGA(CSR0) = CSR0_INIT;
 
@@ -434,23 +450,52 @@
 	lp->old_rx = lp->old_tx = 0;
 
 	for( i = 0; i < TX_RING_SIZE; i++ ) {
-		MEM->tx_head[i].base = sun3_dvma_vtop(MEM->tx_data[i]);
+		MEM->tx_head[i].base = dvma_vtob(MEM->tx_data[i]);
 		MEM->tx_head[i].flag = 0;
  		MEM->tx_head[i].base_hi = 
-			(sun3_dvma_vtop(MEM->tx_data[i])) >>16;
+			(dvma_vtob(MEM->tx_data[i])) >>16;
 		MEM->tx_head[i].length = 0;
 		MEM->tx_head[i].misc = 0;
 	}
 
 	for( i = 0; i < RX_RING_SIZE; i++ ) {
-		MEM->rx_head[i].base = sun3_dvma_vtop(MEM->rx_data[i]);
-		MEM->rx_head[i].flag = TMD1_OWN_CHIP;
+		MEM->rx_head[i].base = dvma_vtob(MEM->rx_data[i]);
+		MEM->rx_head[i].flag = RMD1_OWN_CHIP;
 		MEM->rx_head[i].base_hi = 
-			(sun3_dvma_vtop(MEM->rx_data[i])) >> 16;
+			(dvma_vtob(MEM->rx_data[i])) >> 16;
 		MEM->rx_head[i].buf_length = -PKT_BUF_SZ | 0xf000;
 		MEM->rx_head[i].msg_length = 0;
 	}
 
+	/* tell the card it's ether address, bytes swapped */
+	MEM->init.hwaddr[0] = dev->dev_addr[1];
+	MEM->init.hwaddr[1] = dev->dev_addr[0];
+	MEM->init.hwaddr[2] = dev->dev_addr[3];
+	MEM->init.hwaddr[3] = dev->dev_addr[2];
+	MEM->init.hwaddr[4] = dev->dev_addr[5];
+	MEM->init.hwaddr[5] = dev->dev_addr[4];
+
+	MEM->init.mode = 0x0000;
+	MEM->init.filter[0] = 0x00000000;
+	MEM->init.filter[1] = 0x00000000;
+	MEM->init.rdra = dvma_vtob(MEM->rx_head);
+	MEM->init.rlen    = (RX_LOG_RING_SIZE << 13) |
+		(dvma_vtob(MEM->rx_head) >> 16);
+	MEM->init.tdra = dvma_vtob(MEM->tx_head);
+	MEM->init.tlen    = (TX_LOG_RING_SIZE << 13) |
+		(dvma_vtob(MEM->tx_head) >> 16);
+
+
+	/* tell the lance the address of its init block */
+	REGA(CSR1) = dvma_vtob(&(MEM->init));
+	REGA(CSR2) = dvma_vtob(&(MEM->init)) >> 16;
+
+#ifdef CONFIG_SUN3X
+	REGA(CSR3) = CSR3_BSWP | CSR3_ACON | CSR3_BCON;
+#else
+	REGA(CSR3) = CSR3_BSWP;
+#endif
+
 }
 
 
@@ -512,7 +557,7 @@
 	   stopping the queue for a bit... */
      
 	netif_stop_queue(dev);
-
+	
 	if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
 		printk( "%s: tx queue lock!.\n", dev->name);
 		/* don't clear dev->tbusy flag. */
@@ -520,13 +565,22 @@
 	}
 
 	AREG = CSR0;
-//	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
-//				  dev->name, DREG ));
-	
+  	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
+  				  dev->name, DREG ));
+
+#ifdef CONFIG_SUN3X
+	/* this weirdness doesn't appear on sun3... */
+	if(!(DREG & CSR0_INIT)) {
+		DPRINTK( 1, ("INIT not set, reinitializing...\n"));
+		REGA( CSR0 ) = CSR0_STOP;
+		lance_init_ring(dev);
+		REGA( CSR0 ) = CSR0_INIT | CSR0_STRT;
+	}
+#endif
 
 	/* Fill in a Tx ring entry */
 #if 0
-	if (lance_debug >= 3) {
+	if (lance_debug >= 2) {
 		u_char *p;
 		int i;
 		printk( "%s: TX pkt %d type 0x%04x from ", dev->name,
@@ -566,7 +620,10 @@
 	lp->stats.tx_bytes += skb->len;
 
 	/* Trigger an immediate send poll. */
-	REGA(CSR0) = CSR0_INEA | CSR0_TDMD;
+	REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT;
+	AREG = CSR0;
+  	DPRINTK( 2, ( "%s: lance_start_xmit() exiting, csr0 %4.4x.\n",
+  				  dev->name, DREG ));
 	dev->trans_start = jiffies;
 	dev_kfree_skb( skb );
 
@@ -597,14 +654,15 @@
 	if (in_interrupt)
 		DPRINTK( 2, ( "%s: Re-entering the interrupt handler.\n", dev->name ));
 	in_interrupt = 1;
-
+	
  still_more:
-
+	flush_cache_all();
+	
 	AREG = CSR0;
 	csr0 = DREG;
 
 	/* ack interrupts */
-	DREG = csr0 & (CSR0_TINT | CSR0_RINT);
+	DREG = csr0 & (CSR0_TINT | CSR0_RINT | CSR0_IDON);
 
 	/* clear errors */
 	if(csr0 & CSR0_ERR)
diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c
--- a/drivers/net/sungem.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/sungem.c	Thu May  2 17:22:17 2002
@@ -2126,9 +2126,9 @@
 	 */
 	if (restart_link)
 		gem_init_phy(gp);
+	gem_init_pause_thresholds(gp);
 	gem_init_dma(gp);
 	gem_init_mac(gp);
-	gem_init_pause_thresholds(gp);
 
 	if (restart_link) {
 		/* Default aneg parameters */
@@ -2823,7 +2823,7 @@
 	dev_addr[0] = 0x08;
 	dev_addr[1] = 0x00;
 	dev_addr[2] = 0x20;
-	get_random_bytes(dev_addr, 3);
+	get_random_bytes(dev_addr + 3, 3);
 	return;
 }
 #endif /* not Sparc and not PPC */
diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/tg3.c	Thu May  2 17:22:17 2002
@@ -52,8 +52,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"0.96"
-#define DRV_MODULE_RELDATE	"Mar 6, 2002"
+#define DRV_MODULE_VERSION	"0.98"
+#define DRV_MODULE_RELDATE	"Mar 28, 2002"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -3206,12 +3206,19 @@
 	/* Now startup only the RX cpu. */
 	tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
 	tw32(RX_CPU_BASE + CPU_PC,    TG3_FW_TEXT_ADDR);
+
+	/* Flush posted writes. */
+	tr32(RX_CPU_BASE + CPU_PC);
 	for (i = 0; i < 5; i++) {
 		if (tr32(RX_CPU_BASE + CPU_PC) == TG3_FW_TEXT_ADDR)
 			break;
 		tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
 		tw32(RX_CPU_BASE + CPU_MODE,  CPU_MODE_HALT);
 		tw32(RX_CPU_BASE + CPU_PC,    TG3_FW_TEXT_ADDR);
+
+		/* Flush posted writes. */
+		tr32(RX_CPU_BASE + CPU_PC);
+
 		udelay(1000);
 	}
 	if (i >= 5) {
@@ -3223,6 +3230,9 @@
 	}
 	tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
 	tw32(RX_CPU_BASE + CPU_MODE,  0x00000000);
+
+	/* Flush posted writes. */
+	tr32(RX_CPU_BASE + CPU_MODE);
 
 	return 0;
 }
diff -Nru a/drivers/net/tlan.c b/drivers/net/tlan.c
--- a/drivers/net/tlan.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/tlan.c	Thu May  2 17:22:16 2002
@@ -8,6 +8,7 @@
  *  (C) 1997-1998 Caldera, Inc.
  *  (C) 1998 James Banks
  *  (C) 1999-2001 Torben Mathiasen
+ *  (C) 2002 Samuel Chessman
  *
  *  This software may be used and distributed according to the terms
  *  of the GNU General Public License, incorporated herein by reference.
@@ -158,6 +159,11 @@
  *
  * 	v1.14a Jan 6, 2001   - Minor adjustments (spinlocks, etc.)
  *
+ *	Samuel Chessman <chessman@tux.org> New Maintainer!
+ *
+ *	v1.15 Apr 4, 2002    - Correct operation when aui=1 to be
+ *	                       10T half duplex no loopback
+ *	                       Thanks to Gunnar Eikman
  *******************************************************************************/
 
 #error Please convert me to Documentation/DMA-mapping.txt
@@ -189,7 +195,7 @@
 static  int speed[MAX_TLAN_BOARDS];
 static  int boards_found;
 
-MODULE_AUTHOR("Maintainer: Torben Mathiasen <torben.mathiasen@compaq.com>");
+MODULE_AUTHOR("Maintainer: Samuel Chessman <chessman@tux.org>");
 MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters");
 MODULE_LICENSE("GPL");
 
@@ -214,7 +220,7 @@
 static	int		bbuf;
 static	u8		*TLanPadBuffer;
 static	char		TLanSignature[] = "TLAN";
-static const char tlan_banner[] = "ThunderLAN driver v1.14a\n";
+static const char tlan_banner[] = "ThunderLAN driver v1.15\n";
 static int tlan_have_pci;
 static int tlan_have_eisa;
 
@@ -2601,12 +2607,12 @@
 		TLan_SetTimer( dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN );
 		return;
 	}  else if ( priv->phyNum == 0 ) {
+		control = 0;
         	TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tctl );
 		if ( priv->aui ) {
                 	tctl |= TLAN_TC_AUISEL;
 		} else { 
                 	tctl &= ~TLAN_TC_AUISEL;
-			control = 0;
 			if ( priv->duplex == TLAN_DUPLEX_FULL ) {
 				control |= MII_GC_DUPLEX;
 				priv->tlanFullDuplex = TRUE;
@@ -2614,8 +2620,8 @@
 			if ( priv->speed == TLAN_SPEED_100 ) {
 				control |= MII_GC_SPEEDSEL;
 			}
-       			TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, control );
 		}
+		TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, control );
         	TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tctl );
 	}
 
diff -Nru a/drivers/net/wan/Config.help b/drivers/net/wan/Config.help
--- a/drivers/net/wan/Config.help	Thu May  2 17:22:15 2002
+++ b/drivers/net/wan/Config.help	Thu May  2 17:22:15 2002
@@ -398,6 +398,37 @@
 
   If unsure, say N here.
 
+CONFIG_COMX_HW_MUNICH
+  Hardware driver for the 'SliceCOM' (channelized E1) and 'PciCOM'
+  boards (X21) from the MultiGate family.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called comx-hw-munich.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
+
+  Read linux/Documentation/networking/slicecom.txt for help on
+  configuring and using SliceCOM interfaces. Further info on these cards
+  can be found at http://www.itc.hu or <info@itc.hu>.
+
+CONFIG_HDLC_RAW
+  Say Y to this option if you want generic HDLC driver to support
+  raw HDLC over WAN (Wide Area Network) connections.
+
+  If unsure, say N here.
+
+CONFIG_HDLC_CISCO
+  Say Y to this option if you want generic HDLC driver to support
+  Cisco HDLC over WAN (Wide Area Network) connections.
+
+  If unsure, say N here.
+
+CONFIG_HDLC_FR
+  Say Y to this option if you want generic HDLC driver to support
+  Frame-Relay protocol over WAN (Wide Area Network) connections.
+
+  If unsure, say N here.
+
 CONFIG_HDLC_PPP
   Say Y to this option if you want generic HDLC driver to support
   PPP over WAN (Wide Area Network) connections.
@@ -425,4 +456,26 @@
   say Y here and see <http://hq.pm.waw.pl/pub/hdlc/>
 
   If unsure, say N here.
+
+Cyclades-PC300 support
+CONFIG_PC300
+  This is a driver for the Cyclades-PC300 synchronous communication
+  boards. These boards provide synchronous serial interfaces to your
+  Linux box (interfaces currently available are RS-232/V.35, X.21 and
+  T1/E1). If you wish to support Multilink PPP, please select the
+  option below this one and read the file README.mlppp provided by PC300
+  package.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called pc300.o.
+
+  If you haven't heard about it, it's safe to say N.
+
+Cyclades-PC300 Sync TTY (to MLPPP) support
+CONFIG_PC300_MLPPP
+  Say 'Y' to this option if you are planning to use Multilink PPP over the
+  PC300 synchronous communication boards.
+
 
diff -Nru a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in
--- a/drivers/net/wan/Config.in	Thu May  2 17:22:16 2002
+++ b/drivers/net/wan/Config.in	Thu May  2 17:22:16 2002
@@ -66,6 +66,17 @@
       else
 	 comment '    X.25/LAPB support is disabled'
       fi
+
+      dep_tristate '    Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)' CONFIG_PC300 $CONFIG_HDLC $CONFIG_PCI
+      if [ "$CONFIG_PC300" != "n" ]; then
+            if [ "$CONFIG_PPP" != "n" -a "$CONFIG_PPP_MULTLINK" != "n" -a "$CONFIG_PPP_SYNCTTY" != "n" -a "$CONFIG_HDLC_PPP" = "y" ]; then
+                    bool '      Cyclades-PC300 MLPPP support' CONFIG_PC300_MLPPP
+            else
+                    comment '     Cyclades-PC300 MLPPP support is disabled.'+                       comment '     Refer to the file README.mlppp, provided by PC300 package.'
+            fi
+      fi
+
+
       dep_tristate '    SDL RISCom/N2 support' CONFIG_N2 $CONFIG_HDLC
       dep_tristate '    Moxa C101 support' CONFIG_C101 $CONFIG_HDLC
       dep_tristate '    FarSync T-Series support' CONFIG_FARSYNC $CONFIG_HDLC
diff -Nru a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
--- a/drivers/net/wan/Makefile	Thu May  2 17:22:15 2002
+++ b/drivers/net/wan/Makefile	Thu May  2 17:22:15 2002
@@ -8,7 +8,7 @@
 O_TARGET := wan.o
 
 export-objs :=	z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc_generic.o \
-		dlci.o
+		dlci.o pc300_drv.o
 
 wanpipe-y			:= sdlamain.o sdla_ft1.o
 wanpipe-$(CONFIG_WANPIPE_X25)	+= sdla_x25.o
@@ -30,6 +30,10 @@
 hdlc-$(CONFIG_HDLC_X25)		+= hdlc_x25.o
 hdlc-objs			:= $(hdlc-y)
 
+pc300-y				:= pc300_drv.o
+pc300-$(CONFIG_PC300_MLPPP)	+= pc300_tty.o
+pc300-objs			:= $(pc300-y)
+
 obj-$(CONFIG_HOSTESS_SV11)	+= z85230.o	syncppp.o	hostess_sv11.o
 obj-$(CONFIG_SEALEVEL_4021)	+= z85230.o	syncppp.o	sealevel.o
 obj-$(CONFIG_COMX)		+= 				comx.o
@@ -63,6 +67,7 @@
 obj-$(CONFIG_CYCLADES_SYNC)	+= cycx_drv.o cyclomx.o
 obj-$(CONFIG_LAPBETHER)		+= lapbether.o
 obj-$(CONFIG_SBNI)		+= sbni.o
+obj-$(CONFIG_PC300)		+= pc300.o
 obj-$(CONFIG_HDLC)		+= hdlc.o
 ifeq ($(CONFIG_HDLC_PPP),y)
   obj-$(CONFIG_HDLC)		+= syncppp.o
diff -Nru a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
--- a/drivers/net/wan/dscc4.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/wan/dscc4.c	Thu May  2 17:22:16 2002
@@ -1552,7 +1552,7 @@
 				rx_fd->state1 &= ~Hold;
 				rx_fd->state2 = 0x00000000;
 				rx_fd->end = 0xbabeface;
-			}
+			//}
 			goto try;
 		}
 		if (state & Fi) {
diff -Nru a/drivers/net/wan/hd64572.h b/drivers/net/wan/hd64572.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wan/hd64572.h	Thu May  2 17:22:17 2002
@@ -0,0 +1,443 @@
+/*
+ * hd64572.h	Description of the Hitachi HD64572 (SCA-II), valid for 
+ * 		CPU modes 0 & 2.
+ *
+ * Author:	Ivan Passos <ivan@cyclades.com>
+ *
+ * Copyright:   (c) 2000-2001 Cyclades Corp.
+ *
+ *	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.
+ *
+ * $Log: hd64572.h,v $
+ * Revision 3.1  2001/06/15 12:41:10  regina
+ * upping major version number
+ *
+ * Revision 1.1.1.1  2001/06/13 20:24:49  daniela
+ * PC300 initial CVS version (3.4.0-pre1)
+ *
+ * Revision 1.0 2000/01/25 ivan
+ * Initial version.
+ *
+ */
+
+#ifndef _HD64572_H
+#define _HD64572_H
+
+/* Illegal Access Register */
+#define	ILAR	0x00
+
+/* Wait Controller Registers */
+#define PABR0L	0x20	/* Physical Addr Boundary Register 0 L */
+#define PABR0H	0x21	/* Physical Addr Boundary Register 0 H */
+#define PABR1L	0x22	/* Physical Addr Boundary Register 1 L */
+#define PABR1H	0x23	/* Physical Addr Boundary Register 1 H */
+#define WCRL	0x24	/* Wait Control Register L */
+#define WCRM	0x25	/* Wait Control Register M */
+#define WCRH	0x26	/* Wait Control Register H */
+
+/* Interrupt Registers */
+#define IVR	0x60	/* Interrupt Vector Register */
+#define IMVR	0x64	/* Interrupt Modified Vector Register */
+#define ITCR	0x68	/* Interrupt Control Register */
+#define ISR0	0x6c	/* Interrupt Status Register 0 */
+#define ISR1	0x70	/* Interrupt Status Register 1 */
+#define IER0	0x74	/* Interrupt Enable Register 0 */
+#define IER1	0x78	/* Interrupt Enable Register 1 */
+
+/* Register Access Macros (chan is 0 or 1 in _any_ case) */
+#define	M_REG(reg, chan)	(reg + 0x80*chan)		/* MSCI */
+#define	DRX_REG(reg, chan)	(reg + 0x40*chan)		/* DMA Rx */
+#define	DTX_REG(reg, chan)	(reg + 0x20*(2*chan + 1))	/* DMA Tx */
+#define	TRX_REG(reg, chan)	(reg + 0x20*chan)		/* Timer Rx */
+#define	TTX_REG(reg, chan)	(reg + 0x10*(2*chan + 1))	/* Timer Tx */
+#define	ST_REG(reg, chan)	(reg + 0x80*chan)		/* Status Cnt */
+#define IR0_DRX(val, chan)	((val)<<(8*(chan)))		/* Int DMA Rx */
+#define IR0_DTX(val, chan)	((val)<<(4*(2*chan + 1)))	/* Int DMA Tx */
+#define IR0_M(val, chan)	((val)<<(8*(chan)))		/* Int MSCI */
+
+/* MSCI Channel Registers */
+#define MD0	0x138	/* Mode reg 0 */
+#define MD1	0x139	/* Mode reg 1 */
+#define MD2	0x13a	/* Mode reg 2 */
+#define MD3	0x13b	/* Mode reg 3 */
+#define CTL	0x130	/* Control reg */
+#define RXS	0x13c	/* RX clock source */
+#define TXS	0x13d	/* TX clock source */
+#define EXS	0x13e	/* External clock input selection */
+#define TMCT	0x144	/* Time constant (Tx) */
+#define TMCR	0x145	/* Time constant (Rx) */
+#define CMD	0x128	/* Command reg */
+#define ST0	0x118	/* Status reg 0 */
+#define ST1	0x119	/* Status reg 1 */
+#define ST2	0x11a	/* Status reg 2 */
+#define ST3	0x11b	/* Status reg 3 */
+#define ST4	0x11c	/* Status reg 4 */
+#define FST	0x11d	/* frame Status reg  */
+#define IE0	0x120	/* Interrupt enable reg 0 */
+#define IE1	0x121	/* Interrupt enable reg 1 */
+#define IE2	0x122	/* Interrupt enable reg 2 */
+#define IE4	0x124	/* Interrupt enable reg 4 */
+#define FIE	0x125	/* Frame Interrupt enable reg  */
+#define SA0	0x140	/* Syn Address reg 0 */
+#define SA1	0x141	/* Syn Address reg 1 */
+#define IDL	0x142	/* Idle register */
+#define TRBL	0x100	/* TX/RX buffer reg L */ 
+#define TRBK	0x101	/* TX/RX buffer reg K */ 
+#define TRBJ	0x102	/* TX/RX buffer reg J */ 
+#define TRBH	0x103	/* TX/RX buffer reg H */ 
+#define TRC0	0x148	/* TX Ready control reg 0 */ 
+#define TRC1	0x149	/* TX Ready control reg 1 */ 
+#define RRC	0x14a	/* RX Ready control reg */ 
+#define CST0	0x108	/* Current Status Register 0 */ 
+#define CST1	0x109	/* Current Status Register 1 */ 
+#define CST2	0x10a	/* Current Status Register 2 */ 
+#define CST3	0x10b	/* Current Status Register 3 */ 
+#define GPO	0x131	/* General Purpose Output Pin Ctl Reg */
+#define TFS	0x14b	/* Tx Start Threshold Ctl Reg */
+#define TFN	0x143	/* Inter-transmit-frame Time Fill Ctl Reg */
+#define TBN	0x110	/* Tx Buffer Number Reg */
+#define RBN	0x111	/* Rx Buffer Number Reg */
+#define TNR0	0x150	/* Tx DMA Request Ctl Reg 0 */
+#define TNR1	0x151	/* Tx DMA Request Ctl Reg 1 */
+#define TCR	0x152	/* Tx DMA Critical Request Reg */
+#define RNR	0x154	/* Rx DMA Request Ctl Reg */
+#define RCR	0x156	/* Rx DMA Critical Request Reg */
+
+/* Timer Registers */
+#define TCNTL	0x200	/* Timer Upcounter L */
+#define TCNTH	0x201	/* Timer Upcounter H */
+#define TCONRL	0x204	/* Timer Constant Register L */
+#define TCONRH	0x205	/* Timer Constant Register H */
+#define TCSR	0x206	/* Timer Control/Status Register */
+#define TEPR	0x207	/* Timer Expand Prescale Register */
+
+/* DMA registers */
+#define PCR		0x40		/* DMA priority control reg */
+#define DRR		0x44		/* DMA reset reg */
+#define DMER		0x07		/* DMA Master Enable reg */
+#define BTCR		0x08		/* Burst Tx Ctl Reg */
+#define BOLR		0x0c		/* Back-off Length Reg */
+#define DSR_RX(chan)	(0x48 + 2*chan)	/* DMA Status Reg (Rx) */
+#define DSR_TX(chan)	(0x49 + 2*chan)	/* DMA Status Reg (Tx) */
+#define DIR_RX(chan)	(0x4c + 2*chan)	/* DMA Interrupt Enable Reg (Rx) */
+#define DIR_TX(chan)	(0x4d + 2*chan)	/* DMA Interrupt Enable Reg (Tx) */
+#define FCT_RX(chan)	(0x50 + 2*chan)	/* Frame End Interrupt Counter (Rx) */
+#define FCT_TX(chan)	(0x51 + 2*chan)	/* Frame End Interrupt Counter (Tx) */
+#define DMR_RX(chan)	(0x54 + 2*chan)	/* DMA Mode Reg (Rx) */
+#define DMR_TX(chan)	(0x55 + 2*chan)	/* DMA Mode Reg (Tx) */
+#define DCR_RX(chan)	(0x58 + 2*chan)	/* DMA Command Reg (Rx) */
+#define DCR_TX(chan)	(0x59 + 2*chan)	/* DMA Command Reg (Tx) */
+
+/* DMA Channel Registers */
+#define DARL	0x80	/* Dest Addr Register L (single-block, RX only) */
+#define DARH	0x81	/* Dest Addr Register H (single-block, RX only) */
+#define DARB	0x82	/* Dest Addr Register B (single-block, RX only) */
+#define DARBH	0x83	/* Dest Addr Register BH (single-block, RX only) */
+#define SARL	0x80	/* Source Addr Register L (single-block, TX only) */
+#define SARH	0x81	/* Source Addr Register H (single-block, TX only) */
+#define SARB	0x82	/* Source Addr Register B (single-block, TX only) */
+#define DARBH	0x83	/* Source Addr Register BH (single-block, TX only) */
+#define BARL	0x80	/* Buffer Addr Register L (chained-block) */
+#define BARH	0x81	/* Buffer Addr Register H (chained-block) */
+#define BARB	0x82	/* Buffer Addr Register B (chained-block) */
+#define BARBH	0x83	/* Buffer Addr Register BH (chained-block) */
+#define CDAL	0x84	/* Current Descriptor Addr Register L */
+#define CDAH	0x85	/* Current Descriptor Addr Register H */
+#define CDAB	0x86	/* Current Descriptor Addr Register B */
+#define CDABH	0x87	/* Current Descriptor Addr Register BH */
+#define EDAL	0x88	/* Error Descriptor Addr Register L */
+#define EDAH	0x89	/* Error Descriptor Addr Register H */
+#define EDAB	0x8a	/* Error Descriptor Addr Register B */
+#define EDABH	0x8b	/* Error Descriptor Addr Register BH */
+#define BFLL	0x90	/* RX Buffer Length L (only RX) */
+#define BFLH	0x91	/* RX Buffer Length H (only RX) */
+#define BCRL	0x8c	/* Byte Count Register L */
+#define BCRH	0x8d	/* Byte Count Register H */
+
+/* Block Descriptor Structure */
+typedef struct {
+	unsigned long	next;		/* pointer to next block descriptor */
+	unsigned long	ptbuf;		/* buffer pointer */
+	unsigned short	len;		/* data length */
+	unsigned char	status;		/* status */
+	unsigned char	filler[5];	/* alignment filler (16 bytes) */ 
+} pcsca_bd_t;
+
+/* 
+	Descriptor Status definitions:
+
+	Bit	Transmission	Reception
+
+	7	EOM		EOM
+	6	-		Short Frame
+	5	-		Abort
+	4	-		Residual bit
+	3	Underrun	Overrun	
+	2	-		CRC
+	1	Ownership	Ownership
+	0	EOT		-
+*/
+#define DST_EOT		0x01	/* End of transmit command */
+#define DST_OSB		0x02	/* Ownership bit */
+#define DST_CRC		0x04	/* CRC Error */
+#define DST_OVR		0x08	/* Overrun */
+#define DST_UDR		0x08	/* Underrun */
+#define DST_RBIT	0x10	/* Residual bit */
+#define DST_ABT		0x20	/* Abort */
+#define DST_SHRT	0x40	/* Short Frame  */
+#define DST_EOM		0x80	/* End of Message  */
+
+/* Status Counter Registers */
+#define CMCR	0x158	/* Counter Master Ctl Reg */
+#define TECNTL	0x160	/* Tx EOM Counter L */
+#define TECNTM	0x161	/* Tx EOM Counter M */
+#define TECNTH	0x162	/* Tx EOM Counter H */
+#define TECCR	0x163	/* Tx EOM Counter Ctl Reg */
+#define URCNTL	0x164	/* Underrun Counter L */
+#define URCNTH	0x165	/* Underrun Counter H */
+#define URCCR	0x167	/* Underrun Counter Ctl Reg */
+#define RECNTL	0x168	/* Rx EOM Counter L */
+#define RECNTM	0x169	/* Rx EOM Counter M */
+#define RECNTH	0x16a	/* Rx EOM Counter H */
+#define RECCR	0x16b	/* Rx EOM Counter Ctl Reg */
+#define ORCNTL	0x16c	/* Overrun Counter L */
+#define ORCNTH	0x16d	/* Overrun Counter H */
+#define ORCCR	0x16f	/* Overrun Counter Ctl Reg */
+#define CECNTL	0x170	/* CRC Counter L */
+#define CECNTH	0x171	/* CRC Counter H */
+#define CECCR	0x173	/* CRC Counter Ctl Reg */
+#define ABCNTL	0x174	/* Abort frame Counter L */
+#define ABCNTH	0x175	/* Abort frame Counter H */
+#define ABCCR	0x177	/* Abort frame Counter Ctl Reg */
+#define SHCNTL	0x178	/* Short frame Counter L */
+#define SHCNTH	0x179	/* Short frame Counter H */
+#define SHCCR	0x17b	/* Short frame Counter Ctl Reg */
+#define RSCNTL	0x17c	/* Residual bit Counter L */
+#define RSCNTH	0x17d	/* Residual bit Counter H */
+#define RSCCR	0x17f	/* Residual bit Counter Ctl Reg */
+
+/* Register Programming Constants */
+
+#define IR0_DMIC	0x00000001
+#define IR0_DMIB	0x00000002
+#define IR0_DMIA	0x00000004
+#define IR0_EFT		0x00000008
+#define IR0_DMAREQ	0x00010000
+#define IR0_TXINT	0x00020000
+#define IR0_RXINTB	0x00040000
+#define IR0_RXINTA	0x00080000
+#define IR0_TXRDY	0x00100000
+#define IR0_RXRDY	0x00200000
+
+#define MD0_CRC16_0	0x00
+#define MD0_CRC16_1	0x01
+#define MD0_CRC32	0x02
+#define MD0_CRC_CCITT	0x03
+#define MD0_CRCC0	0x04
+#define MD0_CRCC1	0x08
+#define MD0_AUTO_ENA	0x10
+#define MD0_ASYNC	0x00
+#define MD0_BY_MSYNC	0x20
+#define MD0_BY_BISYNC	0x40
+#define MD0_BY_EXT	0x60
+#define MD0_BIT_SYNC	0x80
+#define MD0_TRANSP	0xc0
+
+#define MD1_NOADDR	0x00
+#define MD1_SADDR1	0x40
+#define MD1_SADDR2	0x80
+#define MD1_DADDR	0xc0
+
+#define MD2_F_DUPLEX	0x00
+#define MD2_AUTO_ECHO	0x01
+#define MD2_LOOP_HI_Z	0x02
+#define MD2_LOOP_MIR	0x03
+#define MD2_ADPLL_X8	0x00
+#define MD2_ADPLL_X16	0x08
+#define MD2_ADPLL_X32	0x10
+#define MD2_NRZ		0x00
+#define MD2_NRZI	0x20
+#define MD2_NRZ_IEEE	0x40
+#define MD2_MANCH	0x00
+#define MD2_FM1		0x20
+#define MD2_FM0		0x40
+#define MD2_FM		0x80
+
+#define CTL_RTS		0x01
+#define CTL_DTR		0x02
+#define CTL_SYN		0x04
+#define CTL_IDLC	0x10
+#define CTL_UDRNC	0x20
+#define CTL_URSKP	0x40
+#define CTL_URCT	0x80
+
+#define	RXS_BR0		0x01
+#define	RXS_BR1		0x02
+#define	RXS_BR2		0x04
+#define	RXS_BR3		0x08
+#define	RXS_ECLK	0x00
+#define	RXS_ECLK_NS	0x20
+#define	RXS_IBRG	0x40
+#define	RXS_PLL1	0x50
+#define	RXS_PLL2	0x60
+#define	RXS_PLL3	0x70
+#define	RXS_DRTXC	0x80
+
+#define	TXS_BR0		0x01
+#define	TXS_BR1		0x02
+#define	TXS_BR2		0x04
+#define	TXS_BR3		0x08
+#define	TXS_ECLK	0x00
+#define	TXS_IBRG	0x40
+#define	TXS_RCLK	0x60
+#define	TXS_DTRXC	0x80
+
+#define	EXS_RES0	0x01
+#define	EXS_RES1	0x02
+#define	EXS_RES2	0x04
+#define	EXS_TES0	0x10
+#define	EXS_TES1	0x20
+#define	EXS_TES2	0x40
+
+#define CMD_RX_RST	0x11
+#define CMD_RX_ENA	0x12
+#define CMD_RX_DIS	0x13
+#define CMD_RX_CRC_INIT	0x14
+#define CMD_RX_MSG_REJ	0x15
+#define CMD_RX_MP_SRCH	0x16
+#define CMD_RX_CRC_EXC	0x17
+#define CMD_RX_CRC_FRC	0x18
+#define CMD_TX_RST	0x01
+#define CMD_TX_ENA	0x02
+#define CMD_TX_DISA	0x03
+#define CMD_TX_CRC_INIT	0x04
+#define CMD_TX_CRC_EXC	0x05
+#define CMD_TX_EOM	0x06
+#define CMD_TX_ABORT	0x07
+#define CMD_TX_MP_ON	0x08
+#define CMD_TX_BUF_CLR	0x09
+#define CMD_TX_DISB	0x0b
+#define CMD_CH_RST	0x21
+#define CMD_SRCH_MODE	0x31
+#define CMD_NOP		0x00
+
+#define ST0_RXRDY	0x01
+#define ST0_TXRDY	0x02
+#define ST0_RXINTB	0x20
+#define ST0_RXINTA	0x40
+#define ST0_TXINT	0x80
+
+#define ST1_IDLE	0x01
+#define ST1_ABORT	0x02
+#define ST1_CDCD	0x04
+#define ST1_CCTS	0x08
+#define ST1_SYN_FLAG	0x10
+#define ST1_CLMD	0x20
+#define ST1_TXIDLE	0x40
+#define ST1_UDRN	0x80
+
+#define ST2_CRCE	0x04
+#define ST2_ONRN	0x08
+#define ST2_RBIT	0x10
+#define ST2_ABORT	0x20
+#define ST2_SHORT	0x40
+#define ST2_EOM		0x80
+
+#define ST3_RX_ENA	0x01
+#define ST3_TX_ENA	0x02
+#define ST3_DCD		0x04
+#define ST3_CTS		0x08
+#define ST3_SRCH_MODE	0x10
+#define ST3_SLOOP	0x20
+#define ST3_GPI		0x80
+
+#define ST4_RDNR	0x01
+#define ST4_RDCR	0x02
+#define ST4_TDNR	0x04
+#define ST4_TDCR	0x08
+#define ST4_OCLM	0x20
+#define ST4_CFT		0x40
+#define ST4_CGPI	0x80
+
+#define FST_CRCEF	0x04
+#define FST_OVRNF	0x08
+#define FST_RBIF	0x10
+#define FST_ABTF	0x20
+#define FST_SHRTF	0x40
+#define FST_EOMF	0x80
+
+#define IE0_RXRDY	0x01
+#define IE0_TXRDY	0x02
+#define IE0_RXINTB	0x20
+#define IE0_RXINTA	0x40
+#define IE0_TXINT	0x80
+
+#define IE1_IDLD	0x01
+#define IE1_ABTD	0x02
+#define IE1_CDCD	0x04
+#define IE1_CCTS	0x08
+#define IE1_SYNCD	0x10
+#define IE1_CLMD	0x20
+#define IE1_IDL		0x40
+#define IE1_UDRN	0x80
+
+#define IE2_CRCE	0x04
+#define IE2_OVRN	0x08
+#define IE2_RBIT	0x10
+#define IE2_ABT		0x20
+#define IE2_SHRT	0x40
+#define IE2_EOM		0x80
+
+#define IE4_RDNR	0x01
+#define IE4_RDCR	0x02
+#define IE4_TDNR	0x04
+#define IE4_TDCR	0x08
+#define IE4_OCLM	0x20
+#define IE4_CFT		0x40
+#define IE4_CGPI	0x80
+
+#define FIE_CRCEF	0x04
+#define FIE_OVRNF	0x08
+#define FIE_RBIF	0x10
+#define FIE_ABTF	0x20
+#define FIE_SHRTF	0x40
+#define FIE_EOMF	0x80
+
+#define DSR_DWE		0x01
+#define DSR_DE		0x02
+#define DSR_REF		0x04
+#define DSR_UDRF	0x04
+#define DSR_COA		0x08
+#define DSR_COF		0x10
+#define DSR_BOF		0x20
+#define DSR_EOM		0x40
+#define DSR_EOT		0x80
+
+#define DIR_REF		0x04
+#define DIR_UDRF	0x04
+#define DIR_COA		0x08
+#define DIR_COF		0x10
+#define DIR_BOF		0x20
+#define DIR_EOM		0x40
+#define DIR_EOT		0x80
+
+#define DMR_CNTE	0x02
+#define DMR_NF		0x04
+#define DMR_SEOME	0x08
+#define DMR_TMOD	0x10
+
+#define DCR_SW_ABT	0x01
+#define DCR_FCT_CLR	0x02
+
+#define PCR_PR0		0x01
+#define PCR_PR1		0x02
+#define PCR_PR2		0x04
+#define PCR_CCC		0x08
+#define PCR_BRC		0x10
+#define PCR_OSB		0x40
+#define PCR_BURST	0x80
+
+#endif /* (_HD64572_H) */
diff -Nru a/drivers/net/wan/pc300-falc-lh.h b/drivers/net/wan/pc300-falc-lh.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wan/pc300-falc-lh.h	Thu May  2 17:22:17 2002
@@ -0,0 +1,1238 @@
+/*
+ * falc.h	Description of the Siemens FALC T1/E1 framer.
+ *
+ * Author:	Ivan Passos <ivan@cyclades.com>
+ *
+ * Copyright:	(c) 2000-2001 Cyclades Corp.
+ *
+ *	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.
+ *
+ * $Log: falc-lh.h,v $
+ * Revision 3.1  2001/06/15 12:41:10  regina
+ * upping major version number
+ *
+ * Revision 1.1.1.1  2001/06/13 20:24:47  daniela
+ * PC300 initial CVS version (3.4.0-pre1)
+ *
+ * Revision 1.1 2000/05/15 ivan
+ * Included DJA bits for the LIM2 register.
+ *
+ * Revision 1.0 2000/02/22 ivan
+ * Initial version.
+ *
+ */
+
+#ifndef _FALC_LH_H
+#define _FALC_LH_H
+
+#define NUM_OF_T1_CHANNELS	24
+#define NUM_OF_E1_CHANNELS	32
+
+/*>>>>>>>>>>>>>>>>>  FALC Register Bits (Transmit Mode)  <<<<<<<<<<<<<<<<<<< */
+
+/* CMDR (Command Register)
+   ---------------- E1 & T1 ------------------------------ */
+#define CMDR_RMC	0x80
+#define CMDR_RRES	0x40
+#define CMDR_XREP	0x20
+#define CMDR_XRES	0x10
+#define CMDR_XHF	0x08
+#define CMDR_XTF	0x04
+#define CMDR_XME	0x02
+#define CMDR_SRES	0x01
+
+/* MODE (Mode Register)
+   ----------------- E1 & T1 ----------------------------- */
+#define MODE_MDS2	0x80
+#define MODE_MDS1	0x40
+#define MODE_MDS0	0x20
+#define MODE_BRAC	0x10
+#define MODE_HRAC	0x08
+
+/* IPC (Interrupt Port Configuration)
+   ----------------- E1 & T1 ----------------------------- */
+#define IPC_VIS		0x80
+#define IPC_SCI		0x04
+#define IPC_IC1		0x02
+#define IPC_IC0		0x01
+
+/* CCR1 (Common Configuration Register 1)
+   ----------------- E1 & T1 ----------------------------- */
+#define CCR1_SFLG       0x80
+#define CCR1_XTS16RA    0x40
+#define CCR1_BRM        0x40
+#define CCR1_CASSYM     0x20
+#define CCR1_EDLX       0x20
+#define CCR1_EITS       0x10
+#define CCR1_ITF        0x08
+#define CCR1_RFT1       0x02
+#define CCR1_RFT0       0x01
+
+/* CCR3 (Common Configuration Register 3)
+   ---------------- E1 & T1 ------------------------------ */
+
+#define CCR3_PRE1       0x80
+#define CCR3_PRE0       0x40
+#define CCR3_EPT        0x20
+#define CCR3_RADD       0x10
+#define CCR3_RCRC       0x04
+#define CCR3_XCRC       0x02
+
+
+/* RTR1-4 (Receive Timeslot Register 1-4)
+   ---------------- E1 & T1 ------------------------------ */
+
+#define RTR1_TS0        0x80
+#define RTR1_TS1        0x40
+#define RTR1_TS2        0x20
+#define RTR1_TS3        0x10
+#define RTR1_TS4        0x08
+#define RTR1_TS5        0x04
+#define RTR1_TS6        0x02
+#define RTR1_TS7        0x01
+
+#define RTR2_TS8        0x80
+#define RTR2_TS9        0x40
+#define RTR2_TS10       0x20
+#define RTR2_TS11       0x10
+#define RTR2_TS12       0x08
+#define RTR2_TS13       0x04
+#define RTR2_TS14       0x02
+#define RTR2_TS15       0x01
+
+#define RTR3_TS16       0x80
+#define RTR3_TS17       0x40
+#define RTR3_TS18       0x20
+#define RTR3_TS19       0x10
+#define RTR3_TS20       0x08
+#define RTR3_TS21       0x04
+#define RTR3_TS22       0x02
+#define RTR3_TS23       0x01
+
+#define RTR4_TS24       0x80
+#define RTR4_TS25       0x40
+#define RTR4_TS26       0x20
+#define RTR4_TS27       0x10
+#define RTR4_TS28       0x08
+#define RTR4_TS29       0x04
+#define RTR4_TS30       0x02
+#define RTR4_TS31       0x01
+
+
+/* TTR1-4 (Transmit Timeslot Register 1-4)
+   ---------------- E1 & T1 ------------------------------ */
+
+#define TTR1_TS0        0x80
+#define TTR1_TS1        0x40
+#define TTR1_TS2        0x20
+#define TTR1_TS3        0x10
+#define TTR1_TS4        0x08
+#define TTR1_TS5        0x04
+#define TTR1_TS6        0x02
+#define TTR1_TS7        0x01
+
+#define TTR2_TS8        0x80
+#define TTR2_TS9        0x40
+#define TTR2_TS10       0x20
+#define TTR2_TS11       0x10
+#define TTR2_TS12       0x08
+#define TTR2_TS13       0x04
+#define TTR2_TS14       0x02
+#define TTR2_TS15       0x01
+
+#define TTR3_TS16       0x80
+#define TTR3_TS17       0x40
+#define TTR3_TS18       0x20
+#define TTR3_TS19       0x10
+#define TTR3_TS20       0x08
+#define TTR3_TS21       0x04
+#define TTR3_TS22       0x02
+#define TTR3_TS23       0x01
+
+#define TTR4_TS24       0x80
+#define TTR4_TS25       0x40
+#define TTR4_TS26       0x20
+#define TTR4_TS27       0x10
+#define TTR4_TS28       0x08
+#define TTR4_TS29       0x04
+#define TTR4_TS30       0x02
+#define TTR4_TS31       0x01
+
+
+
+/* IMR0-4 (Interrupt Mask Register 0-4)
+
+   ----------------- E1 & T1 ----------------------------- */
+
+#define IMR0_RME        0x80
+#define IMR0_RFS        0x40
+#define IMR0_T8MS       0x20
+#define IMR0_ISF        0x20
+#define IMR0_RMB        0x10
+#define IMR0_CASC       0x08
+#define IMR0_RSC        0x08
+#define IMR0_CRC6       0x04
+#define IMR0_CRC4       0x04
+#define IMR0_PDEN	0x02
+#define IMR0_RPF        0x01
+
+#define IMR1_CASE       0x80
+#define IMR1_RDO        0x40
+#define IMR1_ALLS       0x20
+#define IMR1_XDU        0x10
+#define IMR1_XMB        0x08
+#define IMR1_XLSC       0x02
+#define IMR1_XPR        0x01
+#define IMR1_LLBSC	0x80
+
+#define IMR2_FAR        0x80
+#define IMR2_LFA        0x40
+#define IMR2_MFAR       0x20
+#define IMR2_T400MS     0x10
+#define IMR2_LMFA       0x10
+#define IMR2_AIS        0x08
+#define IMR2_LOS        0x04
+#define IMR2_RAR        0x02
+#define IMR2_RA         0x01
+
+#define IMR3_ES         0x80
+#define IMR3_SEC        0x40
+#define IMR3_LMFA16     0x20
+#define IMR3_AIS16      0x10
+#define IMR3_RA16       0x08
+#define IMR3_API        0x04
+#define IMR3_XSLP       0x20
+#define IMR3_XSLN       0x10
+#define IMR3_LLBSC      0x08
+#define IMR3_XRS        0x04
+#define IMR3_SLN        0x02
+#define IMR3_SLP        0x01
+
+#define IMR4_LFA        0x80
+#define IMR4_FER        0x40
+#define IMR4_CER        0x20
+#define IMR4_AIS        0x10
+#define IMR4_LOS        0x08
+#define IMR4_CVE        0x04
+#define IMR4_SLIP       0x02
+#define IMR4_EBE        0x01
+
+/* FMR0-5 for E1 and T1  (Framer Mode Register ) */
+
+#define FMR0_XC1        0x80
+#define FMR0_XC0        0x40
+#define FMR0_RC1        0x20
+#define FMR0_RC0        0x10
+#define FMR0_EXTD       0x08
+#define FMR0_ALM        0x04
+#define E1_FMR0_FRS     0x02
+#define T1_FMR0_FRS     0x08
+#define FMR0_SRAF       0x04
+#define FMR0_EXLS       0x02
+#define FMR0_SIM        0x01
+
+#define FMR1_MFCS       0x80
+#define FMR1_AFR        0x40
+#define FMR1_ENSA       0x20
+#define FMR1_CTM        0x80
+#define FMR1_SIGM       0x40
+#define FMR1_EDL        0x20
+#define FMR1_PMOD       0x10
+#define FMR1_XFS        0x08
+#define FMR1_CRC        0x08
+#define FMR1_ECM        0x04
+#define FMR1_IMOD       0x02
+#define FMR1_XAIS       0x01
+
+#define FMR2_RFS1       0x80
+#define FMR2_RFS0       0x40
+#define FMR2_MCSP	0x40
+#define FMR2_RTM        0x20
+#define FMR2_SSP        0x20
+#define FMR2_DAIS       0x10
+#define FMR2_SAIS       0x08
+#define FMR2_PLB        0x04
+#define FMR2_AXRA       0x02
+#define FMR2_ALMF       0x01
+#define FMR2_EXZE       0x01
+
+#define LOOP_RTM	0x40
+#define LOOP_SFM	0x40
+#define LOOP_ECLB	0x20
+#define LOOP_CLA	0x1f
+
+/*--------------------- E1 ----------------------------*/
+#define FMR3_XLD	0x20
+#define FMR3_XLU	0x10
+
+/*--------------------- T1 ----------------------------*/
+#define FMR4_AIS3       0x80
+#define FMR4_TM         0x40
+#define FMR4_XRA        0x20
+#define FMR4_SSC1       0x10
+#define FMR4_SSC0       0x08
+#define FMR4_AUTO       0x04
+#define FMR4_FM1        0x02
+#define FMR4_FM0        0x01
+
+#define FMR5_SRS        0x80
+#define FMR5_EIBR       0x40
+#define FMR5_XLD        0x20
+#define FMR5_XLU        0x10
+
+
+/* LOOP (Channel Loop Back)
+
+   ------------------ E1 & T1 ---------------------------- */
+
+#define LOOP_SFM        0x40
+#define LOOP_ECLB       0x20
+#define LOOP_CLA4       0x10
+#define LOOP_CLA3       0x08
+#define LOOP_CLA2       0x04
+#define LOOP_CLA1       0x02
+#define LOOP_CLA0       0x01
+
+
+
+/* XSW (Transmit Service Word Pulseframe)
+
+   ------------------- E1 --------------------------- */
+
+#define XSW_XSIS        0x80
+#define XSW_XTM         0x40
+#define XSW_XRA         0x20
+#define XSW_XY0         0x10
+#define XSW_XY1         0x08
+#define XSW_XY2         0x04
+#define XSW_XY3         0x02
+#define XSW_XY4         0x01
+
+
+/* XSP (Transmit Spare Bits)
+
+   ------------------- E1 --------------------------- */
+
+#define XSP_XAP         0x80
+#define XSP_CASEN       0x40
+#define XSP_TT0         0x20
+#define XSP_EBP         0x10
+#define XSP_AXS         0x08
+#define XSP_XSIF        0x04
+#define XSP_XS13        0x02
+#define XSP_XS15        0x01
+
+
+/* XC0/1 (Transmit Control 0/1)
+   ------------------ E1 & T1 ---------------------------- */
+
+#define XC0_SA8E        0x80
+#define XC0_SA7E        0x40
+#define XC0_SA6E        0x20
+#define XC0_SA5E        0x10
+#define XC0_SA4E        0x08
+#define XC0_BRM         0x80
+#define XC0_MFBS        0x40
+#define XC0_SFRZ        0x10
+#define XC0_XCO2        0x04
+#define XC0_XCO1        0x02
+#define XC0_XCO0        0x01
+
+#define XC1_XTO5        0x20
+#define XC1_XTO4        0x10
+#define XC1_XTO3        0x08
+#define XC1_XTO2        0x04
+#define XC1_XTO1        0x02
+#define XC1_XTO0        0x01
+
+
+/* RC0/1 (Receive Control 0/1)
+   ------------------ E1 & T1 ---------------------------- */
+
+#define RC0_SICS        0x40
+#define RC0_CRCI        0x20
+#define RC0_XCRCI       0x10
+#define RC0_RDIS        0x08
+#define RC0_RCO2        0x04
+#define RC0_RCO1        0x02
+#define RC0_RCO0        0x01
+
+#define RC1_SWD         0x80
+#define RC1_ASY4        0x40
+#define RC1_RRAM        0x40
+#define RC1_RTO5        0x20
+#define RC1_RTO4        0x10
+#define RC1_RTO3        0x08
+#define RC1_RTO2        0x04
+#define RC1_RTO1        0x02
+#define RC1_RTO0        0x01
+
+
+
+/* XPM0-2 (Transmit Pulse Mask 0-2)
+   --------------------- E1 & T1 ------------------------- */
+
+#define XPM0_XP12       0x80
+#define XPM0_XP11       0x40
+#define XPM0_XP10       0x20
+#define XPM0_XP04       0x10
+#define XPM0_XP03       0x08
+#define XPM0_XP02       0x04
+#define XPM0_XP01       0x02
+#define XPM0_XP00       0x01
+
+#define XPM1_XP30       0x80
+#define XPM1_XP24       0x40
+#define XPM1_XP23       0x20
+#define XPM1_XP22       0x10
+#define XPM1_XP21       0x08
+#define XPM1_XP20       0x04
+#define XPM1_XP14       0x02
+#define XPM1_XP13       0x01
+
+#define XPM2_XLHP       0x80
+#define XPM2_XLT        0x40
+#define XPM2_DAXLT      0x20
+#define XPM2_XP34       0x08
+#define XPM2_XP33       0x04
+#define XPM2_XP32       0x02
+#define XPM2_XP31       0x01
+
+
+/* TSWM (Transparent Service Word Mask)
+   ------------------ E1 ---------------------------- */
+
+#define TSWM_TSIS       0x80
+#define TSWM_TSIF       0x40
+#define TSWM_TRA        0x20
+#define TSWM_TSA4       0x10
+#define TSWM_TSA5       0x08
+#define TSWM_TSA6       0x04
+#define TSWM_TSA7       0x02
+#define TSWM_TSA8       0x01
+
+/* IDLE <Idle Channel Code Register>
+
+   ------------------ E1 & T1 ----------------------- */
+
+#define IDLE_IDL7       0x80
+#define IDLE_IDL6       0x40
+#define IDLE_IDL5       0x20
+#define IDLE_IDL4       0x10
+#define IDLE_IDL3       0x08
+#define IDLE_IDL2       0x04
+#define IDLE_IDL1       0x02
+#define IDLE_IDL0       0x01
+
+
+/* XSA4-8 <Transmit SA4-8 Register(Read/Write) >
+   -------------------E1 ----------------------------- */
+
+#define XSA4_XS47       0x80
+#define XSA4_XS46       0x40
+#define XSA4_XS45       0x20
+#define XSA4_XS44       0x10
+#define XSA4_XS43       0x08
+#define XSA4_XS42       0x04
+#define XSA4_XS41       0x02
+#define XSA4_XS40       0x01
+
+#define XSA5_XS57       0x80
+#define XSA5_XS56       0x40
+#define XSA5_XS55       0x20
+#define XSA5_XS54       0x10
+#define XSA5_XS53       0x08
+#define XSA5_XS52       0x04
+#define XSA5_XS51       0x02
+#define XSA5_XS50       0x01
+
+#define XSA6_XS67       0x80
+#define XSA6_XS66       0x40
+#define XSA6_XS65       0x20
+#define XSA6_XS64       0x10
+#define XSA6_XS63       0x08
+#define XSA6_XS62       0x04
+#define XSA6_XS61       0x02
+#define XSA6_XS60       0x01
+
+#define XSA7_XS77       0x80
+#define XSA7_XS76       0x40
+#define XSA7_XS75       0x20
+#define XSA7_XS74       0x10
+#define XSA7_XS73       0x08
+#define XSA7_XS72       0x04
+#define XSA7_XS71       0x02
+#define XSA7_XS70       0x01
+
+#define XSA8_XS87       0x80
+#define XSA8_XS86       0x40
+#define XSA8_XS85       0x20
+#define XSA8_XS84       0x10
+#define XSA8_XS83       0x08
+#define XSA8_XS82       0x04
+#define XSA8_XS81       0x02
+#define XSA8_XS80       0x01
+
+
+/* XDL1-3 (Transmit DL-Bit Register1-3 (read/write))
+   ----------------------- T1 --------------------- */
+
+#define XDL1_XDL17      0x80
+#define XDL1_XDL16      0x40
+#define XDL1_XDL15      0x20
+#define XDL1_XDL14      0x10
+#define XDL1_XDL13      0x08
+#define XDL1_XDL12      0x04
+#define XDL1_XDL11      0x02
+#define XDL1_XDL10      0x01
+
+#define XDL2_XDL27      0x80
+#define XDL2_XDL26      0x40
+#define XDL2_XDL25      0x20
+#define XDL2_XDL24      0x10
+#define XDL2_XDL23      0x08
+#define XDL2_XDL22      0x04
+#define XDL2_XDL21      0x02
+#define XDL2_XDL20      0x01
+
+#define XDL3_XDL37      0x80
+#define XDL3_XDL36      0x40
+#define XDL3_XDL35      0x20
+#define XDL3_XDL34      0x10
+#define XDL3_XDL33      0x08
+#define XDL3_XDL32      0x04
+#define XDL3_XDL31      0x02
+#define XDL3_XDL30      0x01
+
+
+/* ICB1-4 (Idle Channel Register 1-4)
+   ------------------ E1 ---------------------------- */
+
+#define E1_ICB1_IC0	0x80
+#define E1_ICB1_IC1	0x40
+#define E1_ICB1_IC2	0x20
+#define E1_ICB1_IC3	0x10
+#define E1_ICB1_IC4	0x08
+#define E1_ICB1_IC5	0x04
+#define E1_ICB1_IC6	0x02
+#define E1_ICB1_IC7	0x01
+
+#define E1_ICB2_IC8	0x80
+#define E1_ICB2_IC9	0x40
+#define E1_ICB2_IC10	0x20
+#define E1_ICB2_IC11	0x10
+#define E1_ICB2_IC12	0x08
+#define E1_ICB2_IC13	0x04
+#define E1_ICB2_IC14	0x02
+#define E1_ICB2_IC15	0x01
+
+#define E1_ICB3_IC16	0x80
+#define E1_ICB3_IC17	0x40
+#define E1_ICB3_IC18	0x20
+#define E1_ICB3_IC19	0x10
+#define E1_ICB3_IC20	0x08
+#define E1_ICB3_IC21	0x04
+#define E1_ICB3_IC22	0x02
+#define E1_ICB3_IC23	0x01
+
+#define E1_ICB4_IC24	0x80
+#define E1_ICB4_IC25	0x40
+#define E1_ICB4_IC26	0x20
+#define E1_ICB4_IC27	0x10
+#define E1_ICB4_IC28	0x08
+#define E1_ICB4_IC29	0x04
+#define E1_ICB4_IC30	0x02
+#define E1_ICB4_IC31	0x01
+
+/* ICB1-4 (Idle Channel Register 1-4)
+   ------------------ T1 ---------------------------- */
+
+#define T1_ICB1_IC1	0x80
+#define T1_ICB1_IC2	0x40
+#define T1_ICB1_IC3	0x20
+#define T1_ICB1_IC4	0x10
+#define T1_ICB1_IC5	0x08
+#define T1_ICB1_IC6	0x04
+#define T1_ICB1_IC7	0x02
+#define T1_ICB1_IC8	0x01
+
+#define T1_ICB2_IC9	0x80
+#define T1_ICB2_IC10	0x40
+#define T1_ICB2_IC11	0x20
+#define T1_ICB2_IC12	0x10
+#define T1_ICB2_IC13	0x08
+#define T1_ICB2_IC14	0x04
+#define T1_ICB2_IC15	0x02
+#define T1_ICB2_IC16	0x01
+
+#define T1_ICB3_IC17	0x80
+#define T1_ICB3_IC18	0x40
+#define T1_ICB3_IC19	0x20
+#define T1_ICB3_IC20	0x10
+#define T1_ICB3_IC21	0x08
+#define T1_ICB3_IC22	0x04
+#define T1_ICB3_IC23	0x02
+#define T1_ICB3_IC24	0x01
+
+/* FMR3 (Framer Mode Register 3)
+   --------------------E1------------------------ */
+
+#define FMR3_CMI        0x08
+#define FMR3_SYNSA      0x04
+#define FMR3_CFRZ       0x02
+#define FMR3_EXTIW      0x01
+
+
+
+/* CCB1-3 (Clear Channel Register)
+   ------------------- T1 ----------------------- */
+
+#define CCB1_CH1        0x80
+#define CCB1_CH2        0x40
+#define CCB1_CH3        0x20
+#define CCB1_CH4        0x10
+#define CCB1_CH5        0x08
+#define CCB1_CH6        0x04
+#define CCB1_CH7        0x02
+#define CCB1_CH8        0x01
+
+#define CCB2_CH9        0x80
+#define CCB2_CH10       0x40
+#define CCB2_CH11       0x20
+#define CCB2_CH12       0x10
+#define CCB2_CH13       0x08
+#define CCB2_CH14       0x04
+#define CCB2_CH15       0x02
+#define CCB2_CH16       0x01
+
+#define CCB3_CH17       0x80
+#define CCB3_CH18       0x40
+#define CCB3_CH19       0x20
+#define CCB3_CH20       0x10
+#define CCB3_CH21       0x08
+#define CCB3_CH22       0x04
+#define CCB3_CH23       0x02
+#define CCB3_CH24       0x01
+
+
+/* LIM0/1 (Line Interface Mode 0/1)
+   ------------------- E1 & T1 --------------------------- */
+
+#define LIM0_XFB        0x80
+#define LIM0_XDOS       0x40
+#define LIM0_SCL1       0x20
+#define LIM0_SCL0       0x10
+#define LIM0_EQON       0x08
+#define LIM0_ELOS       0x04
+#define LIM0_LL         0x02
+#define LIM0_MAS        0x01
+
+#define LIM1_EFSC       0x80
+#define LIM1_RIL2       0x40
+#define LIM1_RIL1       0x20
+#define LIM1_RIL0       0x10
+#define LIM1_DCOC       0x08
+#define LIM1_JATT       0x04
+#define LIM1_RL         0x02
+#define LIM1_DRS        0x01
+
+
+/* PCDR (Pulse Count Detection Register(Read/Write))
+   ------------------ E1 & T1 ------------------------- */
+
+#define PCDR_PCD7	0x80
+#define PCDR_PCD6	0x40
+#define PCDR_PCD5	0x20
+#define PCDR_PCD4	0x10
+#define PCDR_PCD3	0x08
+#define PCDR_PCD2	0x04
+#define PCDR_PCD1	0x02
+#define PCDR_PCD0	0x01
+
+#define PCRR_PCR7	0x80
+#define PCRR_PCR6	0x40
+#define PCRR_PCR5	0x20
+#define PCRR_PCR4	0x10
+#define PCRR_PCR3	0x08
+#define PCRR_PCR2	0x04
+#define PCRR_PCR1	0x02
+#define PCRR_PCR0	0x01
+
+
+/* LIM2 (Line Interface Mode 2)
+
+   ------------------ E1 & T1 ---------------------------- */
+
+#define LIM2_DJA2	0x20
+#define LIM2_DJA1	0x10
+#define LIM2_LOS2	0x02
+#define LIM2_LOS1	0x01
+
+/* LCR1 (Loop Code Register 1) */
+
+#define LCR1_EPRM	0x80
+#define	LCR1_XPRBS	0x40
+
+/* SIC1 (System Interface Control 1) */
+#define SIC1_SRSC	0x80
+#define SIC1_RBS1	0x20
+#define SIC1_RBS0	0x10
+#define SIC1_SXSC	0x08
+#define SIC1_XBS1	0x02
+#define SIC1_XBS0	0x01
+
+/* DEC (Disable Error Counter)
+   ------------------ E1 & T1 ---------------------------- */
+
+#define DEC_DCEC3       0x20
+#define DEC_DBEC        0x10
+#define DEC_DCEC1       0x08
+#define DEC_DCEC        0x08
+#define DEC_DEBC        0x04
+#define DEC_DCVC        0x02
+#define DEC_DFEC        0x01
+
+
+/* FALC Register Bits (Receive Mode)
+   ---------------------------------------------------------------------------- */
+
+
+/* FRS0/1 (Framer Receive Status Register 0/1)
+   ----------------- E1 & T1 ---------------------------------- */
+
+#define FRS0_LOS        0x80
+#define FRS0_AIS        0x40
+#define FRS0_LFA        0x20
+#define FRS0_RRA        0x10
+#define FRS0_API        0x08
+#define FRS0_NMF        0x04
+#define FRS0_LMFA       0x02
+#define FRS0_FSRF       0x01
+
+#define FRS1_TS16RA     0x40
+#define FRS1_TS16LOS    0x20
+#define FRS1_TS16AIS    0x10
+#define FRS1_TS16LFA    0x08
+#define FRS1_EXZD       0x80
+#define FRS1_LLBDD      0x10
+#define FRS1_LLBAD      0x08
+#define FRS1_XLS        0x02
+#define FRS1_XLO        0x01
+#define FRS1_PDEN	0x40
+
+/* FRS2/3 (Framer Receive Status Register 2/3)
+   ----------------- T1 ---------------------------------- */
+
+#define FRS2_ESC2       0x80
+#define FRS2_ESC1       0x40
+#define FRS2_ESC0       0x20
+
+#define FRS3_FEH5       0x20
+#define FRS3_FEH4       0x10
+#define FRS3_FEH3       0x08
+#define FRS3_FEH2       0x04
+#define FRS3_FEH1       0x02
+#define FRS3_FEH0       0x01
+
+
+/* RSW (Receive Service Word Pulseframe)
+   ----------------- E1 ------------------------------ */
+
+#define RSW_RSI         0x80
+#define RSW_RRA         0x20
+#define RSW_RYO         0x10
+#define RSW_RY1         0x08
+#define RSW_RY2         0x04
+#define RSW_RY3         0x02
+#define RSW_RY4         0x01
+
+
+/* RSP (Receive Spare Bits / Additional Status)
+   ---------------- E1 ------------------------------- */
+
+#define RSP_SI1         0x80
+#define RSP_SI2         0x40
+#define RSP_LLBDD	0x10
+#define RSP_LLBAD	0x08
+#define RSP_RSIF        0x04
+#define RSP_RS13        0x02
+#define RSP_RS15        0x01
+
+
+/* FECL (Framing Error Counter)
+   ---------------- E1 & T1 -------------------------- */
+
+#define FECL_FE7        0x80
+#define FECL_FE6        0x40
+#define FECL_FE5        0x20
+#define FECL_FE4        0x10
+#define FECL_FE3        0x08
+#define FECL_FE2        0x04
+#define FECL_FE1        0x02
+#define FECL_FE0        0x01
+
+#define FECH_FE15       0x80
+#define FECH_FE14       0x40
+#define FECH_FE13       0x20
+#define FECH_FE12       0x10
+#define FECH_FE11       0x08
+#define FECH_FE10       0x04
+#define FECH_FE9        0x02
+#define FECH_FE8        0x01
+
+
+/* CVCl (Code Violation Counter)
+   ----------------- E1 ------------------------- */
+
+#define CVCL_CV7        0x80
+#define CVCL_CV6        0x40
+#define CVCL_CV5        0x20
+#define CVCL_CV4        0x10
+#define CVCL_CV3        0x08
+#define CVCL_CV2        0x04
+#define CVCL_CV1        0x02
+#define CVCL_CV0        0x01
+
+#define CVCH_CV15       0x80
+#define CVCH_CV14       0x40
+#define CVCH_CV13       0x20
+#define CVCH_CV12       0x10
+#define CVCH_CV11       0x08
+#define CVCH_CV10       0x04
+#define CVCH_CV9        0x02
+#define CVCH_CV8        0x01
+
+
+/* CEC1-3L (CRC Error Counter)
+   ------------------ E1 ----------------------------- */
+
+#define CEC1L_CR7       0x80
+#define CEC1L_CR6       0x40
+#define CEC1L_CR5       0x20
+#define CEC1L_CR4       0x10
+#define CEC1L_CR3       0x08
+#define CEC1L_CR2       0x04
+#define CEC1L_CR1       0x02
+#define CEC1L_CR0       0x01
+
+#define CEC1H_CR15      0x80
+#define CEC1H_CR14      0x40
+#define CEC1H_CR13      0x20
+#define CEC1H_CR12      0x10
+#define CEC1H_CR11      0x08
+#define CEC1H_CR10      0x04
+#define CEC1H_CR9       0x02
+#define CEC1H_CR8       0x01
+
+#define CEC2L_CR7       0x80
+#define CEC2L_CR6       0x40
+#define CEC2L_CR5       0x20
+#define CEC2L_CR4       0x10
+#define CEC2L_CR3       0x08
+#define CEC2L_CR2       0x04
+#define CEC2L_CR1       0x02
+#define CEC2L_CR0       0x01
+
+#define CEC2H_CR15      0x80
+#define CEC2H_CR14      0x40
+#define CEC2H_CR13      0x20
+#define CEC2H_CR12      0x10
+#define CEC2H_CR11      0x08
+#define CEC2H_CR10      0x04
+#define CEC2H_CR9       0x02
+#define CEC2H_CR8       0x01
+
+#define CEC3L_CR7       0x80
+#define CEC3L_CR6       0x40
+#define CEC3L_CR5       0x20
+#define CEC3L_CR4       0x10
+#define CEC3L_CR3       0x08
+#define CEC3L_CR2       0x04
+#define CEC3L_CR1       0x02
+#define CEC3L_CR0       0x01
+
+#define CEC3H_CR15      0x80
+#define CEC3H_CR14      0x40
+#define CEC3H_CR13      0x20
+#define CEC3H_CR12      0x10
+#define CEC3H_CR11      0x08
+#define CEC3H_CR10      0x04
+#define CEC3H_CR9       0x02
+#define CEC3H_CR8       0x01
+
+
+/* CECL (CRC Error Counter)
+
+   ------------------ T1 ----------------------------- */
+
+#define CECL_CR7        0x80
+#define CECL_CR6        0x40
+#define CECL_CR5        0x20
+#define CECL_CR4        0x10
+#define CECL_CR3        0x08
+#define CECL_CR2        0x04
+#define CECL_CR1        0x02
+#define CECL_CR0        0x01
+
+#define CECH_CR15       0x80
+#define CECH_CR14       0x40
+#define CECH_CR13       0x20
+#define CECH_CR12       0x10
+#define CECH_CR11       0x08
+#define CECH_CR10       0x04
+#define CECH_CR9        0x02
+#define CECH_CR8        0x01
+
+/* EBCL (E Bit Error Counter)
+   ------------------- E1 & T1 ------------------------- */
+
+#define EBCL_EB7        0x80
+#define EBCL_EB6        0x40
+#define EBCL_EB5        0x20
+#define EBCL_EB4        0x10
+#define EBCL_EB3        0x08
+#define EBCL_EB2        0x04
+#define EBCL_EB1        0x02
+#define EBCL_EB0        0x01
+
+#define EBCH_EB15       0x80
+#define EBCH_EB14       0x40
+#define EBCH_EB13       0x20
+#define EBCH_EB12       0x10
+#define EBCH_EB11       0x08
+#define EBCH_EB10       0x04
+#define EBCH_EB9        0x02
+#define EBCH_EB8        0x01
+
+
+/* RSA4-8 (Receive Sa4-8-Bit Register)
+   -------------------- E1 --------------------------- */
+
+#define RSA4_RS47       0x80
+#define RSA4_RS46       0x40
+#define RSA4_RS45       0x20
+#define RSA4_RS44       0x10
+#define RSA4_RS43       0x08
+#define RSA4_RS42       0x04
+#define RSA4_RS41       0x02
+#define RSA4_RS40       0x01
+
+#define RSA5_RS57       0x80
+#define RSA5_RS56       0x40
+#define RSA5_RS55       0x20
+#define RSA5_RS54       0x10
+#define RSA5_RS53       0x08
+#define RSA5_RS52       0x04
+#define RSA5_RS51       0x02
+#define RSA5_RS50       0x01
+
+#define RSA6_RS67       0x80
+#define RSA6_RS66       0x40
+#define RSA6_RS65       0x20
+#define RSA6_RS64       0x10
+#define RSA6_RS63       0x08
+#define RSA6_RS62       0x04
+#define RSA6_RS61       0x02
+#define RSA6_RS60       0x01
+
+#define RSA7_RS77       0x80
+#define RSA7_RS76       0x40
+#define RSA7_RS75       0x20
+#define RSA7_RS74       0x10
+#define RSA7_RS73       0x08
+#define RSA7_RS72       0x04
+#define RSA7_RS71       0x02
+#define RSA7_RS70       0x01
+
+#define RSA8_RS87       0x80
+#define RSA8_RS86       0x40
+#define RSA8_RS85       0x20
+#define RSA8_RS84       0x10
+#define RSA8_RS83       0x08
+#define RSA8_RS82       0x04
+#define RSA8_RS81       0x02
+#define RSA8_RS80       0x01
+
+/* RSA6S (Receive Sa6 Bit Status Register)
+   ------------------------ T1 ------------------------- */
+
+#define RSA6S_SX        0x20
+#define RSA6S_SF        0x10
+#define RSA6S_SE        0x08
+#define RSA6S_SC        0x04
+#define RSA6S_SA        0x02
+#define RSA6S_S8        0x01
+
+
+/* RDL1-3 Receive DL-Bit Register1-3)
+   ------------------------ T1 ------------------------- */
+
+#define RDL1_RDL17      0x80
+#define RDL1_RDL16      0x40
+#define RDL1_RDL15      0x20
+#define RDL1_RDL14      0x10
+#define RDL1_RDL13      0x08
+#define RDL1_RDL12      0x04
+#define RDL1_RDL11      0x02
+#define RDL1_RDL10      0x01
+
+#define RDL2_RDL27      0x80
+#define RDL2_RDL26      0x40
+#define RDL2_RDL25      0x20
+#define RDL2_RDL24      0x10
+#define RDL2_RDL23      0x08
+#define RDL2_RDL22      0x04
+#define RDL2_RDL21      0x02
+#define RDL2_RDL20      0x01
+
+#define RDL3_RDL37      0x80
+#define RDL3_RDL36      0x40
+#define RDL3_RDL35      0x20
+#define RDL3_RDL34      0x10
+#define RDL3_RDL33      0x08
+#define RDL3_RDL32      0x04
+#define RDL3_RDL31      0x02
+#define RDL3_RDL30      0x01
+
+
+/* SIS (Signaling Status Register)
+
+   -------------------- E1 & T1 -------------------------- */
+
+#define SIS_XDOV        0x80
+#define SIS_XFW         0x40
+#define SIS_XREP        0x20
+#define SIS_RLI         0x08
+#define SIS_CEC         0x04
+#define SIS_BOM         0x01
+
+
+/* RSIS (Receive Signaling Status Register)
+
+   -------------------- E1 & T1 --------------------------- */
+
+#define RSIS_VFR        0x80
+#define RSIS_RDO        0x40
+#define RSIS_CRC16      0x20
+#define RSIS_RAB        0x10
+#define RSIS_HA1        0x08
+#define RSIS_HA0        0x04
+#define RSIS_HFR        0x02
+#define RSIS_LA         0x01
+
+
+/* RBCL/H (Receive Byte Count Low/High)
+
+   ------------------- E1 & T1 ----------------------- */
+
+#define RBCL_RBC7       0x80
+#define RBCL_RBC6       0x40
+#define RBCL_RBC5       0x20
+#define RBCL_RBC4       0x10
+#define RBCL_RBC3       0x08
+#define RBCL_RBC2       0x04
+#define RBCL_RBC1       0x02
+#define RBCL_RBC0       0x01
+
+#define RBCH_OV         0x10
+#define RBCH_RBC11      0x08
+#define RBCH_RBC10      0x04
+#define RBCH_RBC9       0x02
+#define RBCH_RBC8       0x01
+
+
+/* ISR1-3  (Interrupt Status Register 1-3)
+
+   ------------------ E1 & T1 ------------------------------ */
+
+#define  FISR0_RME	0x80
+#define  FISR0_RFS	0x40
+#define  FISR0_T8MS	0x20
+#define  FISR0_ISF	0x20
+#define  FISR0_RMB	0x10
+#define  FISR0_CASC	0x08
+#define  FISR0_RSC	0x08
+#define  FISR0_CRC6	0x04
+#define  FISR0_CRC4	0x04
+#define  FISR0_PDEN	0x02
+#define  FISR0_RPF	0x01
+
+#define  FISR1_CASE	0x80
+#define  FISR1_LLBSC	0x80
+#define  FISR1_RDO	0x40
+#define  FISR1_ALLS	0x20
+#define  FISR1_XDU	0x10
+#define  FISR1_XMB	0x08
+#define  FISR1_XLSC	0x02
+#define  FISR1_XPR	0x01
+
+#define  FISR2_FAR	0x80
+#define  FISR2_LFA	0x40
+#define  FISR2_MFAR	0x20
+#define  FISR2_T400MS	0x10
+#define  FISR2_LMFA	0x10
+#define  FISR2_AIS	0x08
+#define  FISR2_LOS	0x04
+#define  FISR2_RAR	0x02
+#define  FISR2_RA	0x01
+
+#define  FISR3_ES	0x80
+#define  FISR3_SEC	0x40
+#define  FISR3_LMFA16	0x20
+#define  FISR3_AIS16	0x10
+#define  FISR3_RA16	0x08
+#define  FISR3_API	0x04
+#define  FISR3_XSLP	0x20
+#define  FISR3_XSLN	0x10
+#define  FISR3_LLBSC	0x08
+#define  FISR3_XRS	0x04
+#define  FISR3_SLN	0x02
+#define  FISR3_SLP	0x01
+
+
+/* GIS  (Global Interrupt Status Register)
+
+   --------------------- E1 & T1 --------------------- */
+
+#define  GIS_ISR3	0x08
+#define  GIS_ISR2	0x04
+#define  GIS_ISR1	0x02
+#define  GIS_ISR0	0x01
+
+
+/* VSTR  (Version Status Register)
+
+   --------------------- E1 & T1 --------------------- */
+
+#define  VSTR_VN3	0x08
+#define  VSTR_VN2	0x04
+#define  VSTR_VN1	0x02
+#define  VSTR_VN0	0x01
+
+
+/*>>>>>>>>>>>>>>>>>>>>>  Local Control Structures  <<<<<<<<<<<<<<<<<<<<<<<<< */
+
+/* Write-only Registers (E1/T1 control mode write registers) */
+#define XFIFOH	0x00		/* Tx FIFO High Byte */
+#define XFIFOL	0x01		/* Tx FIFO Low Byte */
+#define CMDR	0x02		/* Command Reg */
+#define DEC	0x60		/* Disable Error Counter */
+#define TEST2	0x62		/* Manuf. Test Reg 2 */
+#define XS(nbr)	(0x70 + (nbr))	/* Tx CAS Reg (0 to 15) */
+
+/* Read-write Registers (E1/T1 status mode read registers) */
+#define MODE	0x03	/* Mode Reg */
+#define RAH1	0x04	/* Receive Address High 1 */
+#define RAH2	0x05	/* Receive Address High 2 */
+#define RAL1	0x06	/* Receive Address Low 1 */
+#define RAL2	0x07	/* Receive Address Low 2 */
+#define IPC	0x08	/* Interrupt Port Configuration */
+#define CCR1	0x09	/* Common Configuration Reg 1 */
+#define CCR3	0x0A	/* Common Configuration Reg 3 */
+#define PRE	0x0B	/* Preamble Reg */
+#define RTR1	0x0C	/* Receive Timeslot Reg 1 */
+#define RTR2	0x0D	/* Receive Timeslot Reg 2 */
+#define RTR3	0x0E	/* Receive Timeslot Reg 3 */
+#define RTR4	0x0F	/* Receive Timeslot Reg 4 */
+#define TTR1	0x10	/* Transmit Timeslot Reg 1 */
+#define TTR2	0x11	/* Transmit Timeslot Reg 2 */
+#define TTR3	0x12	/* Transmit Timeslot Reg 3 */
+#define TTR4	0x13	/* Transmit Timeslot Reg 4 */
+#define IMR0	0x14	/* Interrupt Mask Reg 0 */
+#define IMR1	0x15	/* Interrupt Mask Reg 1 */
+#define IMR2	0x16	/* Interrupt Mask Reg 2 */
+#define IMR3	0x17	/* Interrupt Mask Reg 3 */
+#define IMR4	0x18	/* Interrupt Mask Reg 4 */
+#define IMR5	0x19	/* Interrupt Mask Reg 5 */
+#define FMR0	0x1A	/* Framer Mode Reigster 0 */
+#define FMR1	0x1B	/* Framer Mode Reigster 1 */
+#define FMR2	0x1C	/* Framer Mode Reigster 2 */
+#define LOOP	0x1D	/* Channel Loop Back */
+#define XSW	0x1E	/* Transmit Service Word */
+#define FMR4	0x1E	/* Framer Mode Reg 4 */
+#define XSP	0x1F	/* Transmit Spare Bits */
+#define FMR5	0x1F	/* Framer Mode Reg 5 */
+#define XC0	0x20	/* Transmit Control 0 */
+#define XC1	0x21	/* Transmit Control 1 */
+#define RC0	0x22	/* Receive Control 0 */
+#define RC1	0x23	/* Receive Control 1 */
+#define XPM0	0x24	/* Transmit Pulse Mask 0 */
+#define XPM1	0x25	/* Transmit Pulse Mask 1 */
+#define XPM2	0x26	/* Transmit Pulse Mask 2 */
+#define TSWM	0x27	/* Transparent Service Word Mask */
+#define TEST1	0x28	/* Manuf. Test Reg 1 */
+#define IDLE	0x29	/* Idle Channel Code */
+#define XSA4    0x2A	/* Transmit SA4 Bit Reg */
+#define XDL1	0x2A	/* Transmit DL-Bit Reg 2 */
+#define XSA5    0x2B	/* Transmit SA4 Bit Reg */
+#define XDL2	0x2B	/* Transmit DL-Bit Reg 2 */
+#define XSA6    0x2C	/* Transmit SA4 Bit Reg */
+#define XDL3	0x2C	/* Transmit DL-Bit Reg 2 */
+#define XSA7    0x2D	/* Transmit SA4 Bit Reg */
+#define CCB1	0x2D	/* Clear Channel Reg 1 */
+#define XSA8    0x2E	/* Transmit SA4 Bit Reg */
+#define CCB2	0x2E	/* Clear Channel Reg 2 */
+#define FMR3	0x2F	/* Framer Mode Reg. 3 */
+#define CCB3	0x2F	/* Clear Channel Reg 3 */
+#define ICB1	0x30	/* Idle Channel Reg 1 */
+#define ICB2	0x31	/* Idle Channel Reg 2 */
+#define ICB3	0x32	/* Idle Channel Reg 3 */
+#define ICB4	0x33	/* Idle Channel Reg 4 */
+#define LIM0	0x34	/* Line Interface Mode 0 */
+#define LIM1	0x35	/* Line Interface Mode 1 */
+#define PCDR	0x36	/* Pulse Count Detection */
+#define PCRR	0x37	/* Pulse Count Recovery */
+#define LIM2	0x38	/* Line Interface Mode Reg 2 */
+#define LCR1	0x39	/* Loop Code Reg 1 */
+#define LCR2	0x3A	/* Loop Code Reg 2 */
+#define LCR3	0x3B	/* Loop Code Reg 3 */
+#define SIC1	0x3C	/* System Interface Control 1 */
+
+/* Read-only Registers (E1/T1 control mode read registers) */
+#define RFIFOH	0x00		/* Receive FIFO */
+#define RFIFOL	0x01		/* Receive FIFO */
+#define FRS0	0x4C		/* Framer Receive Status 0 */
+#define FRS1	0x4D		/* Framer Receive Status 1 */
+#define RSW	0x4E		/* Receive Service Word */
+#define FRS2	0x4E		/* Framer Receive Status 2 */
+#define RSP	0x4F		/* Receive Spare Bits */
+#define FRS3	0x4F		/* Framer Receive Status 3 */
+#define FECL	0x50		/* Framing Error Counter */
+#define FECH	0x51		/* Framing Error Counter */
+#define CVCL	0x52		/* Code Violation Counter */
+#define CVCH	0x53		/* Code Violation Counter */
+#define CECL	0x54		/* CRC Error Counter 1 */
+#define CECH	0x55		/* CRC Error Counter 1 */
+#define EBCL	0x56		/* E-Bit Error Counter */
+#define EBCH	0x57		/* E-Bit Error Counter */
+#define BECL	0x58		/* Bit Error Counter Low */
+#define BECH	0x59		/* Bit Error Counter Low */
+#define CEC3	0x5A		/* CRC Error Counter 3 (16-bit) */
+#define RSA4	0x5C		/* Receive SA4 Bit Reg */
+#define RDL1	0x5C		/* Receive DL-Bit Reg 1 */
+#define RSA5	0x5D		/* Receive SA5 Bit Reg */
+#define RDL2	0x5D		/* Receive DL-Bit Reg 2 */
+#define RSA6	0x5E		/* Receive SA6 Bit Reg */
+#define RDL3	0x5E		/* Receive DL-Bit Reg 3 */
+#define RSA7	0x5F		/* Receive SA7 Bit Reg */
+#define RSA8	0x60		/* Receive SA8 Bit Reg */
+#define RSA6S	0x61		/* Receive SA6 Bit Status Reg */
+#define TSR0	0x62		/* Manuf. Test Reg 0 */
+#define TSR1	0x63		/* Manuf. Test Reg 1 */
+#define SIS	0x64		/* Signaling Status Reg */
+#define RSIS	0x65		/* Receive Signaling Status Reg */
+#define RBCL	0x66		/* Receive Byte Control */
+#define RBCH	0x67		/* Receive Byte Control */
+#define FISR0	0x68		/* Interrupt Status Reg 0 */
+#define FISR1	0x69		/* Interrupt Status Reg 1 */
+#define FISR2	0x6A		/* Interrupt Status Reg 2 */
+#define FISR3	0x6B		/* Interrupt Status Reg 3 */
+#define GIS	0x6E		/* Global Interrupt Status */
+#define VSTR	0x6F		/* Version Status */
+#define RS(nbr)	(0x70 + (nbr))	/* Rx CAS Reg (0 to 15) */
+
+#endif	/* _FALC_LH_H */
+
diff -Nru a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wan/pc300.h	Thu May  2 17:22:17 2002
@@ -0,0 +1,501 @@
+/*
+ * pc300.h	Cyclades-PC300(tm) Kernel API Definitions.
+ *
+ * Author:	Ivan Passos <ivan@cyclades.com>
+ *
+ * Copyright:	(c) 1999-2002 Cyclades Corp.
+ *
+ *	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.
+ *
+ * $Log: pc300.h,v $
+ * Revision 3.12  2002/03/07 14:17:09  henrique
+ * License data fixed
+ *
+ * Revision 3.11  2002/01/28 21:09:39  daniela
+ * Included ';' after pc300hw.bus.
+ *
+ * Revision 3.10  2002/01/17 17:58:52  ivan
+ * Support for PC300-TE/M (PMC).
+ *
+ * Revision 3.9  2001/09/28 13:30:53  daniela
+ * Renamed dma_start routine to rx_dma_start.
+ *
+ * Revision 3.8  2001/09/24 13:03:45  daniela
+ * Fixed BOF interrupt treatment. Created dma_start routine.
+ *
+ * Revision 3.7  2001/08/10 17:19:58  daniela
+ * Fixed IOCTLs defines.
+ *
+ * Revision 3.6  2001/07/18 19:24:42  daniela
+ * Included kernel version.
+ *
+ * Revision 3.5  2001/07/05 18:38:08  daniela
+ * DMA transmission bug fix.
+ *
+ * Revision 3.4  2001/06/26 17:10:40  daniela
+ * New configuration parameters (line code, CRC calculation and clock).
+ *
+ * Revision 3.3  2001/06/22 13:13:02  regina
+ * MLPPP implementation
+ *
+ * Revision 3.2  2001/06/18 17:56:09  daniela
+ * Increased DEF_MTU and TX_QUEUE_LEN.
+ *
+ * Revision 3.1  2001/06/15 12:41:10  regina
+ * upping major version number
+ *
+ * Revision 1.1.1.1  2001/06/13 20:25:06  daniela
+ * PC300 initial CVS version (3.4.0-pre1)
+ *
+ * Revision 2.3 2001/03/05 daniela
+ * Created struct pc300conf, to provide the hardware information to pc300util.
+ * Inclusion of 'alloc_ramsize' field on structure 'pc300hw'.
+ * 
+ * Revision 2.2 2000/12/22 daniela
+ * Structures and defines to support pc300util: statistics, status, 
+ * loopback tests, trace.
+ * 
+ * Revision 2.1 2000/09/28 ivan
+ * Inclusion of 'iophys' and 'iosize' fields on structure 'pc300hw', to 
+ * allow release of I/O region at module unload.
+ * Changed location of include files.
+ *
+ * Revision 2.0 2000/03/27 ivan
+ * Added support for the PC300/TE cards.
+ *
+ * Revision 1.1 2000/01/31 ivan
+ * Replaced 'pc300[drv|sca].h' former PC300 driver include files.
+ *
+ * Revision 1.0 1999/12/16 ivan
+ * First official release.
+ * Inclusion of 'nchan' field on structure 'pc300hw', to allow variable 
+ * number of ports per card.
+ * Inclusion of 'if_ptr' field on structure 'pc300dev'.
+ *
+ * Revision 0.6 1999/11/17 ivan
+ * Changed X.25-specific function names to comply with adopted convention.
+ *
+ * Revision 0.5 1999/11/16 Daniela Squassoni
+ * X.25 support.
+ *
+ * Revision 0.4 1999/11/15 ivan
+ * Inclusion of 'clock' field on structure 'pc300hw'.
+ *
+ * Revision 0.3 1999/11/10 ivan
+ * IOCTL name changing.
+ * Inclusion of driver function prototypes.
+ *
+ * Revision 0.2 1999/11/03 ivan
+ * Inclusion of 'tx_skb' and union 'ifu' on structure 'pc300dev'.
+ *
+ * Revision 0.1 1999/01/15 ivan
+ * Initial version.
+ *
+ */
+
+#ifndef	_PC300_H
+#define	_PC300_H
+
+#include <linux/hdlc.h>
+#include "hd64572.h"
+#include "pc300-falc-lh.h"
+
+#ifndef CY_TYPES
+#define CY_TYPES
+#if defined(__alpha__)
+typedef	unsigned long	ucdouble;	/* 64 bits, unsigned */
+typedef	unsigned int	uclong;		/* 32 bits, unsigned */
+#else
+typedef	unsigned long	uclong;		/* 32 bits, unsigned */
+#endif
+typedef	unsigned short	ucshort;	/* 16 bits, unsigned */
+typedef	unsigned char	ucchar;		/* 8 bits, unsigned */
+#endif /* CY_TYPES */
+
+#define PC300_PROTO_MLPPP 1		
+
+#define PC300_KERNEL	"2.4.x"	/* Kernel supported by this driver */
+
+#define	PC300_DEVNAME	"hdlc"	/* Dev. name base (for hdlc0, hdlc1, etc.) */
+#define PC300_MAXINDEX	100	/* Max dev. name index (the '0' in hdlc0) */
+
+#define	PC300_MAXCARDS	4	/* Max number of cards per system */
+#define	PC300_MAXCHAN	2	/* Number of channels per card */
+
+#define	PC300_PLX_WIN	0x80    /* PLX control window size (128b) */
+#define	PC300_RAMSIZE	0x40000 /* RAM window size (256Kb) */
+#define	PC300_SCASIZE	0x400   /* SCA window size (1Kb) */
+#define	PC300_FALCSIZE	0x400	/* FALC window size (1Kb) */
+
+#define PC300_OSC_CLOCK	24576000
+#define PC300_PCI_CLOCK	33000000
+
+#define BD_DEF_LEN	0x0800	/* DMA buffer length (2KB) */
+#define DMA_TX_MEMSZ	0x8000	/* Total DMA Tx memory size (32KB/ch) */
+#define DMA_RX_MEMSZ	0x10000	/* Total DMA Rx memory size (64KB/ch) */
+
+#define N_DMA_TX_BUF	(DMA_TX_MEMSZ / BD_DEF_LEN)	/* DMA Tx buffers */
+#define N_DMA_RX_BUF	(DMA_RX_MEMSZ / BD_DEF_LEN)	/* DMA Rx buffers */
+
+/* DMA Buffer Offsets */
+#define DMA_TX_BASE	((N_DMA_TX_BUF + N_DMA_RX_BUF) *	\
+			 PC300_MAXCHAN * sizeof(pcsca_bd_t))
+#define DMA_RX_BASE	(DMA_TX_BASE + PC300_MAXCHAN*DMA_TX_MEMSZ)
+
+/* DMA Descriptor Offsets */
+#define DMA_TX_BD_BASE	0x0000
+#define DMA_RX_BD_BASE	(DMA_TX_BD_BASE + ((PC300_MAXCHAN*DMA_TX_MEMSZ / \
+				BD_DEF_LEN) * sizeof(pcsca_bd_t)))
+
+/* DMA Descriptor Macros */
+#define TX_BD_ADDR(chan, n)	(DMA_TX_BD_BASE + \
+				 ((N_DMA_TX_BUF*chan) + n) * sizeof(pcsca_bd_t))
+#define RX_BD_ADDR(chan, n)	(DMA_RX_BD_BASE + \
+				 ((N_DMA_RX_BUF*chan) + n) * sizeof(pcsca_bd_t))
+
+/* Macro to access the FALC registers (TE only) */
+#define F_REG(reg, chan)	(0x200*(chan) + ((reg)<<2))
+
+/***************************************
+ * Memory access functions/macros      *
+ * (required to support Alpha systems) *
+ ***************************************/
+#ifdef __KERNEL__
+#define cpc_writeb(port,val)	{writeb((ucchar)(val),(ulong)(port)); mb();}
+#define cpc_writew(port,val)	{writew((ushort)(val),(ulong)(port)); mb();}
+#define cpc_writel(port,val)	{writel((uclong)(val),(ulong)(port)); mb();}
+
+#define cpc_readb(port)		readb(port)
+#define cpc_readw(port)		readw(port)
+#define cpc_readl(port)		readl(port)
+
+#else /* __KERNEL__ */
+#define cpc_writeb(port,val)	(*(volatile ucchar *)(port) = (ucchar)(val))
+#define cpc_writew(port,val)	(*(volatile ucshort *)(port) = (ucshort)(val))
+#define cpc_writel(port,val)	(*(volatile uclong *)(port) = (uclong)(val))
+
+#define cpc_readb(port)		(*(volatile ucchar *)(port))
+#define cpc_readw(port)		(*(volatile ucshort *)(port))
+#define cpc_readl(port)		(*(volatile uclong *)(port))
+
+#endif /* __KERNEL__ */
+
+/****** Data Structures *****************************************************/
+
+/*
+ *      RUNTIME_9050 - PLX PCI9050-1 local configuration and shared runtime
+ *      registers. This structure can be used to access the 9050 registers
+ *      (memory mapped).
+ */
+struct RUNTIME_9050 {
+	uclong	loc_addr_range[4];	/* 00-0Ch : Local Address Ranges */
+	uclong	loc_rom_range;		/* 10h : Local ROM Range */
+	uclong	loc_addr_base[4];	/* 14-20h : Local Address Base Addrs */
+	uclong	loc_rom_base;		/* 24h : Local ROM Base */
+	uclong	loc_bus_descr[4];	/* 28-34h : Local Bus Descriptors */
+	uclong	rom_bus_descr;		/* 38h : ROM Bus Descriptor */
+	uclong	cs_base[4];		/* 3C-48h : Chip Select Base Addrs */
+	uclong	intr_ctrl_stat;		/* 4Ch : Interrupt Control/Status */
+	uclong	init_ctrl;		/* 50h : EEPROM ctrl, Init Ctrl, etc */
+};
+
+#define PLX_9050_LINT1_ENABLE	0x01
+#define PLX_9050_LINT1_POL	0x02
+#define PLX_9050_LINT1_STATUS	0x04
+#define PLX_9050_LINT2_ENABLE	0x08
+#define PLX_9050_LINT2_POL	0x10
+#define PLX_9050_LINT2_STATUS	0x20
+#define PLX_9050_INTR_ENABLE	0x40
+#define PLX_9050_SW_INTR	0x80
+
+/* Masks to access the init_ctrl PLX register */
+#define	PC300_CLKSEL_MASK		(0x00000004UL)
+#define	PC300_CHMEDIA_MASK(chan)	(0x00000020UL<<(chan*3))
+#define	PC300_CTYPE_MASK		(0x00000800UL)
+
+/* CPLD Registers (base addr = falcbase, TE only) */
+/* CPLD v. 0 */
+#define CPLD_REG1	0x140	/* Chip resets, DCD/CTS status */
+#define CPLD_REG2	0x144	/* Clock enable , LED control */
+/* CPLD v. 2 or higher */
+#define CPLD_V2_REG1	0x100	/* Chip resets, DCD/CTS status */
+#define CPLD_V2_REG2	0x104	/* Clock enable , LED control */
+#define CPLD_ID_REG	0x108	/* CPLD version */
+
+/* CPLD Register bit description: for the FALC bits, they should always be 
+   set based on the channel (use (bit<<(2*ch)) to access the correct bit for 
+   that channel) */
+#define CPLD_REG1_FALC_RESET	0x01
+#define CPLD_REG1_SCA_RESET	0x02
+#define CPLD_REG1_GLOBAL_CLK	0x08
+#define CPLD_REG1_FALC_DCD	0x10
+#define CPLD_REG1_FALC_CTS	0x20
+
+#define CPLD_REG2_FALC_TX_CLK	0x01
+#define CPLD_REG2_FALC_RX_CLK	0x02
+#define CPLD_REG2_FALC_LED1	0x10
+#define CPLD_REG2_FALC_LED2	0x20
+
+/* Structure with FALC-related fields (TE only) */
+#define PC300_FALC_MAXLOOP	0x0000ffff	/* for falc_issue_cmd() */
+
+typedef struct falc {
+	ucchar sync;		/* If true FALC is synchronized */
+	ucchar active;		/* if TRUE then already active */
+	ucchar loop_active;	/* if TRUE a line loopback UP was received */
+	ucchar loop_gen;	/* if TRUE a line loopback UP was issued */
+
+	ucchar num_channels;
+	ucchar offset;		/* 1 for T1, 0 for E1 */
+	ucchar full_bandwidth;
+
+	ucchar xmb_cause;
+	ucchar multiframe_mode;
+
+	/* Statistics */
+	ucshort pden;	/* Pulse Density violation count */
+	ucshort los;	/* Loss of Signal count */
+	ucshort losr;	/* Loss of Signal recovery count */
+	ucshort lfa;	/* Loss of frame alignment count */
+	ucshort farec;	/* Frame Alignment Recovery count */
+	ucshort lmfa;	/* Loss of multiframe alignment count */
+	ucshort ais;	/* Remote Alarm indication Signal count */
+	ucshort sec;	/* One-second timer */
+	ucshort es;	/* Errored second */
+	ucshort rai;	/* remote alarm received */
+	ucshort bec;
+	ucshort fec;
+	ucshort cvc;
+	ucshort cec;
+	ucshort ebc;
+
+	/* Status */
+	ucchar red_alarm;
+	ucchar blue_alarm;
+	ucchar loss_fa;
+	ucchar yellow_alarm;
+	ucchar loss_mfa;
+	ucchar prbs;
+} falc_t;
+
+typedef struct falc_status {
+	ucchar sync;  /* If true FALC is synchronized */
+	ucchar red_alarm;
+	ucchar blue_alarm;
+	ucchar loss_fa;
+	ucchar yellow_alarm;
+	ucchar loss_mfa;
+	ucchar prbs;
+} falc_status_t;
+
+typedef struct rsv_x21_status {
+	ucchar dcd;
+	ucchar dsr;
+	ucchar cts;
+	ucchar rts;
+	ucchar dtr;
+} rsv_x21_status_t;
+
+typedef struct pc300stats {
+	int hw_type;
+	uclong line_on;
+	uclong line_off;
+	struct net_device_stats gen_stats;
+	falc_t te_stats;
+} pc300stats_t;
+
+typedef struct pc300status {
+	int hw_type;
+	rsv_x21_status_t gen_status;
+	falc_status_t te_status;
+} pc300status_t;
+
+typedef struct pc300loopback {
+	char loop_type;
+	char loop_on;
+} pc300loopback_t;
+
+typedef struct pc300patterntst {
+	char patrntst_on;       /* 0 - off; 1 - on; 2 - read num_errors */
+	ucshort num_errors;
+} pc300patterntst_t;
+
+typedef struct pc300dev {
+	void *if_ptr;		/* General purpose pointer */
+	struct pc300ch *chan;
+	ucchar trace_on;
+	uclong line_on;		/* DCD(X.21, RSV) / sync(TE) change counters */
+	uclong line_off;
+#ifdef __KERNEL__
+	char name[16];
+	hdlc_device *hdlc;
+
+	void *private;
+	struct sk_buff *tx_skb;
+	union {	/* This union has all the protocol-specific structures */
+		struct ppp_device pppdev;
+	}ifu;
+#ifdef CONFIG_PC300_MLPPP
+	void *cpc_tty;	/* information to PC300 TTY driver */
+#endif
+#endif /* __KERNEL__ */
+}pc300dev_t;
+
+typedef struct pc300hw {
+	int type;		/* RSV, X21, etc. */
+	int bus;		/* Bus (PCI, PMC, etc.) */
+	int nchan;		/* number of channels */
+	int irq;		/* interrupt request level */
+	uclong clock;		/* Board clock */
+	ucchar cpld_id;		/* CPLD ID (TE only) */
+	ucshort cpld_reg1;	/* CPLD reg 1 (TE only) */
+	ucshort cpld_reg2;	/* CPLD reg 2 (TE only) */
+	ucshort gpioc_reg;	/* PLX GPIOC reg */
+	ucshort intctl_reg;	/* PLX Int Ctrl/Status reg */
+	uclong iophys;		/* PLX registers I/O base */
+	uclong iosize;		/* PLX registers I/O size */
+	uclong plxphys;		/* PLX registers MMIO base (physical) */
+	uclong plxbase;		/* PLX registers MMIO base (virtual) */
+	uclong plxsize;		/* PLX registers MMIO size */
+	uclong scaphys;		/* SCA registers MMIO base (physical) */
+	uclong scabase;		/* SCA registers MMIO base (virtual) */
+	uclong scasize;		/* SCA registers MMIO size */
+	uclong ramphys;		/* On-board RAM MMIO base (physical) */
+	uclong rambase;		/* On-board RAM MMIO base (virtual) */
+	uclong alloc_ramsize;	/* RAM MMIO size allocated by the PCI bridge */
+	uclong ramsize;		/* On-board RAM MMIO size */
+	uclong falcphys;	/* FALC registers MMIO base (physical) */
+	uclong falcbase;	/* FALC registers MMIO base (virtual) */
+	uclong falcsize;	/* FALC registers MMIO size */
+} pc300hw_t;
+
+typedef struct pc300chconf {
+	sync_serial_settings	phys_settings;	/* Clock type/rate (in bps), 
+						   loopback mode */
+	raw_hdlc_proto		proto_settings;	/* Encoding, parity (CRC) */
+	uclong media;		/* HW media (RS232, V.35, etc.) */
+	uclong proto;		/* Protocol (PPP, X.25, etc.) */
+	ucchar monitor;		/* Monitor mode (0 = off, !0 = on) */
+
+	/* TE-specific parameters */
+	ucchar lcode;		/* Line Code (AMI, B8ZS, etc.) */
+	ucchar fr_mode;		/* Frame Mode (ESF, D4, etc.) */
+	ucchar lbo;		/* Line Build Out */
+	ucchar rx_sens;		/* Rx Sensitivity (long- or short-haul) */
+	uclong tslot_bitmap;	/* bit[i]=1  =>  timeslot _i_ is active */
+} pc300chconf_t;
+
+typedef struct pc300ch {
+	struct pc300 *card;
+	int channel;
+	pc300dev_t d;
+	pc300chconf_t conf;
+	ucchar tx_first_bd;	/* First TX DMA block descr. w/ data */
+	ucchar tx_next_bd;	/* Next free TX DMA block descriptor */
+	ucchar rx_first_bd;	/* First free RX DMA block descriptor */
+	ucchar rx_last_bd;	/* Last free RX DMA block descriptor */
+	ucchar nfree_tx_bd;	/* Number of free TX DMA block descriptors */
+	falc_t falc;		/* FALC structure (TE only) */
+} pc300ch_t;
+
+typedef struct pc300 {
+	pc300hw_t hw;			/* hardware config. */
+	pc300ch_t chan[PC300_MAXCHAN];
+#ifdef __KERNEL__
+	spinlock_t card_lock;
+#endif /* __KERNEL__ */
+} pc300_t;
+
+typedef struct pc300conf {
+	pc300hw_t hw;
+	pc300chconf_t conf;
+} pc300conf_t;
+
+/* DEV ioctl() commands */
+#define	N_SPPP_IOCTLS	2
+
+enum pc300_ioctl_cmds {
+	SIOCCPCRESERVED = (SIOCDEVPRIVATE + N_SPPP_IOCTLS),
+	SIOCGPC300CONF,
+	SIOCSPC300CONF,
+	SIOCGPC300STATUS,
+	SIOCGPC300FALCSTATUS,
+	SIOCGPC300UTILSTATS,
+	SIOCGPC300UTILSTATUS,
+	SIOCSPC300TRACE,
+	SIOCSPC300LOOPBACK,
+	SIOCSPC300PATTERNTEST,
+};
+
+/* Loopback types - PC300/TE boards */
+enum pc300_loopback_cmds {
+	PC300LOCLOOP = 1,
+	PC300REMLOOP,
+	PC300PAYLOADLOOP,
+	PC300GENLOOPUP,
+	PC300GENLOOPDOWN,
+};
+
+/* Control Constant Definitions */
+#define	PC300_RSV	0x01
+#define	PC300_X21	0x02
+#define	PC300_TE	0x03
+
+#define	PC300_PCI	0x00
+#define	PC300_PMC	0x01
+
+#define PC300_LC_AMI	0x01
+#define PC300_LC_B8ZS	0x02
+#define PC300_LC_NRZ	0x03
+#define PC300_LC_HDB3	0x04
+
+/* Framing (T1) */
+#define PC300_FR_ESF		0x01
+#define PC300_FR_D4		0x02
+#define PC300_FR_ESF_JAPAN	0x03
+
+/* Framing (E1) */
+#define PC300_FR_MF_CRC4	0x04
+#define PC300_FR_MF_NON_CRC4	0x05
+#define PC300_FR_UNFRAMED	0x06
+
+#define PC300_LBO_0_DB		0x00
+#define PC300_LBO_7_5_DB	0x01
+#define PC300_LBO_15_DB		0x02
+#define PC300_LBO_22_5_DB	0x03
+
+#define PC300_RX_SENS_SH	0x01
+#define PC300_RX_SENS_LH	0x02
+
+#define PC300_TX_TIMEOUT	(2*HZ)
+#define PC300_TX_QUEUE_LEN	100
+#define	PC300_DEF_MTU		1600
+
+#ifdef __KERNEL__
+/* Function Prototypes */
+int dma_buf_write(pc300_t *, int, ucchar *, int);
+int dma_buf_read(pc300_t *, int, struct sk_buff *);
+void tx_dma_start(pc300_t *, int);
+void rx_dma_start(pc300_t *, int);
+void tx_dma_stop(pc300_t *, int);
+void rx_dma_stop(pc300_t *, int);
+int cpc_queue_xmit(struct sk_buff *, struct net_device *);
+void cpc_net_rx(hdlc_device *);
+void cpc_sca_status(pc300_t *, int);
+int cpc_change_mtu(struct net_device *, int);
+int cpc_ioctl(struct net_device *, struct ifreq *, int);
+int ch_config(pc300dev_t *);
+int rx_config(pc300dev_t *);
+int tx_config(pc300dev_t *);
+void cpc_opench(pc300dev_t *);
+void cpc_closech(pc300dev_t *);
+int cpc_open(struct net_device *dev);
+int cpc_close(struct net_device *dev);
+int cpc_set_media(hdlc_device *, int);
+#endif /* __KERNEL__ */
+
+#endif	/* _PC300_H */
+
diff -Nru a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wan/pc300_drv.c	Thu May  2 17:22:17 2002
@@ -0,0 +1,3683 @@
+#define	USE_PCI_CLOCK
+static char rcsid[] = 
+"Revision: 3.4.5 Date: 2002/03/07 ";
+
+/*
+ * pc300.c	Cyclades-PC300(tm) Driver.
+ *
+ * Author:	Ivan Passos <ivan@cyclades.com>
+ * Maintainer:	Daniela Squassoni <daniela@cyclades.com>
+ *
+ * Copyright:	(c) 1999-2002 Cyclades Corp.
+ *
+ *	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.
+ *	
+ *	Using tabstop = 4.
+ * 
+ * $Log: pc300_drv.c,v $
+ * Revision 3.23  2002/03/20 13:58:40  henrique
+ * Fixed ortographic mistakes
+ *
+ * Revision 3.22  2002/03/13 16:56:56  henrique
+ * Take out the debug messages
+ *
+ * Revision 3.21  2002/03/07 14:17:09  henrique
+ * License data fixed
+ *
+ * Revision 3.20  2002/01/17 17:58:52  ivan
+ * Support for PC300-TE/M (PMC).
+ *
+ * Revision 3.19  2002/01/03 17:08:47  daniela
+ * Enables DMA reception when the SCA-II disables it improperly.
+ *
+ * Revision 3.18  2001/12/03 18:47:50  daniela
+ * Esthetic changes.
+ *
+ * Revision 3.17  2001/10/19 16:50:13  henrique
+ * Patch to kernel 2.4.12 and new generic hdlc.
+ *
+ * Revision 3.16  2001/10/16 15:12:31  regina
+ * clear statistics
+ *
+ * Revision 3.11 to 3.15  2001/10/11 20:26:04  daniela
+ * More DMA fixes for noisy lines.
+ * Return the size of bad frames in dma_get_rx_frame_size, so that the Rx buffer
+ * descriptors can be cleaned by dma_buf_read (called in cpc_net_rx).
+ * Renamed dma_start routine to rx_dma_start. Improved Rx statistics.
+ * Fixed BOF interrupt treatment. Created dma_start routine.
+ * Changed min and max to cpc_min and cpc_max.
+ *
+ * Revision 3.10  2001/08/06 12:01:51  regina
+ * Fixed problem in DSR_DE bit.
+ *
+ * Revision 3.9  2001/07/18 19:27:26  daniela
+ * Added some history comments.
+ *
+ * Revision 3.8  2001/07/12 13:11:19  regina
+ * bug fix - DCD-OFF in pc300 tty driver
+ *
+ * Revision 3.3 to 3.7  2001/07/06 15:00:20  daniela
+ * Removing kernel 2.4.3 and previous support.
+ * DMA transmission bug fix.
+ * MTU check in cpc_net_rx fixed.
+ * Boot messages reviewed.
+ * New configuration parameters (line code, CRC calculation and clock).
+ *
+ * Revision 3.2 2001/06/22 13:13:02  regina
+ * MLPPP implementation. Changed the header of message trace to include
+ * the device name. New format : "hdlcX[R/T]: ".
+ * Default configuration changed.
+ *
+ * Revision 3.1 2001/06/15 regina
+ * in cpc_queue_xmit, netif_stop_queue is called if don't have free descriptor
+ * upping major version number
+ *
+ * Revision 1.1.1.1  2001/06/13 20:25:04  daniela
+ * PC300 initial CVS version (3.4.0-pre1)
+ *
+ * Revision 3.0.1.2 2001/06/08 daniela
+ * Did some changes in the DMA programming implementation to avoid the 
+ * occurrence of a SCA-II bug when CDA is accessed during a DMA transfer.
+ *
+ * Revision 3.0.1.1 2001/05/02 daniela
+ * Added kernel 2.4.3 support.
+ * 
+ * Revision 3.0.1.0 2001/03/13 daniela, henrique
+ * Added Frame Relay Support.
+ * Driver now uses HDLC generic driver to provide protocol support.
+ * 
+ * Revision 3.0.0.8 2001/03/02 daniela
+ * Fixed ram size detection. 
+ * Changed SIOCGPC300CONF ioctl, to give hw information to pc300util.
+ * 
+ * Revision 3.0.0.7 2001/02/23 daniela
+ * netif_stop_queue called before the SCA-II transmition commands in 
+ * cpc_queue_xmit, and with interrupts disabled to avoid race conditions with 
+ * transmition interrupts.
+ * Fixed falc_check_status for Unframed E1.
+ * 
+ * Revision 3.0.0.6 2000/12/13 daniela
+ * Implemented pc300util support: trace, statistics, status and loopback
+ * tests for the PC300 TE boards.
+ * 
+ * Revision 3.0.0.5 2000/12/12 ivan
+ * Added support for Unframed E1.
+ * Implemented monitor mode.
+ * Fixed DCD sensitivity on the second channel.
+ * Driver now complies with new PCI kernel architecture.
+ *
+ * Revision 3.0.0.4 2000/09/28 ivan
+ * Implemented DCD sensitivity.
+ * Moved hardware-specific open to the end of cpc_open, to avoid race
+ * conditions with early reception interrupts.
+ * Included code for [request|release]_mem_region().
+ * Changed location of pc300.h .
+ * Minor code revision (contrib. of Jeff Garzik).
+ *
+ * Revision 3.0.0.3 2000/07/03 ivan
+ * Previous bugfix for the framing errors with external clock made X21
+ * boards stop working. This version fixes it.
+ *
+ * Revision 3.0.0.2 2000/06/23 ivan
+ * Revisited cpc_queue_xmit to prevent race conditions on Tx DMA buffer
+ * handling when Tx timeouts occur.
+ * Revisited Rx statistics.
+ * Fixed a bug in the SCA-II programming that would cause framing errors
+ * when external clock was configured.
+ *
+ * Revision 3.0.0.1 2000/05/26 ivan
+ * Added logic in the SCA interrupt handler so that no board can monopolize
+ * the driver.
+ * Request PLX I/O region, although driver doesn't use it, to avoid
+ * problems with other drivers accessing it.
+ *
+ * Revision 3.0.0.0 2000/05/15 ivan
+ * Did some changes in the DMA programming implementation to avoid the
+ * occurrence of a SCA-II bug in the second channel.
+ * Implemented workaround for PLX9050 bug that would cause a system lockup
+ * in certain systems, depending on the MMIO addresses allocated to the
+ * board.
+ * Fixed the FALC chip programming to avoid synchronization problems in the
+ * second channel (TE only).
+ * Implemented a cleaner and faster Tx DMA descriptor cleanup procedure in
+ * cpc_queue_xmit().
+ * Changed the built-in driver implementation so that the driver can use the
+ * general 'hdlcN' naming convention instead of proprietary device names.
+ * Driver load messages are now device-centric, instead of board-centric.
+ * Dynamic allocation of net_device structures.
+ * Code is now compliant with the new module interface (module_[init|exit]).
+ * Make use of the PCI helper functions to access PCI resources.
+ *
+ * Revision 2.0.0.0 2000/04/15 ivan
+ * Added support for the PC300/TE boards (T1/FT1/E1/FE1).
+ *
+ * Revision 1.1.0.0 2000/02/28 ivan
+ * Major changes in the driver architecture.
+ * Softnet compliancy implemented.
+ * Driver now reports physical instead of virtual memory addresses.
+ * Added cpc_change_mtu function.
+ *
+ * Revision 1.0.0.0 1999/12/16 ivan
+ * First official release.
+ * Support for 1- and 2-channel boards (which use distinct PCI Device ID's).
+ * Support for monolythic installation (i.e., drv built into the kernel).
+ * X.25 additional checking when lapb_[dis]connect_request returns an error.
+ * SCA programming now covers X.21 as well.
+ *
+ * Revision 0.3.1.0 1999/11/18 ivan
+ * Made X.25 support configuration-dependent (as it depends on external 
+ * modules to work).
+ * Changed X.25-specific function names to comply with adopted convention.
+ * Fixed typos in X.25 functions that would cause compile errors (Daniela).
+ * Fixed bug in ch_config that would disable interrupts on a previously 
+ * enabled channel if the other channel on the same board was enabled later.
+ *
+ * Revision 0.3.0.0 1999/11/16 daniela
+ * X.25 support.
+ *
+ * Revision 0.2.3.0 1999/11/15 ivan
+ * Function cpc_ch_status now provides more detailed information.
+ * Added support for X.21 clock configuration.
+ * Changed TNR1 setting in order to prevent Tx FIFO overaccesses by the SCA.
+ * Now using PCI clock instead of internal oscillator clock for the SCA.
+ *
+ * Revision 0.2.2.0 1999/11/10 ivan
+ * Changed the *_dma_buf_check functions so that they would print only 
+ * the useful info instead of the whole buffer descriptor bank.
+ * Fixed bug in cpc_queue_xmit that would eventually crash the system 
+ * in case of a packet drop.
+ * Implemented TX underrun handling.
+ * Improved SCA fine tuning to boost up its performance.
+ *
+ * Revision 0.2.1.0 1999/11/03 ivan
+ * Added functions *dma_buf_pt_init to allow independent initialization 
+ * of the next-descr. and DMA buffer pointers on the DMA descriptors.
+ * Kernel buffer release and tbusy clearing is now done in the interrupt 
+ * handler.
+ * Fixed bug in cpc_open that would cause an interface reopen to fail.
+ * Added a protocol-specific code section in cpc_net_rx.
+ * Removed printk level defs (they might be added back after the beta phase).
+ *
+ * Revision 0.2.0.0 1999/10/28 ivan
+ * Revisited the code so that new protocols can be easily added / supported. 
+ *
+ * Revision 0.1.0.1 1999/10/20 ivan
+ * Mostly "esthetic" changes.
+ *
+ * Revision 0.1.0.0 1999/10/11 ivan
+ * Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/if.h>
+#include <linux/version.h>
+#include <net/arp.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <net/syncppp.h>
+
+#include "pc300.h"
+
+#define	CPC_LOCK(card,flags)		\
+		do {						\
+		spin_lock_irqsave(&card->card_lock, flags);	\
+		} while (0)
+
+#define CPC_UNLOCK(card,flags)			\
+		do {							\
+		spin_unlock_irqrestore(&card->card_lock, flags);	\
+		} while (0)
+
+#undef	PC300_DEBUG_PCI
+#undef	PC300_DEBUG_INTR
+#undef	PC300_DEBUG_TX
+#undef	PC300_DEBUG_RX
+#undef	PC300_DEBUG_OTHER
+
+static struct pci_device_id cpc_pci_dev_id[] __devinitdata = {
+	/* PC300/RSV or PC300/X21, 2 chan */
+	{0x120e, 0x300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x300},
+	/* PC300/RSV or PC300/X21, 1 chan */
+	{0x120e, 0x301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x301},
+	/* PC300/TE, 2 chan */
+	{0x120e, 0x310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x310},
+	/* PC300/TE, 1 chan */
+	{0x120e, 0x311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x311},
+	/* PC300/TE-M, 2 chan */
+	{0x120e, 0x320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x320},
+	/* PC300/TE-M, 1 chan */
+	{0x120e, 0x321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x321},
+	/* End of table */
+	{0,},
+};
+MODULE_DEVICE_TABLE(pci, cpc_pci_dev_id);
+
+#ifndef cpc_min
+#define	cpc_min(a,b)	(((a)<(b))?(a):(b))
+#endif
+#ifndef cpc_max
+#define	cpc_max(a,b)	(((a)>(b))?(a):(b))
+#endif
+
+/* prototypes */
+static void tx_dma_buf_pt_init(pc300_t *, int);
+static void tx_dma_buf_init(pc300_t *, int);
+static void rx_dma_buf_pt_init(pc300_t *, int);
+static void rx_dma_buf_init(pc300_t *, int);
+static void tx_dma_buf_check(pc300_t *, int);
+static void rx_dma_buf_check(pc300_t *, int);
+static void cpc_intr(int, void *, struct pt_regs *);
+static struct net_device_stats *cpc_get_stats(struct net_device *);
+static int clock_rate_calc(uclong, uclong, int *);
+static uclong detect_ram(pc300_t *);
+static void plx_init(pc300_t *);
+static void cpc_trace(struct net_device *, struct sk_buff *, char);
+static int cpc_attach(hdlc_device *, unsigned short, unsigned short);
+
+#ifdef CONFIG_PC300_MLPPP
+void cpc_tty_init(pc300dev_t * dev);
+void cpc_tty_unregister_service(pc300dev_t * pc300dev);
+void cpc_tty_receive(pc300dev_t * pc300dev);
+void cpc_tty_trigger_poll(pc300dev_t * pc300dev);
+void cpc_tty_reset_var(void);
+#endif
+
+/************************/
+/***   DMA Routines   ***/
+/************************/
+static void tx_dma_buf_pt_init(pc300_t * card, int ch)
+{
+	int i;
+	int ch_factor = ch * N_DMA_TX_BUF;
+	volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase
+			               + DMA_TX_BD_BASE + ch_factor * sizeof(pcsca_bd_t));
+
+	for (i = 0; i < N_DMA_TX_BUF; i++, ptdescr++) {
+		cpc_writel(&ptdescr->next, (uclong) (DMA_TX_BD_BASE +
+			(ch_factor + ((i + 1) & (N_DMA_TX_BUF - 1))) * sizeof(pcsca_bd_t)));
+		cpc_writel(&ptdescr->ptbuf, 
+						(uclong) (DMA_TX_BASE + (ch_factor + i) * BD_DEF_LEN));
+	}
+}
+
+static void tx_dma_buf_init(pc300_t * card, int ch)
+{
+	int i;
+	int ch_factor = ch * N_DMA_TX_BUF;
+	volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase
+			       + DMA_TX_BD_BASE + ch_factor * sizeof(pcsca_bd_t));
+
+	for (i = 0; i < N_DMA_TX_BUF; i++, ptdescr++) {
+		memset_io(ptdescr, 0, sizeof(pcsca_bd_t));
+		cpc_writew(&ptdescr->len, 0);
+		cpc_writeb(&ptdescr->status, DST_OSB);
+	}
+	tx_dma_buf_pt_init(card, ch);
+}
+
+static void rx_dma_buf_pt_init(pc300_t * card, int ch)
+{
+	int i;
+	int ch_factor = ch * N_DMA_RX_BUF;
+	volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase
+				       + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t));
+
+	for (i = 0; i < N_DMA_RX_BUF; i++, ptdescr++) {
+		cpc_writel(&ptdescr->next, (uclong) (DMA_RX_BD_BASE +
+	     	(ch_factor + ((i + 1) & (N_DMA_RX_BUF - 1))) * sizeof(pcsca_bd_t)));
+		cpc_writel(&ptdescr->ptbuf,
+			   (uclong) (DMA_RX_BASE + (ch_factor + i) * BD_DEF_LEN));
+	}
+}
+
+static void rx_dma_buf_init(pc300_t * card, int ch)
+{
+	int i;
+	int ch_factor = ch * N_DMA_RX_BUF;
+	volatile pcsca_bd_t *ptdescr = (pcsca_bd_t *) (card->hw.rambase
+				       + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t));
+
+	for (i = 0; i < N_DMA_RX_BUF; i++, ptdescr++) {
+		memset_io(ptdescr, 0, sizeof(pcsca_bd_t));
+		cpc_writew(&ptdescr->len, 0);
+		cpc_writeb(&ptdescr->status, 0);
+	}
+	rx_dma_buf_pt_init(card, ch);
+}
+
+static void tx_dma_buf_check(pc300_t * card, int ch)
+{
+	volatile pcsca_bd_t *ptdescr;
+	int i;
+	ucshort first_bd = card->chan[ch].tx_first_bd;
+	ucshort next_bd = card->chan[ch].tx_next_bd;
+
+	printk("#CH%d: f_bd = %d(0x%08x), n_bd = %d(0x%08x)\n", ch,
+	       first_bd, TX_BD_ADDR(ch, first_bd),
+	       next_bd, TX_BD_ADDR(ch, next_bd));
+	for (i = first_bd,
+	     ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, first_bd));
+	     i != ((next_bd + 1) & (N_DMA_TX_BUF - 1));
+	     i = (i + 1) & (N_DMA_TX_BUF - 1), 
+		 ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, i))) {
+		printk("\n CH%d TX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d",
+		       ch, i, (uclong) cpc_readl(&ptdescr->next),
+		       (uclong) cpc_readl(&ptdescr->ptbuf),
+		       cpc_readb(&ptdescr->status), cpc_readw(&ptdescr->len));
+	}
+	printk("\n");
+}
+
+#ifdef	PC300_DEBUG_OTHER
+/* Show all TX buffer descriptors */
+static void tx1_dma_buf_check(pc300_t * card, int ch)
+{
+	volatile pcsca_bd_t *ptdescr;
+	int i;
+	ucshort first_bd = card->chan[ch].tx_first_bd;
+	ucshort next_bd = card->chan[ch].tx_next_bd;
+	uclong scabase = card->hw.scabase;
+
+	printk ("\nnfree_tx_bd = %d \n", card->chan[ch].nfree_tx_bd);
+	printk("#CH%d: f_bd = %d(0x%08x), n_bd = %d(0x%08x)\n", ch,
+	       first_bd, TX_BD_ADDR(ch, first_bd),
+	       next_bd, TX_BD_ADDR(ch, next_bd));
+	printk("TX_CDA=0x%08lx, TX_EDA=0x%08lx\n",
+	       (uclong) cpc_readl(scabase + DTX_REG(CDAL, ch)),
+	       (uclong) cpc_readl(scabase + DTX_REG(EDAL, ch)));
+	for (i = 0; i < N_DMA_TX_BUF; i++) {
+		ptdescr = (pcsca_bd_t *) (card->hw.rambase + TX_BD_ADDR(ch, i));
+		printk("\n CH%d TX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d",
+		       ch, i, (uclong) cpc_readl(&ptdescr->next),
+		       (uclong) cpc_readl(&ptdescr->ptbuf),
+		       cpc_readb(&ptdescr->status), cpc_readw(&ptdescr->len));
+	}
+	printk("\n");
+}
+#endif
+			 
+static void rx_dma_buf_check(pc300_t * card, int ch)
+{
+	volatile pcsca_bd_t *ptdescr;
+	int i;
+	ucshort first_bd = card->chan[ch].rx_first_bd;
+	ucshort last_bd = card->chan[ch].rx_last_bd;
+	int ch_factor;
+
+	ch_factor = ch * N_DMA_RX_BUF;
+	printk("#CH%d: f_bd = %d, l_bd = %d\n", ch, first_bd, last_bd);
+	for (i = 0, ptdescr = (pcsca_bd_t *) (card->hw.rambase +
+					      DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t));
+	     i < N_DMA_RX_BUF; i++, ptdescr++) {
+		if (cpc_readb(&ptdescr->status) & DST_OSB)
+			printk ("\n CH%d RX%d: next=0x%lx, ptbuf=0x%lx, ST=0x%x, len=%d",
+				 ch, i, (uclong) cpc_readl(&ptdescr->next),
+				 (uclong) cpc_readl(&ptdescr->ptbuf),
+				 cpc_readb(&ptdescr->status),
+				 cpc_readw(&ptdescr->len));
+	}
+	printk("\n");
+}
+
+int dma_get_rx_frame_size(pc300_t * card, int ch)
+{
+	volatile pcsca_bd_t *ptdescr;
+	ucshort first_bd = card->chan[ch].rx_first_bd;
+	int rcvd = 0;
+	volatile ucchar status;
+
+	ptdescr = (pcsca_bd_t *)(card->hw.rambase + RX_BD_ADDR(ch, first_bd));
+	while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) {
+		rcvd += cpc_readw(&ptdescr->len);
+		first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1);
+		if ((status & DST_EOM) || (first_bd == card->chan[ch].rx_last_bd)) {
+			/* Return the size of a good frame or incomplete bad frame 
+			* (dma_buf_read will clean the buffer descriptors in this case). */
+			return (rcvd);
+		}
+		ptdescr = (pcsca_bd_t *)(card->hw.rambase + cpc_readl(&ptdescr->next));
+	}
+	return (-1);
+}
+
+/*
+ * dma_buf_write: writes a frame to the Tx DMA buffers
+ * NOTE: this function writes one frame at a time.
+ */
+int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len)
+{
+	int i, nchar;
+	volatile pcsca_bd_t *ptdescr;
+	int tosend = len;
+	ucchar nbuf = ((len - 1) / BD_DEF_LEN) + 1;
+
+	if (nbuf >= card->chan[ch].nfree_tx_bd) {
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < nbuf; i++) {
+		ptdescr = (pcsca_bd_t *) (card->hw.rambase +
+					  TX_BD_ADDR(ch, card->chan[ch].tx_next_bd));
+		nchar = cpc_min(BD_DEF_LEN, tosend);
+		if (cpc_readb(&ptdescr->status) & DST_OSB) {
+			memcpy_toio((void *)(card->hw.rambase + cpc_readl(&ptdescr->ptbuf)),
+				    &ptdata[len - tosend], nchar);
+			cpc_writew(&ptdescr->len, nchar);
+			card->chan[ch].nfree_tx_bd--;
+			if ((i + 1) == nbuf) {
+				/* This must be the last BD to be used */
+				cpc_writeb(&ptdescr->status, DST_EOM);
+			} else {
+				cpc_writeb(&ptdescr->status, 0);
+			}
+		} else {
+			return -ENOMEM;
+		}
+		tosend -= nchar;
+		card->chan[ch].tx_next_bd =
+			(card->chan[ch].tx_next_bd + 1) & (N_DMA_TX_BUF - 1);
+	}
+	/* If it gets to here, it means we have sent the whole frame */
+	return 0;
+}
+
+/*
+ * dma_buf_read: reads a frame from the Rx DMA buffers
+ * NOTE: this function reads one frame at a time.
+ */
+int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb)
+{
+	int nchar;
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	volatile pcsca_bd_t *ptdescr;
+	int rcvd = 0;
+	volatile ucchar status;
+
+	ptdescr = (pcsca_bd_t *) (card->hw.rambase +
+				  RX_BD_ADDR(ch, chan->rx_first_bd));
+	while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) {
+		nchar = cpc_readw(&ptdescr->len);
+		if ((status & (DST_OVR | DST_CRC | DST_RBIT | DST_SHRT | DST_ABT))
+		    || (nchar > BD_DEF_LEN)) {
+
+			if (nchar > BD_DEF_LEN)
+				status |= DST_RBIT;
+			rcvd = -status;
+			/* Discard remaining descriptors used by the bad frame */
+			while (chan->rx_first_bd != chan->rx_last_bd) {
+				cpc_writeb(&ptdescr->status, 0);
+				chan->rx_first_bd = (chan->rx_first_bd+1) & (N_DMA_RX_BUF-1);
+				if (status & DST_EOM)
+					break;
+				ptdescr = (pcsca_bd_t *) (card->hw.rambase +
+							  cpc_readl(&ptdescr->next));
+				status = cpc_readb(&ptdescr->status);
+			}
+			break;
+		}
+		if (nchar != 0) {
+			if (skb) {
+				memcpy_fromio(skb_put(skb, nchar),
+				 (void *)(card->hw.rambase+cpc_readl(&ptdescr->ptbuf)),nchar);
+			}
+			rcvd += nchar;
+		}
+		cpc_writeb(&ptdescr->status, 0);
+		cpc_writeb(&ptdescr->len, 0);
+		chan->rx_first_bd = (chan->rx_first_bd + 1) & (N_DMA_RX_BUF - 1);
+
+		if (status & DST_EOM)
+			break;
+
+		ptdescr = (pcsca_bd_t *) (card->hw.rambase + cpc_readl(&ptdescr->next));
+	}
+
+	if (rcvd != 0) {
+		/* Update pointer */
+		chan->rx_last_bd = (chan->rx_first_bd - 1) & (N_DMA_RX_BUF - 1);
+		/* Update EDA */
+		cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch),
+			   RX_BD_ADDR(ch, chan->rx_last_bd));
+	}
+	return (rcvd);
+}
+
+void tx_dma_stop(pc300_t * card, int ch)
+{
+	uclong scabase = card->hw.scabase;
+	ucchar drr_ena_bit = 1 << (5 + 2 * ch);
+	ucchar drr_rst_bit = 1 << (1 + 2 * ch);
+
+	/* Disable DMA */
+	cpc_writeb(scabase + DRR, drr_ena_bit);
+	cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit);
+}
+
+void rx_dma_stop(pc300_t * card, int ch)
+{
+	uclong scabase = card->hw.scabase;
+	ucchar drr_ena_bit = 1 << (4 + 2 * ch);
+	ucchar drr_rst_bit = 1 << (2 * ch);
+
+	/* Disable DMA */
+	cpc_writeb(scabase + DRR, drr_ena_bit);
+	cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit);
+}
+
+void rx_dma_start(pc300_t * card, int ch)
+{
+	uclong scabase = card->hw.scabase;
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	
+	/* Start DMA */
+	cpc_writel(scabase + DRX_REG(CDAL, ch),
+		   RX_BD_ADDR(ch, chan->rx_first_bd));
+	if (cpc_readl(scabase + DRX_REG(CDAL,ch)) !=
+				  RX_BD_ADDR(ch, chan->rx_first_bd)) {
+		cpc_writel(scabase + DRX_REG(CDAL, ch),
+				   RX_BD_ADDR(ch, chan->rx_first_bd));
+	}
+	cpc_writel(scabase + DRX_REG(EDAL, ch),
+		   RX_BD_ADDR(ch, chan->rx_last_bd));
+	cpc_writew(scabase + DRX_REG(BFLL, ch), BD_DEF_LEN);
+	cpc_writeb(scabase + DSR_RX(ch), DSR_DE);
+	if (!(cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) {
+	cpc_writeb(scabase + DSR_RX(ch), DSR_DE);
+	}
+}
+
+/*************************/
+/***   FALC Routines   ***/
+/*************************/
+void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd)
+{
+	uclong falcbase = card->hw.falcbase;
+	unsigned long i = 0;
+
+	while (cpc_readb(falcbase + F_REG(SIS, ch)) & SIS_CEC) {
+		if (i++ >= PC300_FALC_MAXLOOP) {
+			printk("%s: FALC command locked(cmd=0x%x).\n",
+			       card->chan[ch].d.name, cmd);
+			break;
+		}
+	}
+	cpc_writeb(falcbase + F_REG(CMDR, ch), cmd);
+}
+
+void falc_intr_enable(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+
+	/* Interrupt pins are open-drain */
+	cpc_writeb(falcbase + F_REG(IPC, ch),
+		   cpc_readb(falcbase + F_REG(IPC, ch)) & ~IPC_IC0);
+	/* Conters updated each second */
+	cpc_writeb(falcbase + F_REG(FMR1, ch),
+		   cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_ECM);
+	/* Enable SEC and ES interrupts  */
+	cpc_writeb(falcbase + F_REG(IMR3, ch),
+		   cpc_readb(falcbase + F_REG(IMR3, ch)) & ~(IMR3_SEC | IMR3_ES));
+	if (conf->fr_mode == PC300_FR_UNFRAMED) {
+		cpc_writeb(falcbase + F_REG(IMR4, ch),
+			   cpc_readb(falcbase + F_REG(IMR4, ch)) & ~(IMR4_LOS));
+	} else {
+		cpc_writeb(falcbase + F_REG(IMR4, ch),
+			   cpc_readb(falcbase + F_REG(IMR4, ch)) &
+			   ~(IMR4_LFA | IMR4_AIS | IMR4_LOS | IMR4_SLIP));
+	}
+	if (conf->media == IF_IFACE_T1) {
+		cpc_writeb(falcbase + F_REG(IMR3, ch),
+			   cpc_readb(falcbase + F_REG(IMR3, ch)) & ~IMR3_LLBSC);
+	} else {
+		cpc_writeb(falcbase + F_REG(IPC, ch),
+			   cpc_readb(falcbase + F_REG(IPC, ch)) | IPC_SCI);
+		if (conf->fr_mode == PC300_FR_UNFRAMED) {
+			cpc_writeb(falcbase + F_REG(IMR2, ch),
+				   cpc_readb(falcbase + F_REG(IMR2, ch)) & ~(IMR2_LOS));
+		} else {
+			cpc_writeb(falcbase + F_REG(IMR2, ch),
+				   cpc_readb(falcbase + F_REG(IMR2, ch)) &
+				   ~(IMR2_FAR | IMR2_LFA | IMR2_AIS | IMR2_LOS));
+			if (pfalc->multiframe_mode) {
+				cpc_writeb(falcbase + F_REG(IMR2, ch),
+					   cpc_readb(falcbase + F_REG(IMR2, ch)) & 
+					   ~(IMR2_T400MS | IMR2_MFAR));
+			} else {
+				cpc_writeb(falcbase + F_REG(IMR2, ch),
+					   cpc_readb(falcbase + F_REG(IMR2, ch)) | 
+					   IMR2_T400MS | IMR2_MFAR);
+			}
+		}
+	}
+}
+
+void falc_open_timeslot(pc300_t * card, int ch, int timeslot)
+{
+	uclong falcbase = card->hw.falcbase;
+	ucchar tshf = card->chan[ch].falc.offset;
+
+	cpc_writeb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch),
+		   cpc_readb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch)) & 
+		   	~(0x80 >> ((timeslot - tshf) & 0x07)));
+	cpc_writeb(falcbase + F_REG((TTR1 + timeslot / 8), ch),
+		   cpc_readb(falcbase + F_REG((TTR1 + timeslot / 8), ch)) | 
+   			(0x80 >> (timeslot & 0x07)));
+	cpc_writeb(falcbase + F_REG((RTR1 + timeslot / 8), ch),
+		   cpc_readb(falcbase + F_REG((RTR1 + timeslot / 8), ch)) | 
+			(0x80 >> (timeslot & 0x07)));
+}
+
+void falc_close_timeslot(pc300_t * card, int ch, int timeslot)
+{
+	uclong falcbase = card->hw.falcbase;
+	ucchar tshf = card->chan[ch].falc.offset;
+
+	cpc_writeb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch),
+		   cpc_readb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch)) | 
+		   (0x80 >> ((timeslot - tshf) & 0x07)));
+	cpc_writeb(falcbase + F_REG((TTR1 + timeslot / 8), ch),
+		   cpc_readb(falcbase + F_REG((TTR1 + timeslot / 8), ch)) & 
+		   ~(0x80 >> (timeslot & 0x07)));
+	cpc_writeb(falcbase + F_REG((RTR1 + timeslot / 8), ch),
+		   cpc_readb(falcbase + F_REG((RTR1 + timeslot / 8), ch)) & 
+		   ~(0x80 >> (timeslot & 0x07)));
+}
+
+void falc_close_all_timeslots(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	uclong falcbase = card->hw.falcbase;
+
+	cpc_writeb(falcbase + F_REG(ICB1, ch), 0xff);
+	cpc_writeb(falcbase + F_REG(TTR1, ch), 0);
+	cpc_writeb(falcbase + F_REG(RTR1, ch), 0);
+	cpc_writeb(falcbase + F_REG(ICB2, ch), 0xff);
+	cpc_writeb(falcbase + F_REG(TTR2, ch), 0);
+	cpc_writeb(falcbase + F_REG(RTR2, ch), 0);
+	cpc_writeb(falcbase + F_REG(ICB3, ch), 0xff);
+	cpc_writeb(falcbase + F_REG(TTR3, ch), 0);
+	cpc_writeb(falcbase + F_REG(RTR3, ch), 0);
+	if (conf->media == IF_IFACE_E1) {
+		cpc_writeb(falcbase + F_REG(ICB4, ch), 0xff);
+		cpc_writeb(falcbase + F_REG(TTR4, ch), 0);
+		cpc_writeb(falcbase + F_REG(RTR4, ch), 0);
+	}
+}
+
+void falc_open_all_timeslots(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	uclong falcbase = card->hw.falcbase;
+
+	cpc_writeb(falcbase + F_REG(ICB1, ch), 0);
+	if (conf->fr_mode == PC300_FR_UNFRAMED) {
+		cpc_writeb(falcbase + F_REG(TTR1, ch), 0xff);
+		cpc_writeb(falcbase + F_REG(RTR1, ch), 0xff);
+	} else {
+		/* Timeslot 0 is never enabled */
+		cpc_writeb(falcbase + F_REG(TTR1, ch), 0x7f);
+		cpc_writeb(falcbase + F_REG(RTR1, ch), 0x7f);
+	}
+	cpc_writeb(falcbase + F_REG(ICB2, ch), 0);
+	cpc_writeb(falcbase + F_REG(TTR2, ch), 0xff);
+	cpc_writeb(falcbase + F_REG(RTR2, ch), 0xff);
+	cpc_writeb(falcbase + F_REG(ICB3, ch), 0);
+	cpc_writeb(falcbase + F_REG(TTR3, ch), 0xff);
+	cpc_writeb(falcbase + F_REG(RTR3, ch), 0xff);
+	if (conf->media == IF_IFACE_E1) {
+		cpc_writeb(falcbase + F_REG(ICB4, ch), 0);
+		cpc_writeb(falcbase + F_REG(TTR4, ch), 0xff);
+		cpc_writeb(falcbase + F_REG(RTR4, ch), 0xff);
+	} else {
+		cpc_writeb(falcbase + F_REG(ICB4, ch), 0xff);
+		cpc_writeb(falcbase + F_REG(TTR4, ch), 0x80);
+		cpc_writeb(falcbase + F_REG(RTR4, ch), 0x80);
+	}
+}
+
+void falc_init_timeslot(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	int tslot;
+
+	for (tslot = 0; tslot < pfalc->num_channels; tslot++) {
+		if (conf->tslot_bitmap & (1 << tslot)) {
+			// Channel enabled
+			falc_open_timeslot(card, ch, tslot + 1);
+		} else {
+			// Channel disabled
+			falc_close_timeslot(card, ch, tslot + 1);
+		}
+	}
+}
+
+void falc_enable_comm(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	falc_t *pfalc = (falc_t *) & chan->falc;
+
+	if (pfalc->full_bandwidth) {
+		falc_open_all_timeslots(card, ch);
+	} else {
+		falc_init_timeslot(card, ch);
+	}
+	// CTS/DCD ON
+	cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
+		   cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) &
+		   ~((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch)));
+}
+
+void falc_disable_comm(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	falc_t *pfalc = (falc_t *) & chan->falc;
+
+	if (pfalc->loop_active != 2) {
+		falc_close_all_timeslots(card, ch);
+	}
+	// CTS/DCD OFF
+	cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
+		   cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) |
+		   ((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch)));
+}
+
+void falc_init_t1(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+	ucchar dja = (ch ? (LIM2_DJA2 | LIM2_DJA1) : 0);
+
+	/* Switch to T1 mode (PCM 24) */
+	cpc_writeb(falcbase + F_REG(FMR1, ch), FMR1_PMOD);
+
+	/* Wait 20 us for setup */
+	udelay(20);
+
+	/* Transmit Buffer Size (1 frame) */
+	cpc_writeb(falcbase + F_REG(SIC1, ch), SIC1_XBS0);
+
+	/* Clock mode */
+	if (conf->phys_settings.clock_type == CLOCK_INT) { /* Master mode */
+		cpc_writeb(falcbase + F_REG(LIM0, ch),
+			   cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_MAS);
+	} else { /* Slave mode */
+		cpc_writeb(falcbase + F_REG(LIM0, ch),
+			   cpc_readb(falcbase + F_REG(LIM0, ch)) & ~LIM0_MAS);
+		cpc_writeb(falcbase + F_REG(LOOP, ch),
+			   cpc_readb(falcbase + F_REG(LOOP, ch)) & ~LOOP_RTM);
+	}
+
+	cpc_writeb(falcbase + F_REG(IPC, ch), IPC_SCI);
+	cpc_writeb(falcbase + F_REG(FMR0, ch),
+		   cpc_readb(falcbase + F_REG(FMR0, ch)) &
+		   ~(FMR0_XC0 | FMR0_XC1 | FMR0_RC0 | FMR0_RC1));
+
+	switch (conf->lcode) {
+		case PC300_LC_AMI:
+			cpc_writeb(falcbase + F_REG(FMR0, ch),
+				   cpc_readb(falcbase + F_REG(FMR0, ch)) |
+				   FMR0_XC1 | FMR0_RC1);
+			/* Clear Channel register to ON for all channels */
+			cpc_writeb(falcbase + F_REG(CCB1, ch), 0xff);
+			cpc_writeb(falcbase + F_REG(CCB2, ch), 0xff);
+			cpc_writeb(falcbase + F_REG(CCB3, ch), 0xff);
+			break;
+
+		case PC300_LC_B8ZS:
+			cpc_writeb(falcbase + F_REG(FMR0, ch),
+				   cpc_readb(falcbase + F_REG(FMR0, ch)) |
+				   FMR0_XC0 | FMR0_XC1 | FMR0_RC0 | FMR0_RC1);
+			break;
+
+		case PC300_LC_NRZ:
+			cpc_writeb(falcbase + F_REG(FMR0, ch),
+				   cpc_readb(falcbase + F_REG(FMR0, ch)) | 0x00);
+			break;
+	}
+
+	cpc_writeb(falcbase + F_REG(LIM0, ch),
+		   cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_ELOS);
+	cpc_writeb(falcbase + F_REG(LIM0, ch),
+		   cpc_readb(falcbase + F_REG(LIM0, ch)) & ~(LIM0_SCL1 | LIM0_SCL0));
+	/* Set interface mode to 2 MBPS */
+	cpc_writeb(falcbase + F_REG(FMR1, ch),
+		   cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_IMOD);
+
+	switch (conf->fr_mode) {
+		case PC300_FR_ESF:
+			pfalc->multiframe_mode = 0;
+			cpc_writeb(falcbase + F_REG(FMR4, ch),
+				   cpc_readb(falcbase + F_REG(FMR4, ch)) | FMR4_FM1);
+			cpc_writeb(falcbase + F_REG(FMR1, ch),
+				   cpc_readb(falcbase + F_REG(FMR1, ch)) | 
+				   FMR1_CRC | FMR1_EDL);
+			cpc_writeb(falcbase + F_REG(XDL1, ch), 0);
+			cpc_writeb(falcbase + F_REG(XDL2, ch), 0);
+			cpc_writeb(falcbase + F_REG(XDL3, ch), 0);
+			cpc_writeb(falcbase + F_REG(FMR0, ch),
+				   cpc_readb(falcbase + F_REG(FMR0, ch)) & ~FMR0_SRAF);
+			cpc_writeb(falcbase + F_REG(FMR2, ch),
+				   cpc_readb(falcbase + F_REG(FMR2,ch)) | FMR2_MCSP | FMR2_SSP);
+			break;
+
+		case PC300_FR_D4:
+			pfalc->multiframe_mode = 1;
+			cpc_writeb(falcbase + F_REG(FMR4, ch),
+				   cpc_readb(falcbase + F_REG(FMR4, ch)) &
+				   ~(FMR4_FM1 | FMR4_FM0));
+			cpc_writeb(falcbase + F_REG(FMR0, ch),
+				   cpc_readb(falcbase + F_REG(FMR0, ch)) | FMR0_SRAF);
+			cpc_writeb(falcbase + F_REG(FMR2, ch),
+				   cpc_readb(falcbase + F_REG(FMR2, ch)) & ~FMR2_SSP);
+			break;
+	}
+
+	/* Enable Automatic Resynchronization */
+	cpc_writeb(falcbase + F_REG(FMR4, ch),
+		   cpc_readb(falcbase + F_REG(FMR4, ch)) | FMR4_AUTO);
+
+	/* Transmit Automatic Remote Alarm */
+	cpc_writeb(falcbase + F_REG(FMR2, ch),
+		   cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_AXRA);
+
+	/* Channel translation mode 1 : one to one */
+	cpc_writeb(falcbase + F_REG(FMR1, ch),
+		   cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_CTM);
+
+	/* No signaling */
+	cpc_writeb(falcbase + F_REG(FMR1, ch),
+		   cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_SIGM);
+	cpc_writeb(falcbase + F_REG(FMR5, ch),
+		   cpc_readb(falcbase + F_REG(FMR5, ch)) &
+		   ~(FMR5_EIBR | FMR5_SRS));
+	cpc_writeb(falcbase + F_REG(CCR1, ch), 0);
+
+	cpc_writeb(falcbase + F_REG(LIM1, ch),
+		   cpc_readb(falcbase + F_REG(LIM1, ch)) | LIM1_RIL0 | LIM1_RIL1);
+
+	switch (conf->lbo) {
+			/* Provides proper Line Build Out */
+		case PC300_LBO_0_DB:
+			cpc_writeb(falcbase + F_REG(LIM2, ch), (LIM2_LOS1 | dja));
+			cpc_writeb(falcbase + F_REG(XPM0, ch), 0x5a);
+			cpc_writeb(falcbase + F_REG(XPM1, ch), 0x8f);
+			cpc_writeb(falcbase + F_REG(XPM2, ch), 0x20);
+			break;
+		case PC300_LBO_7_5_DB:
+			cpc_writeb(falcbase + F_REG(LIM2, ch), (0x40 | LIM2_LOS1 | dja));
+			cpc_writeb(falcbase + F_REG(XPM0, ch), 0x11);
+			cpc_writeb(falcbase + F_REG(XPM1, ch), 0x02);
+			cpc_writeb(falcbase + F_REG(XPM2, ch), 0x20);
+			break;
+		case PC300_LBO_15_DB:
+			cpc_writeb(falcbase + F_REG(LIM2, ch), (0x80 | LIM2_LOS1 | dja));
+			cpc_writeb(falcbase + F_REG(XPM0, ch), 0x8e);
+			cpc_writeb(falcbase + F_REG(XPM1, ch), 0x01);
+			cpc_writeb(falcbase + F_REG(XPM2, ch), 0x20);
+			break;
+		case PC300_LBO_22_5_DB:
+			cpc_writeb(falcbase + F_REG(LIM2, ch), (0xc0 | LIM2_LOS1 | dja));
+			cpc_writeb(falcbase + F_REG(XPM0, ch), 0x09);
+			cpc_writeb(falcbase + F_REG(XPM1, ch), 0x01);
+			cpc_writeb(falcbase + F_REG(XPM2, ch), 0x20);
+			break;
+	}
+
+	/* Transmit Clock-Slot Offset */
+	cpc_writeb(falcbase + F_REG(XC0, ch),
+		   cpc_readb(falcbase + F_REG(XC0, ch)) | 0x01);
+	/* Transmit Time-slot Offset */
+	cpc_writeb(falcbase + F_REG(XC1, ch), 0x3e);
+	/* Receive  Clock-Slot offset */
+	cpc_writeb(falcbase + F_REG(RC0, ch), 0x05);
+	/* Receive  Time-slot offset */
+	cpc_writeb(falcbase + F_REG(RC1, ch), 0x00);
+
+	/* LOS Detection after 176 consecutive 0s */
+	cpc_writeb(falcbase + F_REG(PCDR, ch), 0x0a);
+	/* LOS Recovery after 22 ones in the time window of PCD */
+	cpc_writeb(falcbase + F_REG(PCRR, ch), 0x15);
+
+	cpc_writeb(falcbase + F_REG(IDLE, ch), 0x7f);
+
+	if (conf->fr_mode == PC300_FR_ESF_JAPAN) {
+		cpc_writeb(falcbase + F_REG(RC1, ch),
+			   cpc_readb(falcbase + F_REG(RC1, ch)) | 0x80);
+	}
+
+	falc_close_all_timeslots(card, ch);
+}
+
+void falc_init_e1(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+	ucchar dja = (ch ? (LIM2_DJA2 | LIM2_DJA1) : 0);
+
+	/* Switch to E1 mode (PCM 30) */
+	cpc_writeb(falcbase + F_REG(FMR1, ch),
+		   cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_PMOD);
+
+	/* Clock mode */
+	if (conf->phys_settings.clock_type == CLOCK_INT) { /* Master mode */
+		cpc_writeb(falcbase + F_REG(LIM0, ch),
+			   cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_MAS);
+	} else { /* Slave mode */
+		cpc_writeb(falcbase + F_REG(LIM0, ch),
+			   cpc_readb(falcbase + F_REG(LIM0, ch)) & ~LIM0_MAS);
+	}
+	cpc_writeb(falcbase + F_REG(LOOP, ch),
+		   cpc_readb(falcbase + F_REG(LOOP, ch)) & ~LOOP_SFM);
+
+	cpc_writeb(falcbase + F_REG(IPC, ch), IPC_SCI);
+	cpc_writeb(falcbase + F_REG(FMR0, ch),
+		   cpc_readb(falcbase + F_REG(FMR0, ch)) &
+		   ~(FMR0_XC0 | FMR0_XC1 | FMR0_RC0 | FMR0_RC1));
+
+	switch (conf->lcode) {
+		case PC300_LC_AMI:
+			cpc_writeb(falcbase + F_REG(FMR0, ch),
+				   cpc_readb(falcbase + F_REG(FMR0, ch)) |
+				   FMR0_XC1 | FMR0_RC1);
+			break;
+
+		case PC300_LC_HDB3:
+			cpc_writeb(falcbase + F_REG(FMR0, ch),
+				   cpc_readb(falcbase + F_REG(FMR0, ch)) |
+				   FMR0_XC0 | FMR0_XC1 | FMR0_RC0 | FMR0_RC1);
+			break;
+
+		case PC300_LC_NRZ:
+			break;
+	}
+
+	cpc_writeb(falcbase + F_REG(LIM0, ch),
+		   cpc_readb(falcbase + F_REG(LIM0, ch)) & ~(LIM0_SCL1 | LIM0_SCL0));
+	/* Set interface mode to 2 MBPS */
+	cpc_writeb(falcbase + F_REG(FMR1, ch),
+		   cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_IMOD);
+
+	cpc_writeb(falcbase + F_REG(XPM0, ch), 0x18);
+	cpc_writeb(falcbase + F_REG(XPM1, ch), 0x03);
+	cpc_writeb(falcbase + F_REG(XPM2, ch), 0x00);
+
+	switch (conf->fr_mode) {
+		case PC300_FR_MF_CRC4:
+			pfalc->multiframe_mode = 1;
+			cpc_writeb(falcbase + F_REG(FMR1, ch),
+				   cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_XFS);
+			cpc_writeb(falcbase + F_REG(FMR2, ch),
+				   cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_RFS1);
+			cpc_writeb(falcbase + F_REG(FMR2, ch),
+				   cpc_readb(falcbase + F_REG(FMR2, ch)) & ~FMR2_RFS0);
+			cpc_writeb(falcbase + F_REG(FMR3, ch),
+				   cpc_readb(falcbase + F_REG(FMR3, ch)) & ~FMR3_EXTIW);
+
+			/* MultiFrame Resynchronization */
+			cpc_writeb(falcbase + F_REG(FMR1, ch),
+				   cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_MFCS);
+
+			/* Automatic Loss of Multiframe > 914 CRC errors */
+			cpc_writeb(falcbase + F_REG(FMR2, ch),
+				   cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_ALMF);
+
+			/* S1 and SI1/SI2 spare Bits set to 1 */
+			cpc_writeb(falcbase + F_REG(XSP, ch),
+				   cpc_readb(falcbase + F_REG(XSP, ch)) & ~XSP_AXS);
+			cpc_writeb(falcbase + F_REG(XSP, ch),
+				   cpc_readb(falcbase + F_REG(XSP, ch)) | XSP_EBP);
+			cpc_writeb(falcbase + F_REG(XSP, ch),
+				   cpc_readb(falcbase + F_REG(XSP, ch)) | XSP_XS13 | XSP_XS15);
+
+			/* Automatic Force Resynchronization */
+			cpc_writeb(falcbase + F_REG(FMR1, ch),
+				   cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_AFR);
+
+			/* Transmit Automatic Remote Alarm */
+			cpc_writeb(falcbase + F_REG(FMR2, ch),
+				   cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_AXRA);
+
+			/* Transmit Spare Bits for National Use (Y, Sn, Sa) */
+			cpc_writeb(falcbase + F_REG(XSW, ch),
+				   cpc_readb(falcbase + F_REG(XSW, ch)) |
+				   XSW_XY0 | XSW_XY1 | XSW_XY2 | XSW_XY3 | XSW_XY4);
+			break;
+
+		case PC300_FR_MF_NON_CRC4:
+		case PC300_FR_D4:
+			pfalc->multiframe_mode = 0;
+			cpc_writeb(falcbase + F_REG(FMR1, ch),
+				   cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_XFS);
+			cpc_writeb(falcbase + F_REG(FMR2, ch),
+				   cpc_readb(falcbase + F_REG(FMR2, ch)) & 
+				   ~(FMR2_RFS1 | FMR2_RFS0));
+			cpc_writeb(falcbase + F_REG(XSW, ch),
+				   cpc_readb(falcbase + F_REG(XSW, ch)) | XSW_XSIS);
+			cpc_writeb(falcbase + F_REG(XSP, ch),
+				   cpc_readb(falcbase + F_REG(XSP, ch)) | XSP_XSIF);
+
+			/* Automatic Force Resynchronization */
+			cpc_writeb(falcbase + F_REG(FMR1, ch),
+				   cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_AFR);
+
+			/* Transmit Automatic Remote Alarm */
+			cpc_writeb(falcbase + F_REG(FMR2, ch),
+				   cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_AXRA);
+
+			/* Transmit Spare Bits for National Use (Y, Sn, Sa) */
+			cpc_writeb(falcbase + F_REG(XSW, ch),
+				   cpc_readb(falcbase + F_REG(XSW, ch)) |
+				   XSW_XY0 | XSW_XY1 | XSW_XY2 | XSW_XY3 | XSW_XY4);
+			break;
+
+		case PC300_FR_UNFRAMED:
+			pfalc->multiframe_mode = 0;
+			cpc_writeb(falcbase + F_REG(FMR1, ch),
+				   cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_XFS);
+			cpc_writeb(falcbase + F_REG(FMR2, ch),
+				   cpc_readb(falcbase + F_REG(FMR2, ch)) & 
+				   ~(FMR2_RFS1 | FMR2_RFS0));
+			cpc_writeb(falcbase + F_REG(XSP, ch),
+				   cpc_readb(falcbase + F_REG(XSP, ch)) | XSP_TT0);
+			cpc_writeb(falcbase + F_REG(XSW, ch),
+				   cpc_readb(falcbase + F_REG(XSW, ch)) & 
+				   ~(XSW_XTM|XSW_XY0|XSW_XY1|XSW_XY2|XSW_XY3|XSW_XY4));
+			cpc_writeb(falcbase + F_REG(TSWM, ch), 0xff);
+			cpc_writeb(falcbase + F_REG(FMR2, ch),
+				   cpc_readb(falcbase + F_REG(FMR2, ch)) |
+				   (FMR2_RTM | FMR2_DAIS));
+			cpc_writeb(falcbase + F_REG(FMR2, ch),
+				   cpc_readb(falcbase + F_REG(FMR2, ch)) & ~FMR2_AXRA);
+			cpc_writeb(falcbase + F_REG(FMR1, ch),
+				   cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_AFR);
+			pfalc->sync = 1;
+			cpc_writeb(falcbase + card->hw.cpld_reg2,
+				   cpc_readb(falcbase + card->hw.cpld_reg2) |
+				   (CPLD_REG2_FALC_LED2 << (2 * ch)));
+			break;
+	}
+
+	/* No signaling */
+	cpc_writeb(falcbase + F_REG(XSP, ch),
+		   cpc_readb(falcbase + F_REG(XSP, ch)) & ~XSP_CASEN);
+	cpc_writeb(falcbase + F_REG(CCR1, ch), 0);
+
+	cpc_writeb(falcbase + F_REG(LIM1, ch),
+		   cpc_readb(falcbase + F_REG(LIM1, ch)) | LIM1_RIL0 | LIM1_RIL1);
+	cpc_writeb(falcbase + F_REG(LIM2, ch), (LIM2_LOS1 | dja));
+
+	/* Transmit Clock-Slot Offset */
+	cpc_writeb(falcbase + F_REG(XC0, ch),
+		   cpc_readb(falcbase + F_REG(XC0, ch)) | 0x01);
+	/* Transmit Time-slot Offset */
+	cpc_writeb(falcbase + F_REG(XC1, ch), 0x3e);
+	/* Receive  Clock-Slot offset */
+	cpc_writeb(falcbase + F_REG(RC0, ch), 0x05);
+	/* Receive  Time-slot offset */
+	cpc_writeb(falcbase + F_REG(RC1, ch), 0x00);
+
+	/* LOS Detection after 176 consecutive 0s */
+	cpc_writeb(falcbase + F_REG(PCDR, ch), 0x0a);
+	/* LOS Recovery after 22 ones in the time window of PCD */
+	cpc_writeb(falcbase + F_REG(PCRR, ch), 0x15);
+
+	cpc_writeb(falcbase + F_REG(IDLE, ch), 0x7f);
+
+	falc_close_all_timeslots(card, ch);
+}
+
+void falc_init_hdlc(pc300_t * card, int ch)
+{
+	uclong falcbase = card->hw.falcbase;
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+
+	/* Enable transparent data transfer */
+	if (conf->fr_mode == PC300_FR_UNFRAMED) {
+		cpc_writeb(falcbase + F_REG(MODE, ch), 0);
+	} else {
+		cpc_writeb(falcbase + F_REG(MODE, ch),
+			   cpc_readb(falcbase + F_REG(MODE, ch)) |
+			   (MODE_HRAC | MODE_MDS2));
+		cpc_writeb(falcbase + F_REG(RAH2, ch), 0xff);
+		cpc_writeb(falcbase + F_REG(RAH1, ch), 0xff);
+		cpc_writeb(falcbase + F_REG(RAL2, ch), 0xff);
+		cpc_writeb(falcbase + F_REG(RAL1, ch), 0xff);
+	}
+
+	/* Tx/Rx reset  */
+	falc_issue_cmd(card, ch, CMDR_RRES | CMDR_XRES | CMDR_SRES);
+
+	/* Enable interrupt sources */
+	falc_intr_enable(card, ch);
+}
+
+void te_config(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+	ucchar dummy;
+	unsigned long flags;
+
+	memset(pfalc, 0, sizeof(falc_t));
+	switch (conf->media) {
+		case IF_IFACE_T1:
+			pfalc->num_channels = NUM_OF_T1_CHANNELS;
+			pfalc->offset = 1;
+			break;
+		case IF_IFACE_E1:
+			pfalc->num_channels = NUM_OF_E1_CHANNELS;
+			pfalc->offset = 0;
+			break;
+	}
+	if (conf->tslot_bitmap == 0xffffffffUL)
+		pfalc->full_bandwidth = 1;
+	else
+		pfalc->full_bandwidth = 0;
+
+	CPC_LOCK(card, flags);
+	/* Reset the FALC chip */
+	cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
+		   cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) |
+		   (CPLD_REG1_FALC_RESET << (2 * ch)));
+	udelay(10000);
+	cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
+		   cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) &
+		   ~(CPLD_REG1_FALC_RESET << (2 * ch)));
+
+	if (conf->media == IF_IFACE_T1) {
+		falc_init_t1(card, ch);
+	} else {
+		falc_init_e1(card, ch);
+	}
+	falc_init_hdlc(card, ch);
+	if (conf->rx_sens == PC300_RX_SENS_SH) {
+		cpc_writeb(falcbase + F_REG(LIM0, ch),
+			   cpc_readb(falcbase + F_REG(LIM0, ch)) & ~LIM0_EQON);
+	} else {
+		cpc_writeb(falcbase + F_REG(LIM0, ch),
+			   cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_EQON);
+	}
+	cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
+		   cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) |
+		   ((CPLD_REG2_FALC_TX_CLK | CPLD_REG2_FALC_RX_CLK) << (2 * ch)));
+
+	/* Clear all interrupt registers */
+	dummy = cpc_readb(falcbase + F_REG(FISR0, ch)) +
+		cpc_readb(falcbase + F_REG(FISR1, ch)) +
+		cpc_readb(falcbase + F_REG(FISR2, ch)) +
+		cpc_readb(falcbase + F_REG(FISR3, ch));
+	CPC_UNLOCK(card, flags);
+}
+
+void falc_check_status(pc300_t * card, int ch, unsigned char frs0)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+
+	/* Verify LOS */
+	if (frs0 & FRS0_LOS) {
+		if (!pfalc->red_alarm) {
+			pfalc->red_alarm = 1;
+			pfalc->los++;
+			if (!pfalc->blue_alarm) {
+				// EVENT_FALC_ABNORMAL
+				if (conf->media == IF_IFACE_T1) {
+					/* Disable this interrupt as it may otherwise interfere 
+					 * with other working boards. */
+					cpc_writeb(falcbase + F_REG(IMR0, ch), 
+						   cpc_readb(falcbase + F_REG(IMR0, ch))
+						   | IMR0_PDEN);
+				}
+				falc_disable_comm(card, ch);
+				// EVENT_FALC_ABNORMAL
+			}
+		}
+	} else {
+		if (pfalc->red_alarm) {
+			pfalc->red_alarm = 0;
+			pfalc->losr++;
+		}
+	}
+
+	if (conf->fr_mode != PC300_FR_UNFRAMED) {
+		/* Verify AIS alarm */
+		if (frs0 & FRS0_AIS) {
+			if (!pfalc->blue_alarm) {
+				pfalc->blue_alarm = 1;
+				pfalc->ais++;
+				// EVENT_AIS
+				if (conf->media == IF_IFACE_T1) {
+					/* Disable this interrupt as it may otherwise interfere with                       other working boards. */
+					cpc_writeb(falcbase + F_REG(IMR0, ch),
+						   cpc_readb(falcbase + F_REG(IMR0, ch)) | IMR0_PDEN);
+				}
+				falc_disable_comm(card, ch);
+				// EVENT_AIS
+			}
+		} else {
+			pfalc->blue_alarm = 0;
+		}
+
+		/* Verify LFA */
+		if (frs0 & FRS0_LFA) {
+			if (!pfalc->loss_fa) {
+				pfalc->loss_fa = 1;
+				pfalc->lfa++;
+				if (!pfalc->blue_alarm && !pfalc->red_alarm) {
+					// EVENT_FALC_ABNORMAL
+					if (conf->media == IF_IFACE_T1) {
+						/* Disable this interrupt as it may otherwise 
+						 * interfere with other working boards. */
+						cpc_writeb(falcbase + F_REG(IMR0, ch),
+							   cpc_readb(falcbase + F_REG(IMR0, ch))
+							   | IMR0_PDEN);
+					}
+					falc_disable_comm(card, ch);
+					// EVENT_FALC_ABNORMAL
+				}
+			}
+		} else {
+			if (pfalc->loss_fa) {
+				pfalc->loss_fa = 0;
+				pfalc->farec++;
+			}
+		}
+
+		/* Verify LMFA */
+		if (pfalc->multiframe_mode && (frs0 & FRS0_LMFA)) {
+			/* D4 or CRC4 frame mode */
+			if (!pfalc->loss_mfa) {
+				pfalc->loss_mfa = 1;
+				pfalc->lmfa++;
+				if (!pfalc->blue_alarm && !pfalc->red_alarm &&
+				    !pfalc->loss_fa) {
+					// EVENT_FALC_ABNORMAL
+					if (conf->media == IF_IFACE_T1) {
+						/* Disable this interrupt as it may otherwise 
+						 * interfere with other working boards. */
+						cpc_writeb(falcbase + F_REG(IMR0, ch),
+							   cpc_readb(falcbase + F_REG(IMR0, ch))
+							   | IMR0_PDEN);
+					}
+					falc_disable_comm(card, ch);
+					// EVENT_FALC_ABNORMAL
+				}
+			}
+		} else {
+			pfalc->loss_mfa = 0;
+		}
+
+		/* Verify Remote Alarm */
+		if (frs0 & FRS0_RRA) {
+			if (!pfalc->yellow_alarm) {
+				pfalc->yellow_alarm = 1;
+				pfalc->rai++;
+				if (pfalc->sync) {
+					// EVENT_RAI
+					falc_disable_comm(card, ch);
+					// EVENT_RAI
+				}
+			}
+		} else {
+			pfalc->yellow_alarm = 0;
+		}
+	} /* if !PC300_UNFRAMED */
+
+	if (pfalc->red_alarm || pfalc->loss_fa ||
+	    pfalc->loss_mfa || pfalc->blue_alarm) {
+		if (pfalc->sync) {
+			pfalc->sync = 0;
+			chan->d.line_off++;
+			cpc_writeb(falcbase + card->hw.cpld_reg2,
+				   cpc_readb(falcbase + card->hw.cpld_reg2) &
+				   ~(CPLD_REG2_FALC_LED2 << (2 * ch)));
+		}
+	} else {
+		if (!pfalc->sync) {
+			pfalc->sync = 1;
+			chan->d.line_on++;
+			cpc_writeb(falcbase + card->hw.cpld_reg2,
+				   cpc_readb(falcbase + card->hw.cpld_reg2) |
+				   (CPLD_REG2_FALC_LED2 << (2 * ch)));
+		}
+	}
+
+	if (pfalc->sync && !pfalc->yellow_alarm) {
+		if (!pfalc->active) {
+			// EVENT_FALC_NORMAL
+			if (pfalc->loop_active) {
+				return;
+			}
+			if (conf->media == IF_IFACE_T1) {
+				cpc_writeb(falcbase + F_REG(IMR0, ch),
+					   cpc_readb(falcbase + F_REG(IMR0, ch)) & ~IMR0_PDEN);
+			}
+			falc_enable_comm(card, ch);
+			// EVENT_FALC_NORMAL
+			pfalc->active = 1;
+		}
+	} else {
+		if (pfalc->active) {
+			pfalc->active = 0;
+		}
+	}
+}
+
+void falc_update_stats(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+	ucshort counter;
+
+	counter = cpc_readb(falcbase + F_REG(FECL, ch));
+	counter |= cpc_readb(falcbase + F_REG(FECH, ch)) << 8;
+	pfalc->fec += counter;
+
+	counter = cpc_readb(falcbase + F_REG(CVCL, ch));
+	counter |= cpc_readb(falcbase + F_REG(CVCH, ch)) << 8;
+	pfalc->cvc += counter;
+
+	counter = cpc_readb(falcbase + F_REG(CECL, ch));
+	counter |= cpc_readb(falcbase + F_REG(CECH, ch)) << 8;
+	pfalc->cec += counter;
+
+	counter = cpc_readb(falcbase + F_REG(EBCL, ch));
+	counter |= cpc_readb(falcbase + F_REG(EBCH, ch)) << 8;
+	pfalc->ebc += counter;
+
+	if (cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_EPRM) {
+		mdelay(10);
+		counter = cpc_readb(falcbase + F_REG(BECL, ch));
+		counter |= cpc_readb(falcbase + F_REG(BECH, ch)) << 8;
+		pfalc->bec += counter;
+
+		if (((conf->media == IF_IFACE_T1) &&
+		     (cpc_readb(falcbase + F_REG(FRS1, ch)) & FRS1_LLBAD) &&
+		     (!(cpc_readb(falcbase + F_REG(FRS1, ch)) & FRS1_PDEN)))
+		    ||
+		    ((conf->media == IF_IFACE_E1) &&
+		     (cpc_readb(falcbase + F_REG(RSP, ch)) & RSP_LLBAD))) {
+			pfalc->prbs = 2;
+		} else {
+			pfalc->prbs = 1;
+		}
+	}
+}
+
+/*----------------------------------------------------------------------------
+ * falc_remote_loop
+ *----------------------------------------------------------------------------
+ * Description:	In the remote loopback mode the clock and data recovered
+ *		from the line inputs RL1/2 or RDIP/RDIN are routed back
+ *		to the line outputs XL1/2 or XDOP/XDON via the analog
+ *		transmitter. As in normal mode they are processsed by
+ *		the synchronizer and then sent to the system interface.
+ *----------------------------------------------------------------------------
+ */
+void falc_remote_loop(pc300_t * card, int ch, int loop_on)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+
+	if (loop_on) {
+		// EVENT_FALC_ABNORMAL
+		if (conf->media == IF_IFACE_T1) {
+			/* Disable this interrupt as it may otherwise interfere with 
+			 * other working boards. */
+			cpc_writeb(falcbase + F_REG(IMR0, ch),
+				   cpc_readb(falcbase + F_REG(IMR0, ch)) | IMR0_PDEN);
+		}
+		falc_disable_comm(card, ch);
+		// EVENT_FALC_ABNORMAL
+		cpc_writeb(falcbase + F_REG(LIM1, ch),
+			   cpc_readb(falcbase + F_REG(LIM1, ch)) | LIM1_RL);
+		pfalc->loop_active = 1;
+	} else {
+		cpc_writeb(falcbase + F_REG(LIM1, ch),
+			   cpc_readb(falcbase + F_REG(LIM1, ch)) & ~LIM1_RL);
+		pfalc->sync = 0;
+		cpc_writeb(falcbase + card->hw.cpld_reg2,
+			   cpc_readb(falcbase + card->hw.cpld_reg2) &
+			   ~(CPLD_REG2_FALC_LED2 << (2 * ch)));
+		pfalc->active = 0;
+		falc_issue_cmd(card, ch, CMDR_XRES);
+		pfalc->loop_active = 0;
+	}
+}
+
+/*----------------------------------------------------------------------------
+ * falc_local_loop
+ *----------------------------------------------------------------------------
+ * Description: The local loopback mode disconnects the receive lines 
+ *		RL1/RL2 resp. RDIP/RDIN from the receiver. Instead of the
+ *		signals coming from the line the data provided by system
+ *		interface are routed through the analog receiver back to
+ *		the system interface. The unipolar bit stream will be
+ *		undisturbed transmitted on the line. Receiver and transmitter
+ *		coding must be identical.
+ *----------------------------------------------------------------------------
+ */
+void falc_local_loop(pc300_t * card, int ch, int loop_on)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+
+	if (loop_on) {
+		cpc_writeb(falcbase + F_REG(LIM0, ch),
+			   cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_LL);
+		pfalc->loop_active = 1;
+	} else {
+		cpc_writeb(falcbase + F_REG(LIM0, ch),
+			   cpc_readb(falcbase + F_REG(LIM0, ch)) & ~LIM0_LL);
+		pfalc->loop_active = 0;
+	}
+}
+
+/*----------------------------------------------------------------------------
+ * falc_payload_loop
+ *----------------------------------------------------------------------------
+ * Description: This routine allows to enable/disable payload loopback.
+ *		When the payload loop is activated, the received 192 bits
+ *		of payload data will be looped back to the transmit
+ *		direction. The framing bits, CRC6 and DL bits are not 
+ *		looped. They are originated by the FALC-LH transmitter.
+ *----------------------------------------------------------------------------
+ */
+void falc_payload_loop(pc300_t * card, int ch, int loop_on)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+
+	if (loop_on) {
+		// EVENT_FALC_ABNORMAL
+		if (conf->media == IF_IFACE_T1) {
+			/* Disable this interrupt as it may otherwise interfere with 
+			 * other working boards. */
+			cpc_writeb(falcbase + F_REG(IMR0, ch),
+				   cpc_readb(falcbase + F_REG(IMR0, ch)) | IMR0_PDEN);
+		}
+		falc_disable_comm(card, ch);
+		// EVENT_FALC_ABNORMAL
+		cpc_writeb(falcbase + F_REG(FMR2, ch),
+			   cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_PLB);
+		if (conf->media == IF_IFACE_T1) {
+			cpc_writeb(falcbase + F_REG(FMR4, ch),
+				   cpc_readb(falcbase + F_REG(FMR4, ch)) | FMR4_TM);
+		} else {
+			cpc_writeb(falcbase + F_REG(FMR5, ch),
+				   cpc_readb(falcbase + F_REG(FMR5, ch)) | XSP_TT0);
+		}
+		falc_open_all_timeslots(card, ch);
+		pfalc->loop_active = 2;
+	} else {
+		cpc_writeb(falcbase + F_REG(FMR2, ch),
+			   cpc_readb(falcbase + F_REG(FMR2, ch)) & ~FMR2_PLB);
+		if (conf->media == IF_IFACE_T1) {
+			cpc_writeb(falcbase + F_REG(FMR4, ch),
+				   cpc_readb(falcbase + F_REG(FMR4, ch)) & ~FMR4_TM);
+		} else {
+			cpc_writeb(falcbase + F_REG(FMR5, ch),
+				   cpc_readb(falcbase + F_REG(FMR5, ch)) & ~XSP_TT0);
+		}
+		pfalc->sync = 0;
+		cpc_writeb(falcbase + card->hw.cpld_reg2,
+			   cpc_readb(falcbase + card->hw.cpld_reg2) &
+			   ~(CPLD_REG2_FALC_LED2 << (2 * ch)));
+		pfalc->active = 0;
+		falc_issue_cmd(card, ch, CMDR_XRES);
+		pfalc->loop_active = 0;
+	}
+}
+
+/*----------------------------------------------------------------------------
+ * turn_off_xlu
+ *----------------------------------------------------------------------------
+ * Description:	Turns XLU bit off in the proper register
+ *----------------------------------------------------------------------------
+ */
+void turn_off_xlu(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	uclong falcbase = card->hw.falcbase;
+
+	if (conf->media == IF_IFACE_T1) {
+		cpc_writeb(falcbase + F_REG(FMR5, ch),
+			   cpc_readb(falcbase + F_REG(FMR5, ch)) & ~FMR5_XLU);
+	} else {
+		cpc_writeb(falcbase + F_REG(FMR3, ch),
+			   cpc_readb(falcbase + F_REG(FMR3, ch)) & ~FMR3_XLU);
+	}
+}
+
+/*----------------------------------------------------------------------------
+ * turn_off_xld
+ *----------------------------------------------------------------------------
+ * Description: Turns XLD bit off in the proper register
+ *----------------------------------------------------------------------------
+ */
+void turn_off_xld(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	uclong falcbase = card->hw.falcbase;
+
+	if (conf->media == IF_IFACE_T1) {
+		cpc_writeb(falcbase + F_REG(FMR5, ch),
+			   cpc_readb(falcbase + F_REG(FMR5, ch)) & ~FMR5_XLD);
+	} else {
+		cpc_writeb(falcbase + F_REG(FMR3, ch),
+			   cpc_readb(falcbase + F_REG(FMR3, ch)) & ~FMR3_XLD);
+	}
+}
+
+/*----------------------------------------------------------------------------
+ * falc_generate_loop_up_code
+ *----------------------------------------------------------------------------
+ * Description:	This routine writes the proper FALC chip register in order
+ *		to generate a LOOP activation code over a T1/E1 line.
+ *----------------------------------------------------------------------------
+ */
+void falc_generate_loop_up_code(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+
+	if (conf->media == IF_IFACE_T1) {
+		cpc_writeb(falcbase + F_REG(FMR5, ch),
+			   cpc_readb(falcbase + F_REG(FMR5, ch)) | FMR5_XLU);
+	} else {
+		cpc_writeb(falcbase + F_REG(FMR3, ch),
+			   cpc_readb(falcbase + F_REG(FMR3, ch)) | FMR3_XLU);
+	}
+	// EVENT_FALC_ABNORMAL
+	if (conf->media == IF_IFACE_T1) {
+		/* Disable this interrupt as it may otherwise interfere with 
+		 * other working boards. */
+		cpc_writeb(falcbase + F_REG(IMR0, ch),
+			   cpc_readb(falcbase + F_REG(IMR0, ch)) | IMR0_PDEN);
+	}
+	falc_disable_comm(card, ch);
+	// EVENT_FALC_ABNORMAL
+	pfalc->loop_gen = 1;
+}
+
+/*----------------------------------------------------------------------------
+ * falc_generate_loop_down_code
+ *----------------------------------------------------------------------------
+ * Description:	This routine writes the proper FALC chip register in order
+ *		to generate a LOOP deactivation code over a T1/E1 line.
+ *----------------------------------------------------------------------------
+ */
+void falc_generate_loop_down_code(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+
+	if (conf->media == IF_IFACE_T1) {
+		cpc_writeb(falcbase + F_REG(FMR5, ch),
+			   cpc_readb(falcbase + F_REG(FMR5, ch)) | FMR5_XLD);
+	} else {
+		cpc_writeb(falcbase + F_REG(FMR3, ch),
+			   cpc_readb(falcbase + F_REG(FMR3, ch)) | FMR3_XLD);
+	}
+	pfalc->sync = 0;
+	cpc_writeb(falcbase + card->hw.cpld_reg2,
+		   cpc_readb(falcbase + card->hw.cpld_reg2) &
+		   ~(CPLD_REG2_FALC_LED2 << (2 * ch)));
+	pfalc->active = 0;
+//?    falc_issue_cmd(card, ch, CMDR_XRES);
+	pfalc->loop_gen = 0;
+}
+
+/*----------------------------------------------------------------------------
+ * falc_pattern_test
+ *----------------------------------------------------------------------------
+ * Description:	This routine generates a pattern code and checks
+ *		it on the reception side.
+ *----------------------------------------------------------------------------
+ */
+void falc_pattern_test(pc300_t * card, int ch, unsigned int activate)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+
+	if (activate) {
+		pfalc->prbs = 1;
+		pfalc->bec = 0;
+		if (conf->media == IF_IFACE_T1) {
+			/* Disable local loop activation/deactivation detect */
+			cpc_writeb(falcbase + F_REG(IMR3, ch),
+				   cpc_readb(falcbase + F_REG(IMR3, ch)) | IMR3_LLBSC);
+		} else {
+			/* Disable local loop activation/deactivation detect */
+			cpc_writeb(falcbase + F_REG(IMR1, ch),
+				   cpc_readb(falcbase + F_REG(IMR1, ch)) | IMR1_LLBSC);
+		}
+		/* Activates generation and monitoring of PRBS 
+		 * (Pseudo Random Bit Sequence) */
+		cpc_writeb(falcbase + F_REG(LCR1, ch),
+			   cpc_readb(falcbase + F_REG(LCR1, ch)) | LCR1_EPRM | LCR1_XPRBS);
+	} else {
+		pfalc->prbs = 0;
+		/* Deactivates generation and monitoring of PRBS 
+		 * (Pseudo Random Bit Sequence) */
+		cpc_writeb(falcbase + F_REG(LCR1, ch),
+			   cpc_readb(falcbase+F_REG(LCR1,ch)) & ~(LCR1_EPRM | LCR1_XPRBS));
+		if (conf->media == IF_IFACE_T1) {
+			/* Enable local loop activation/deactivation detect */
+			cpc_writeb(falcbase + F_REG(IMR3, ch),
+				   cpc_readb(falcbase + F_REG(IMR3, ch)) & ~IMR3_LLBSC);
+		} else {
+			/* Enable local loop activation/deactivation detect */
+			cpc_writeb(falcbase + F_REG(IMR1, ch),
+				   cpc_readb(falcbase + F_REG(IMR1, ch)) & ~IMR1_LLBSC);
+		}
+	}
+}
+
+/*----------------------------------------------------------------------------
+ * falc_pattern_test_error
+ *----------------------------------------------------------------------------
+ * Description:	This routine returns the bit error counter value
+ *----------------------------------------------------------------------------
+ */
+ucshort falc_pattern_test_error(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	falc_t *pfalc = (falc_t *) & chan->falc;
+
+	return (pfalc->bec);
+}
+
+/**********************************/
+/***   Net Interface Routines   ***/
+/**********************************/
+
+static void
+cpc_trace(struct net_device *dev, struct sk_buff *skb_main, char rx_tx)
+{
+	struct sk_buff *skb;
+
+	if ((skb = dev_alloc_skb(10 + skb_main->len)) == NULL) {
+		printk("%s: out of memory\n", dev->name);
+		return;
+	}
+	skb_put(skb, 10 + skb_main->len);
+
+	skb->dev = dev;
+	skb->protocol = htons(ETH_P_CUST);
+	skb->mac.raw = skb->data;
+	skb->pkt_type = PACKET_HOST;
+	skb->len = 10 + skb_main->len;
+
+	memcpy(skb->data, dev->name, 5);
+	skb->data[5] = '[';
+	skb->data[6] = rx_tx;
+	skb->data[7] = ']';
+	skb->data[8] = ':';
+	skb->data[9] = ' ';
+	memcpy(&skb->data[10], skb_main->data, skb_main->len);
+
+	netif_rx(skb);
+}
+
+void cpc_tx_timeout(struct net_device *dev)
+{
+	pc300dev_t *d = (pc300dev_t *) dev->priv;
+	pc300ch_t *chan = (pc300ch_t *) d->chan;
+	pc300_t *card = (pc300_t *) chan->card;
+	struct net_device_stats *stats = &d->hdlc->stats;
+	int ch = chan->channel;
+	uclong flags;
+	ucchar ilar;
+
+	stats->tx_errors++;
+	stats->tx_aborted_errors++;
+	CPC_LOCK(card, flags);
+	if ((ilar = cpc_readb(card->hw.scabase + ILAR)) != 0) {
+		printk("%s: ILAR=0x%x\n", dev->name, ilar);
+		cpc_writeb(card->hw.scabase + ILAR, ilar);
+		cpc_writeb(card->hw.scabase + DMER, 0x80);
+	}
+	if (card->hw.type == PC300_TE) {
+		cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
+			   cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) &
+			   ~(CPLD_REG2_FALC_LED1 << (2 * ch)));
+	}
+	dev->trans_start = jiffies;
+	CPC_UNLOCK(card, flags);
+	netif_wake_queue(dev);
+}
+
+int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	pc300dev_t *d = (pc300dev_t *) dev->priv;
+	pc300ch_t *chan = (pc300ch_t *) d->chan;
+	pc300_t *card = (pc300_t *) chan->card;
+	struct net_device_stats *stats = &d->hdlc->stats;
+	int ch = chan->channel;
+	uclong flags;
+#ifdef PC300_DEBUG_TX
+	int i;
+#endif
+
+	if (chan->conf.monitor) {
+		/* In monitor mode no Tx is done: ignore packet */
+		dev_kfree_skb(skb);
+		return 0;
+	} else if (!netif_carrier_ok(dev)) {
+		/* DCD must be OFF: drop packet */
+		dev_kfree_skb(skb);
+		stats->tx_errors++;
+		stats->tx_carrier_errors++;
+		return 0;
+	} else if (cpc_readb(card->hw.scabase + M_REG(ST3, ch)) & ST3_DCD) {
+		printk("%s: DCD is OFF. Going administrative down.\n", dev->name);
+		stats->tx_errors++;
+		stats->tx_carrier_errors++;
+		dev_kfree_skb(skb);
+		netif_carrier_off(dev);
+		CPC_LOCK(card, flags);
+		cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_BUF_CLR);
+		if (card->hw.type == PC300_TE) {
+			cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
+				   cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) & 
+				   			~(CPLD_REG2_FALC_LED1 << (2 * ch)));
+		}
+		CPC_UNLOCK(card, flags);
+		netif_wake_queue(dev);
+		return 0;
+	}
+
+	/* Write buffer to DMA buffers */
+	if (dma_buf_write(card, ch, (ucchar *) skb->data, skb->len) != 0) {
+//		printk("%s: write error. Dropping TX packet.\n", dev->name);
+		netif_stop_queue(dev);
+		dev_kfree_skb(skb);
+		stats->tx_errors++;
+		stats->tx_dropped++;
+		return 0;
+	}
+#ifdef PC300_DEBUG_TX
+	printk("%s T:", dev->name);
+	for (i = 0; i < skb->len; i++)
+		printk(" %02x", *(skb->data + i));
+	printk("\n");
+#endif
+
+	if (d->trace_on) {
+		cpc_trace(dev, skb, 'T');
+	}
+	dev->trans_start = jiffies;
+
+	/* Start transmission */
+	CPC_LOCK(card, flags);
+	/* verify if it has more than one free descriptor */
+	if (card->chan[ch].nfree_tx_bd <= 1) {
+		/* don't have so stop the queue */
+		netif_stop_queue(dev);
+	}
+	cpc_writel(card->hw.scabase + DTX_REG(EDAL, ch),
+		   TX_BD_ADDR(ch, chan->tx_next_bd));
+	cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_ENA);
+	cpc_writeb(card->hw.scabase + DSR_TX(ch), DSR_DE);
+	if (card->hw.type == PC300_TE) {
+		cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
+			   cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) |
+			   (CPLD_REG2_FALC_LED1 << (2 * ch)));
+	}
+	CPC_UNLOCK(card, flags);
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+void cpc_net_rx(hdlc_device * hdlc)
+{
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	pc300dev_t *d = (pc300dev_t *) dev->priv;
+	pc300ch_t *chan = (pc300ch_t *) d->chan;
+	pc300_t *card = (pc300_t *) chan->card;
+	struct net_device_stats *stats = &d->hdlc->stats;
+	int ch = chan->channel;
+#ifdef PC300_DEBUG_RX
+	int i;
+#endif
+	int rxb;
+	struct sk_buff *skb;
+
+	while (1) {
+		if ((rxb = dma_get_rx_frame_size(card, ch)) == -1)
+			return;
+
+		if (!netif_carrier_ok(dev)) {
+			/* DCD must be OFF: drop packet */
+		    printk("%s : DCD is OFF - drop %d rx bytes\n", dev->name, rxb); 
+			skb = NULL;
+		} else {
+			if (rxb > (dev->mtu + 40)) { /* add headers */
+				printk("%s : MTU exceeded %d\n", dev->name, rxb); 
+				skb = NULL;
+			} else {
+				skb = dev_alloc_skb(rxb);
+				if (skb == NULL) {
+					printk("%s: Memory squeeze!!\n", dev->name);
+					return;
+				}
+				skb->dev = dev;
+			}
+		}
+
+		if (((rxb = dma_buf_read(card, ch, skb)) <= 0) || (skb == NULL)) {
+#ifdef PC300_DEBUG_RX
+			printk("%s: rxb = %x\n", dev->name, rxb);
+#endif
+			if ((skb == NULL) && (rxb > 0)) {
+				/* rxb > dev->mtu */
+				stats->rx_errors++;
+				stats->rx_length_errors++;
+				continue;
+			}
+
+			if (rxb < 0) {	/* Invalid frame */
+				rxb = -rxb;
+				if (rxb & DST_OVR) {
+					stats->rx_errors++;
+					stats->rx_fifo_errors++;
+				}
+				if (rxb & DST_CRC) {
+					stats->rx_errors++;
+					stats->rx_crc_errors++;
+				}
+				if (rxb & (DST_RBIT | DST_SHRT | DST_ABT)) {
+					stats->rx_errors++;
+					stats->rx_frame_errors++;
+				}
+			}
+			if (skb) {
+				dev_kfree_skb_irq(skb);
+			}
+			continue;
+		}
+
+		stats->rx_bytes += rxb;
+
+#ifdef PC300_DEBUG_RX
+		printk("%s R:", dev->name);
+		for (i = 0; i < skb->len; i++)
+			printk(" %02x", *(skb->data + i));
+		printk("\n");
+#endif
+		if (d->trace_on) {
+			cpc_trace(dev, skb, 'R');
+		}
+		stats->rx_packets++;
+		skb->mac.raw = skb->data;
+		skb->protocol = htons(ETH_P_HDLC);
+		netif_rx(skb);
+	}
+}
+
+/************************************/
+/***   PC300 Interrupt Routines   ***/
+/************************************/
+static void sca_tx_intr(pc300dev_t *dev)
+{
+	pc300ch_t *chan = (pc300ch_t *)dev->chan; 
+	pc300_t *card = (pc300_t *)chan->card; 
+	int ch = chan->channel; 
+	volatile pcsca_bd_t * ptdescr; 
+	struct net_device_stats *stats = &dev->hdlc->stats; 
+
+    /* Clean up descriptors from previous transmission */
+	ptdescr = (pcsca_bd_t *)(card->hw.rambase +
+						TX_BD_ADDR(ch,chan->tx_first_bd));
+	while ((cpc_readl(card->hw.scabase + DTX_REG(CDAL,ch)) != 
+							TX_BD_ADDR(ch,chan->tx_first_bd)) && 
+			(cpc_readb(&ptdescr->status) & DST_OSB)) {
+		stats->tx_packets++;
+		stats->tx_bytes += cpc_readw(&ptdescr->len);
+		cpc_writeb(&ptdescr->status, DST_OSB);
+		cpc_writew(&ptdescr->len, 0);
+		chan->nfree_tx_bd++;
+		chan->tx_first_bd = (chan->tx_first_bd + 1) & (N_DMA_TX_BUF - 1);
+		ptdescr = (pcsca_bd_t *)(card->hw.rambase +
+						TX_BD_ADDR(ch,chan->tx_first_bd));
+    }
+
+#ifdef CONFIG_PC300_MLPPP
+	if (chan->conf.proto == PC300_PROTO_MLPPP) {
+			cpc_tty_trigger_poll(dev);
+	} else {
+#endif
+	/* Tell the upper layer we are ready to transmit more packets */
+		netif_wake_queue((struct net_device*)dev->hdlc);
+#ifdef CONFIG_PC300_MLPPP
+	}
+#endif
+}
+
+static void sca_intr(pc300_t * card)
+{
+	uclong scabase = card->hw.scabase;
+	volatile uclong status;
+	int ch;
+	int intr_count = 0;
+	unsigned char dsr_rx;
+
+	while ((status = cpc_readl(scabase + ISR0)) != 0) {
+		for (ch = 0; ch < card->hw.nchan; ch++) {
+			pc300ch_t *chan = &card->chan[ch];
+			pc300dev_t *d = &chan->d;
+			hdlc_device *hdlc = d->hdlc;
+			struct net_device *dev = hdlc_to_dev(hdlc);
+
+			spin_lock(&card->card_lock);
+
+	    /**** Reception ****/
+			if (status & IR0_DRX((IR0_DMIA | IR0_DMIB), ch)) {
+				ucchar drx_stat = cpc_readb(scabase + DSR_RX(ch));
+
+				/* Clear RX interrupts */
+				cpc_writeb(scabase + DSR_RX(ch), drx_stat | DSR_DWE);
+
+#ifdef PC300_DEBUG_INTR
+				printk ("sca_intr: RX intr chan[%d] (st=0x%08lx, dsr=0x%02x)\n",
+					 ch, status, drx_stat);
+#endif
+				if (status & IR0_DRX(IR0_DMIA, ch)) {
+					if (drx_stat & DSR_BOF) {
+#ifdef CONFIG_PC300_MLPPP
+						if (chan->conf.proto == PC300_PROTO_MLPPP) {
+							/* verify if driver is TTY */
+							if ((cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) {
+								rx_dma_stop(card, ch);
+							}
+							cpc_tty_receive(d);
+							rx_dma_start(card, ch);
+						} else 
+#endif
+						{
+							if ((cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) {
+								rx_dma_stop(card, ch);
+							}
+							cpc_net_rx(hdlc);
+							/* Discard invalid frames */
+							hdlc->stats.rx_errors++;
+							hdlc->stats.rx_over_errors++;
+							chan->rx_first_bd = 0;
+							chan->rx_last_bd = N_DMA_RX_BUF - 1;
+							rx_dma_start(card, ch);
+						}
+					}
+				}
+				if (status & IR0_DRX(IR0_DMIB, ch)) {
+					if (drx_stat & DSR_EOM) {
+						if (card->hw.type == PC300_TE) {
+							cpc_writeb(card->hw.falcbase +
+								   card->hw.cpld_reg2,
+								   cpc_readb (card->hw.falcbase +
+								    	card->hw.cpld_reg2) |
+								   (CPLD_REG2_FALC_LED1 << (2 * ch)));
+						}
+#ifdef CONFIG_PC300_MLPPP
+						if (chan->conf.proto == PC300_PROTO_MLPPP) {
+							/* verify if driver is TTY */
+							cpc_tty_receive(d);
+						} else {
+							cpc_net_rx(hdlc);
+						}
+#else
+						cpc_net_rx(hdlc);
+#endif
+						if (card->hw.type == PC300_TE) {
+							cpc_writeb(card->hw.falcbase +
+								   card->hw.cpld_reg2,
+								   cpc_readb (card->hw.falcbase +
+								    		card->hw.cpld_reg2) &
+								   ~ (CPLD_REG2_FALC_LED1 << (2 * ch)));
+						}
+					}
+				}
+				if (!(dsr_rx = cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) {
+
+printk("%s: RX intr chan[%d] (st=0x%08lx, dsr=0x%02x, dsr2=0x%02x)\n", 
+	dev->name, ch, status, drx_stat, dsr_rx);
+					cpc_writeb(scabase + DSR_RX(ch), (dsr_rx | DSR_DE) & 0xfe);
+				}
+			}
+
+	    /**** Transmission ****/
+			if (status & IR0_DTX((IR0_EFT | IR0_DMIA | IR0_DMIB), ch)) {
+				ucchar dtx_stat = cpc_readb(scabase + DSR_TX(ch));
+
+				/* Clear TX interrupts */
+				cpc_writeb(scabase + DSR_TX(ch), dtx_stat | DSR_DWE);
+
+#ifdef PC300_DEBUG_INTR
+				printk ("sca_intr: TX intr chan[%d] (st=0x%08lx, dsr=0x%02x)\n",
+					 ch, status, dtx_stat);
+#endif
+				if (status & IR0_DTX(IR0_EFT, ch)) {
+					if (dtx_stat & DSR_UDRF) {
+						if (cpc_readb (scabase + M_REG(TBN, ch)) != 0) {
+							cpc_writeb(scabase + M_REG(CMD,ch), CMD_TX_BUF_CLR);
+						}
+						if (card->hw.type == PC300_TE) {
+							cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
+								   cpc_readb (card->hw.falcbase + 
+										   card->hw.cpld_reg2) &
+								   ~ (CPLD_REG2_FALC_LED1 << (2 * ch)));
+						}
+						hdlc->stats.tx_errors++;
+						hdlc->stats.tx_fifo_errors++;
+						sca_tx_intr(d);
+					}
+				}
+				if (status & IR0_DTX(IR0_DMIA, ch)) {
+					if (dtx_stat & DSR_BOF) {
+					}
+				}
+				if (status & IR0_DTX(IR0_DMIB, ch)) {
+					if (dtx_stat & DSR_EOM) {
+						if (card->hw.type == PC300_TE) {
+							cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
+								   cpc_readb (card->hw.falcbase +
+								    			card->hw.cpld_reg2) &
+								   ~ (CPLD_REG2_FALC_LED1 << (2 * ch)));
+						}
+						sca_tx_intr(d);
+					}
+				}
+			}
+
+	    /**** MSCI ****/
+			if (status & IR0_M(IR0_RXINTA, ch)) {
+				ucchar st1 = cpc_readb(scabase + M_REG(ST1, ch));
+
+				/* Clear MSCI interrupts */
+				cpc_writeb(scabase + M_REG(ST1, ch), st1);
+
+#ifdef PC300_DEBUG_INTR
+				printk("sca_intr: MSCI intr chan[%d] (st=0x%08lx, st1=0x%02x)\n",
+					 ch, status, st1);
+#endif
+				if (st1 & ST1_CDCD) {	/* DCD changed */
+					if (cpc_readb(scabase + M_REG(ST3, ch)) & ST3_DCD) {
+						printk ("%s: DCD is OFF. Going administrative down.\n",
+							 dev->name);
+#ifdef CONFIG_PC300_MLPPP
+						if (chan->conf.proto != PC300_PROTO_MLPPP) {
+							netif_carrier_off(dev);
+						}
+#else
+						netif_carrier_off(dev);
+
+#endif
+						card->chan[ch].d.line_off++;
+					} else {	/* DCD = 1 */
+						printk ("%s: DCD is ON. Going administrative up.\n",
+							 dev->name);
+#ifdef CONFIG_PC300_MLPPP
+						if (chan->conf.proto != PC300_PROTO_MLPPP)
+							/* verify if driver is not TTY */
+#endif
+							netif_carrier_on(dev);
+						card->chan[ch].d.line_on++;
+					}
+				}
+			}
+			spin_unlock(&card->card_lock);
+		}
+		if (++intr_count == 10)
+			/* Too much work at this board. Force exit */
+			break;
+	}
+}
+
+static void falc_t1_loop_detection(pc300_t * card, int ch, ucchar frs1)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+
+	if (((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_XPRBS) == 0) &&
+	    !pfalc->loop_gen) {
+		if (frs1 & FRS1_LLBDD) {
+			// A Line Loop Back Deactivation signal detected
+			if (pfalc->loop_active) {
+				falc_remote_loop(card, ch, 0);
+			}
+		} else {
+			if ((frs1 & FRS1_LLBAD) &&
+			    ((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_EPRM) == 0)) {
+				// A Line Loop Back Activation signal detected  
+				if (!pfalc->loop_active) {
+					falc_remote_loop(card, ch, 1);
+				}
+			}
+		}
+	}
+}
+
+static void falc_e1_loop_detection(pc300_t * card, int ch, ucchar rsp)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+
+	if (((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_XPRBS) == 0) &&
+	    !pfalc->loop_gen) {
+		if (rsp & RSP_LLBDD) {
+			// A Line Loop Back Deactivation signal detected
+			if (pfalc->loop_active) {
+				falc_remote_loop(card, ch, 0);
+			}
+		} else {
+			if ((rsp & RSP_LLBAD) &&
+			    ((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_EPRM) == 0)) {
+				// A Line Loop Back Activation signal detected  
+				if (!pfalc->loop_active) {
+					falc_remote_loop(card, ch, 1);
+				}
+			}
+		}
+	}
+}
+
+static void falc_t1_intr(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+	ucchar isr0, isr3, gis;
+	ucchar dummy;
+
+	while ((gis = cpc_readb(falcbase + F_REG(GIS, ch))) != 0) {
+		if (gis & GIS_ISR0) {
+			isr0 = cpc_readb(falcbase + F_REG(FISR0, ch));
+			if (isr0 & FISR0_PDEN) {
+				/* Read the bit to clear the situation */
+				if (cpc_readb(falcbase + F_REG(FRS1, ch)) &
+				    FRS1_PDEN) {
+					pfalc->pden++;
+				}
+			}
+		}
+
+		if (gis & GIS_ISR1) {
+			dummy = cpc_readb(falcbase + F_REG(FISR1, ch));
+		}
+
+		if (gis & GIS_ISR2) {
+			dummy = cpc_readb(falcbase + F_REG(FISR2, ch));
+		}
+
+		if (gis & GIS_ISR3) {
+			isr3 = cpc_readb(falcbase + F_REG(FISR3, ch));
+			if (isr3 & FISR3_SEC) {
+				pfalc->sec++;
+				falc_update_stats(card, ch);
+				falc_check_status(card, ch,
+						  cpc_readb(falcbase + F_REG(FRS0, ch)));
+			}
+			if (isr3 & FISR3_ES) {
+				pfalc->es++;
+			}
+			if (isr3 & FISR3_LLBSC) {
+				falc_t1_loop_detection(card, ch,
+						       cpc_readb(falcbase + F_REG(FRS1, ch)));
+			}
+		}
+	}
+}
+
+static void falc_e1_intr(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong falcbase = card->hw.falcbase;
+	ucchar isr1, isr2, isr3, gis, rsp;
+	ucchar dummy;
+
+	while ((gis = cpc_readb(falcbase + F_REG(GIS, ch))) != 0) {
+		rsp = cpc_readb(falcbase + F_REG(RSP, ch));
+
+		if (gis & GIS_ISR0) {
+			dummy = cpc_readb(falcbase + F_REG(FISR0, ch));
+		}
+		if (gis & GIS_ISR1) {
+			isr1 = cpc_readb(falcbase + F_REG(FISR1, ch));
+			if (isr1 & FISR1_XMB) {
+				if ((pfalc->xmb_cause & 2)
+				    && pfalc->multiframe_mode) {
+					if (cpc_readb (falcbase + F_REG(FRS0, ch)) & 
+									(FRS0_LOS | FRS0_AIS | FRS0_LFA)) {
+						cpc_writeb(falcbase + F_REG(XSP, ch),
+							   cpc_readb(falcbase + F_REG(XSP, ch))
+							   & ~XSP_AXS);
+					} else {
+						cpc_writeb(falcbase + F_REG(XSP, ch),
+							   cpc_readb(falcbase + F_REG(XSP, ch))
+							   | XSP_AXS);
+					}
+				}
+				pfalc->xmb_cause = 0;
+				cpc_writeb(falcbase + F_REG(IMR1, ch),
+					   cpc_readb(falcbase + F_REG(IMR1, ch)) | IMR1_XMB);
+			}
+			if (isr1 & FISR1_LLBSC) {
+				falc_e1_loop_detection(card, ch, rsp);
+			}
+		}
+		if (gis & GIS_ISR2) {
+			isr2 = cpc_readb(falcbase + F_REG(FISR2, ch));
+			if (isr2 & FISR2_T400MS) {
+				cpc_writeb(falcbase + F_REG(XSW, ch),
+					   cpc_readb(falcbase + F_REG(XSW, ch)) | XSW_XRA);
+			}
+			if (isr2 & FISR2_MFAR) {
+				cpc_writeb(falcbase + F_REG(XSW, ch),
+					   cpc_readb(falcbase + F_REG(XSW, ch)) & ~XSW_XRA);
+			}
+			if (isr2 & (FISR2_FAR | FISR2_LFA | FISR2_AIS | FISR2_LOS)) {
+				pfalc->xmb_cause |= 2;
+				cpc_writeb(falcbase + F_REG(IMR1, ch),
+					   cpc_readb(falcbase + F_REG(IMR1, ch)) & ~IMR1_XMB);
+			}
+		}
+		if (gis & GIS_ISR3) {
+			isr3 = cpc_readb(falcbase + F_REG(FISR3, ch));
+			if (isr3 & FISR3_SEC) {
+				pfalc->sec++;
+				falc_update_stats(card, ch);
+				falc_check_status(card, ch,
+						  cpc_readb(falcbase + F_REG(FRS0, ch)));
+			}
+			if (isr3 & FISR3_ES) {
+				pfalc->es++;
+			}
+		}
+	}
+}
+
+static void falc_intr(pc300_t * card)
+{
+	int ch;
+
+	for (ch = 0; ch < card->hw.nchan; ch++) {
+		pc300ch_t *chan = &card->chan[ch];
+		pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+
+		if (conf->media == IF_IFACE_T1) {
+			falc_t1_intr(card, ch);
+		} else {
+			falc_e1_intr(card, ch);
+		}
+	}
+}
+
+static void cpc_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	pc300_t *card;
+	volatile ucchar plx_status;
+
+	if ((card = (pc300_t *) dev_id) == 0) {
+#ifdef PC300_DEBUG_INTR
+		printk("cpc_intr: spurious intr %d\n", irq);
+#endif
+		return;		/* spurious intr */
+	}
+
+	if (card->hw.rambase == 0) {
+#ifdef PC300_DEBUG_INTR
+		printk("cpc_intr: spurious intr2 %d\n", irq);
+#endif
+		return;		/* spurious intr */
+	}
+
+	switch (card->hw.type) {
+		case PC300_RSV:
+		case PC300_X21:
+			sca_intr(card);
+			break;
+
+		case PC300_TE:
+			while ( (plx_status = (cpc_readb(card->hw.plxbase + card->hw.intctl_reg) &
+				 (PLX_9050_LINT1_STATUS | PLX_9050_LINT2_STATUS))) != 0) {
+				if (plx_status & PLX_9050_LINT1_STATUS) {	/* SCA Interrupt */
+					sca_intr(card);
+				}
+				if (plx_status & PLX_9050_LINT2_STATUS) {	/* FALC Interrupt */
+					falc_intr(card);
+				}
+			}
+			break;
+	}
+}
+
+void cpc_sca_status(pc300_t * card, int ch)
+{
+	ucchar ilar;
+	uclong scabase = card->hw.scabase;
+	uclong flags;
+
+	tx_dma_buf_check(card, ch);
+	rx_dma_buf_check(card, ch);
+	ilar = cpc_readb(scabase + ILAR);
+	printk ("ILAR=0x%02x, WCRL=0x%02x, PCR=0x%02x, BTCR=0x%02x, BOLR=0x%02x\n",
+		 ilar, cpc_readb(scabase + WCRL), cpc_readb(scabase + PCR),
+		 cpc_readb(scabase + BTCR), cpc_readb(scabase + BOLR));
+	printk("TX_CDA=0x%08lx, TX_EDA=0x%08lx\n",
+	       (uclong) cpc_readl(scabase + DTX_REG(CDAL, ch)),
+	       (uclong) cpc_readl(scabase + DTX_REG(EDAL, ch)));
+	printk("RX_CDA=0x%08lx, RX_EDA=0x%08lx, BFL=0x%04x\n",
+	       (uclong) cpc_readl(scabase + DRX_REG(CDAL, ch)),
+	       (uclong) cpc_readl(scabase + DRX_REG(EDAL, ch)),
+	       cpc_readw(scabase + DRX_REG(BFLL, ch)));
+	printk("DMER=0x%02x, DSR_TX=0x%02x, DSR_RX=0x%02x\n",
+	       cpc_readb(scabase + DMER), cpc_readb(scabase + DSR_TX(ch)),
+	       cpc_readb(scabase + DSR_RX(ch)));
+	printk("DMR_TX=0x%02x, DMR_RX=0x%02x, DIR_TX=0x%02x, DIR_RX=0x%02x\n",
+	       cpc_readb(scabase + DMR_TX(ch)), cpc_readb(scabase + DMR_RX(ch)),
+	       cpc_readb(scabase + DIR_TX(ch)),
+	       cpc_readb(scabase + DIR_RX(ch)));
+	printk("DCR_TX=0x%02x, DCR_RX=0x%02x, FCT_TX=0x%02x, FCT_RX=0x%02x\n",
+	       cpc_readb(scabase + DCR_TX(ch)), cpc_readb(scabase + DCR_RX(ch)),
+	       cpc_readb(scabase + FCT_TX(ch)),
+	       cpc_readb(scabase + FCT_RX(ch)));
+	printk("MD0=0x%02x, MD1=0x%02x, MD2=0x%02x, MD3=0x%02x, IDL=0x%02x\n",
+	       cpc_readb(scabase + M_REG(MD0, ch)),
+	       cpc_readb(scabase + M_REG(MD1, ch)),
+	       cpc_readb(scabase + M_REG(MD2, ch)),
+	       cpc_readb(scabase + M_REG(MD3, ch)),
+	       cpc_readb(scabase + M_REG(IDL, ch)));
+	printk("CMD=0x%02x, SA0=0x%02x, SA1=0x%02x, TFN=0x%02x, CTL=0x%02x\n",
+	       cpc_readb(scabase + M_REG(CMD, ch)),
+	       cpc_readb(scabase + M_REG(SA0, ch)),
+	       cpc_readb(scabase + M_REG(SA1, ch)),
+	       cpc_readb(scabase + M_REG(TFN, ch)),
+	       cpc_readb(scabase + M_REG(CTL, ch)));
+	printk("ST0=0x%02x, ST1=0x%02x, ST2=0x%02x, ST3=0x%02x, ST4=0x%02x\n",
+	       cpc_readb(scabase + M_REG(ST0, ch)),
+	       cpc_readb(scabase + M_REG(ST1, ch)),
+	       cpc_readb(scabase + M_REG(ST2, ch)),
+	       cpc_readb(scabase + M_REG(ST3, ch)),
+	       cpc_readb(scabase + M_REG(ST4, ch)));
+	printk ("CST0=0x%02x, CST1=0x%02x, CST2=0x%02x, CST3=0x%02x, FST=0x%02x\n",
+		 cpc_readb(scabase + M_REG(CST0, ch)),
+		 cpc_readb(scabase + M_REG(CST1, ch)),
+		 cpc_readb(scabase + M_REG(CST2, ch)),
+		 cpc_readb(scabase + M_REG(CST3, ch)),
+		 cpc_readb(scabase + M_REG(FST, ch)));
+	printk("TRC0=0x%02x, TRC1=0x%02x, RRC=0x%02x, TBN=0x%02x, RBN=0x%02x\n",
+	       cpc_readb(scabase + M_REG(TRC0, ch)),
+	       cpc_readb(scabase + M_REG(TRC1, ch)),
+	       cpc_readb(scabase + M_REG(RRC, ch)),
+	       cpc_readb(scabase + M_REG(TBN, ch)),
+	       cpc_readb(scabase + M_REG(RBN, ch)));
+	printk("TFS=0x%02x, TNR0=0x%02x, TNR1=0x%02x, RNR=0x%02x\n",
+	       cpc_readb(scabase + M_REG(TFS, ch)),
+	       cpc_readb(scabase + M_REG(TNR0, ch)),
+	       cpc_readb(scabase + M_REG(TNR1, ch)),
+	       cpc_readb(scabase + M_REG(RNR, ch)));
+	printk("TCR=0x%02x, RCR=0x%02x, TNR1=0x%02x, RNR=0x%02x\n",
+	       cpc_readb(scabase + M_REG(TCR, ch)),
+	       cpc_readb(scabase + M_REG(RCR, ch)),
+	       cpc_readb(scabase + M_REG(TNR1, ch)),
+	       cpc_readb(scabase + M_REG(RNR, ch)));
+	printk("TXS=0x%02x, RXS=0x%02x, EXS=0x%02x, TMCT=0x%02x, TMCR=0x%02x\n",
+	       cpc_readb(scabase + M_REG(TXS, ch)),
+	       cpc_readb(scabase + M_REG(RXS, ch)),
+	       cpc_readb(scabase + M_REG(EXS, ch)),
+	       cpc_readb(scabase + M_REG(TMCT, ch)),
+	       cpc_readb(scabase + M_REG(TMCR, ch)));
+	printk("IE0=0x%02x, IE1=0x%02x, IE2=0x%02x, IE4=0x%02x, FIE=0x%02x\n",
+	       cpc_readb(scabase + M_REG(IE0, ch)),
+	       cpc_readb(scabase + M_REG(IE1, ch)),
+	       cpc_readb(scabase + M_REG(IE2, ch)),
+	       cpc_readb(scabase + M_REG(IE4, ch)),
+	       cpc_readb(scabase + M_REG(FIE, ch)));
+	printk("IER0=0x%08lx\n", (uclong) cpc_readl(scabase + IER0));
+
+	if (ilar != 0) {
+		CPC_LOCK(card, flags);
+		cpc_writeb(scabase + ILAR, ilar);
+		cpc_writeb(scabase + DMER, 0x80);
+		CPC_UNLOCK(card, flags);
+	}
+}
+
+void cpc_falc_status(pc300_t * card, int ch)
+{
+	pc300ch_t *chan = &card->chan[ch];
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	uclong flags;
+
+	CPC_LOCK(card, flags);
+	printk("CH%d:   %s %s  %d channels\n",
+	       ch, (pfalc->sync ? "SYNC" : ""), (pfalc->active ? "ACTIVE" : ""),
+	       pfalc->num_channels);
+
+	printk("        pden=%d,  los=%d,  losr=%d,  lfa=%d,  farec=%d\n",
+	       pfalc->pden, pfalc->los, pfalc->losr, pfalc->lfa, pfalc->farec);
+	printk("        lmfa=%d,  ais=%d,  sec=%d,  es=%d,  rai=%d\n",
+	       pfalc->lmfa, pfalc->ais, pfalc->sec, pfalc->es, pfalc->rai);
+	printk("        bec=%d,  fec=%d,  cvc=%d,  cec=%d,  ebc=%d\n",
+	       pfalc->bec, pfalc->fec, pfalc->cvc, pfalc->cec, pfalc->ebc);
+
+	printk("\n");
+	printk("        STATUS: %s  %s  %s  %s  %s  %s\n",
+	       (pfalc->red_alarm ? "RED" : ""),
+	       (pfalc->blue_alarm ? "BLU" : ""),
+	       (pfalc->yellow_alarm ? "YEL" : ""),
+	       (pfalc->loss_fa ? "LFA" : ""),
+	       (pfalc->loss_mfa ? "LMF" : ""), (pfalc->prbs ? "PRB" : ""));
+	CPC_UNLOCK(card, flags);
+}
+
+int cpc_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 128) || (new_mtu > PC300_DEF_MTU))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+	pc300dev_t *d = (pc300dev_t *) dev->priv;
+	pc300ch_t *chan = (pc300ch_t *) d->chan;
+	pc300_t *card = (pc300_t *) chan->card;
+	pc300conf_t conf_aux;
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	int ch = chan->channel;
+	void *arg = (void *) ifr->ifr_data;
+	union line_settings * line = &ifr->ifr_settings->ifs_line;
+	uclong scabase = card->hw.scabase;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	switch (cmd) {
+		case SIOCGPC300CONF:
+#ifdef CONFIG_PC300_MLPPP
+			if (conf->proto != PC300_PROTO_MLPPP) {
+				conf->proto = hdlc->proto;
+			}
+#else
+			conf->proto = hdlc->proto;
+#endif
+			memcpy(&conf_aux.conf, conf, sizeof(pc300chconf_t));
+			memcpy(&conf_aux.hw, &card->hw, sizeof(pc300hw_t));
+			if (!arg || 
+				copy_to_user(arg, &conf_aux, sizeof(pc300conf_t))) 
+				return -EINVAL;
+			return 0;
+		case SIOCSPC300CONF:
+			if (!suser())
+				return -EPERM;
+			if (!arg || 
+				copy_from_user(&conf_aux.conf, arg, sizeof(pc300chconf_t)))
+				return -EINVAL;
+			if (card->hw.cpld_id < 0x02 &&
+			    conf_aux.conf.fr_mode == PC300_FR_UNFRAMED) {
+				/* CPLD_ID < 0x02 doesn't support Unframed E1 */
+				return -EINVAL;
+			}
+#ifdef CONFIG_PC300_MLPPP
+			if (conf_aux.conf.proto == PC300_PROTO_MLPPP) {
+				if (conf->proto != PC300_PROTO_MLPPP) {
+					memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
+					cpc_tty_init(d);	/* init TTY driver */
+				}
+			} else {
+				if (conf_aux.conf.proto == 0xffff) {
+					if (conf->proto == PC300_PROTO_MLPPP){ 
+						/* ifdown interface */
+						cpc_close(dev);
+					}
+				} else {
+					memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
+					hdlc->proto = conf->proto;
+				}
+			}
+#else
+			memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
+			hdlc->proto = conf->proto;
+#endif
+			return 0;
+		case SIOCGPC300STATUS:
+			cpc_sca_status(card, ch);
+			return 0;
+		case SIOCGPC300FALCSTATUS:
+			cpc_falc_status(card, ch);
+			return 0;
+
+		case SIOCGPC300UTILSTATS:
+			{
+				if (!arg) {	/* clear statistics */
+					memset(&hdlc->stats, 0, sizeof(struct net_device_stats));
+					if (card->hw.type == PC300_TE) {
+						memset(&chan->falc, 0, sizeof(falc_t));
+					}
+				} else {
+					pc300stats_t pc300stats;
+
+					memset(&pc300stats, 0, sizeof(pc300stats_t));
+					pc300stats.hw_type = card->hw.type;
+					pc300stats.line_on = card->chan[ch].d.line_on;
+					pc300stats.line_off = card->chan[ch].d.line_off;
+					memcpy(&pc300stats.gen_stats, &hdlc->stats,
+					       sizeof(struct net_device_stats));
+					if (card->hw.type == PC300_TE)
+						memcpy(&pc300stats.te_stats,&chan->falc,sizeof(falc_t));
+				    copy_to_user(arg, &pc300stats, sizeof(pc300stats_t));
+				}
+				return 0;
+			}
+
+		case SIOCGPC300UTILSTATUS:
+			{
+				struct pc300status pc300status;
+
+				pc300status.hw_type = card->hw.type;
+				if (card->hw.type == PC300_TE) {
+					pc300status.te_status.sync = chan->falc.sync;
+					pc300status.te_status.red_alarm = chan->falc.red_alarm;
+					pc300status.te_status.blue_alarm = chan->falc.blue_alarm;
+					pc300status.te_status.loss_fa = chan->falc.loss_fa;
+					pc300status.te_status.yellow_alarm =chan->falc.yellow_alarm;
+					pc300status.te_status.loss_mfa = chan->falc.loss_mfa;
+					pc300status.te_status.prbs = chan->falc.prbs;
+				} else {
+					pc300status.gen_status.dcd =
+						!(cpc_readb (scabase + M_REG(ST3, ch)) & ST3_DCD);
+					pc300status.gen_status.cts =
+						!(cpc_readb (scabase + M_REG(ST3, ch)) & ST3_CTS);
+					pc300status.gen_status.rts =
+						!(cpc_readb (scabase + M_REG(CTL, ch)) & CTL_RTS);
+					pc300status.gen_status.dtr =
+						!(cpc_readb (scabase + M_REG(CTL, ch)) & CTL_DTR);
+					/* There is no DSR in HD64572 */
+				}
+				if (!arg
+				    || copy_to_user(arg, &pc300status, sizeof(pc300status_t)))
+						return -EINVAL;
+				return 0;
+			}
+
+		case SIOCSPC300TRACE:
+			/* Sets/resets a trace_flag for the respective device */
+			if (!arg || copy_from_user(&d->trace_on, arg,sizeof(unsigned char)))
+					return -EINVAL;
+			return 0;
+
+		case SIOCSPC300LOOPBACK:
+			{
+				struct pc300loopback pc300loop;
+
+				/* TE boards only */
+				if (card->hw.type != PC300_TE)
+					return -EINVAL;
+
+				if (!arg || 
+					copy_from_user(&pc300loop, arg, sizeof(pc300loopback_t)))
+						return -EINVAL;
+				switch (pc300loop.loop_type) {
+					case PC300LOCLOOP:	/* Turn the local loop on/off */
+						falc_local_loop(card, ch, pc300loop.loop_on);
+						return 0;
+
+					case PC300REMLOOP:	/* Turn the remote loop on/off */
+						falc_remote_loop(card, ch, pc300loop.loop_on);
+						return 0;
+
+					case PC300PAYLOADLOOP:	/* Turn the payload loop on/off */
+						falc_payload_loop(card, ch, pc300loop.loop_on);
+						return 0;
+
+					case PC300GENLOOPUP:	/* Generate loop UP */
+						if (pc300loop.loop_on) {
+							falc_generate_loop_up_code (card, ch);
+						} else {
+							turn_off_xlu(card, ch);
+						}
+						return 0;
+
+					case PC300GENLOOPDOWN:	/* Generate loop DOWN */
+						if (pc300loop.loop_on) {
+							falc_generate_loop_down_code (card, ch);
+						} else {
+							turn_off_xld(card, ch);
+						}
+						return 0;
+
+					default:
+						return -EINVAL;
+				}
+			}
+
+		case SIOCSPC300PATTERNTEST:
+			/* Turn the pattern test on/off and show the errors counter */
+			{
+				struct pc300patterntst pc300patrntst;
+
+				/* TE boards only */
+				if (card->hw.type != PC300_TE)
+					return -EINVAL;
+
+				if (card->hw.cpld_id < 0x02) {
+					/* CPLD_ID < 0x02 doesn't support pattern test */
+					return -EINVAL;
+				}
+
+				if (!arg || 
+					copy_from_user(&pc300patrntst,arg,sizeof(pc300patterntst_t)))
+						return -EINVAL;
+				if (pc300patrntst.patrntst_on == 2) {
+					if (chan->falc.prbs == 0) {
+						falc_pattern_test(card, ch, 1);
+					}
+					pc300patrntst.num_errors =
+						falc_pattern_test_error(card, ch);
+					if (!arg
+					    || copy_to_user(arg, &pc300patrntst,
+							    sizeof (pc300patterntst_t)))
+							return -EINVAL;
+				} else {
+					falc_pattern_test(card, ch, pc300patrntst.patrntst_on);
+				}
+				return 0;
+			}
+
+		case SIOCWANDEV:
+			switch (ifr->ifr_settings->type) {
+				case IF_GET_IFACE:
+				{
+					const size_t size = sizeof(sync_serial_settings);
+					ifr->ifr_settings->type = conf->media;
+	
+					if (copy_to_user(&line->sync, &conf->phys_settings, size)) {
+						return -EFAULT;
+					}
+					return 0;
+				}
+
+				case IF_IFACE_V35:
+				case IF_IFACE_V24:
+				case IF_IFACE_X21:
+				{
+					const size_t size = sizeof(sync_serial_settings);
+
+					if (!capable(CAP_NET_ADMIN)) {
+						return -EPERM;
+					}
+
+					if (copy_from_user(&conf->phys_settings, 
+									   &line->sync, size)) {
+						return -EFAULT;
+					}
+
+					if (conf->phys_settings.loopback) {
+						cpc_writeb(card->hw.scabase + M_REG(MD2, ch),
+							cpc_readb(card->hw.scabase + M_REG(MD2, ch)) | 
+							MD2_LOOP_MIR);
+					}
+					conf->media = ifr->ifr_settings->type;
+					return 0;
+				}
+
+				case IF_IFACE_T1:
+				case IF_IFACE_E1:
+				{
+					const size_t size = sizeof(sync_serial_settings);
+
+					if (!capable(CAP_NET_ADMIN)) {
+						return -EPERM;
+					}
+					
+					if (copy_from_user(&conf->phys_settings, 
+						&line->te1, size)) {
+						return -EFAULT;
+					}/* Ignoring HDLC slot_map for a while */
+					
+					if (conf->phys_settings.loopback) {
+						cpc_writeb(card->hw.scabase + M_REG(MD2, ch),
+							cpc_readb(card->hw.scabase + M_REG(MD2, ch)) | 
+							MD2_LOOP_MIR);
+					}
+					conf->media = ifr->ifr_settings->type;
+					return 0;
+				}
+				default:
+					return hdlc_ioctl(dev, ifr, cmd);
+			}
+
+		default:
+			return hdlc_ioctl(dev, ifr, cmd);
+	}
+}
+
+static struct net_device_stats *cpc_get_stats(struct net_device *dev)
+{
+	pc300dev_t *d = (pc300dev_t *) dev->priv;
+
+	if (d)
+		return &d->hdlc->stats;
+	else
+		return NULL;
+}
+
+static int clock_rate_calc(uclong rate, uclong clock, int *br_io)
+{
+	int br, tc;
+	int br_pwr, error;
+
+	if (rate == 0)
+		return (0);
+
+	for (br = 0, br_pwr = 1; br <= 9; br++, br_pwr <<= 1) {
+		if ((tc = clock / br_pwr / rate) <= 0xff) {
+			*br_io = br;
+			break;
+		}
+	}
+
+	if (tc <= 0xff) {
+		error = ((rate - (clock / br_pwr / rate)) / rate) * 1000;
+		/* Errors bigger than +/- 1% won't be tolerated */
+		if (error < -10 || error > 10)
+			return (-1);
+		else
+			return (tc);
+	} else {
+		return (-1);
+	}
+}
+
+int ch_config(pc300dev_t * d)
+{
+	pc300ch_t *chan = (pc300ch_t *) d->chan;
+	pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
+	pc300_t *card = (pc300_t *) chan->card;
+	uclong scabase = card->hw.scabase;
+	uclong plxbase = card->hw.plxbase;
+	int ch = chan->channel;
+	uclong clkrate = chan->conf.phys_settings.clock_rate;
+	uclong clktype = chan->conf.phys_settings.clock_type;
+	ucshort encoding = chan->conf.proto_settings.encoding;
+	ucshort parity = chan->conf.proto_settings.parity;   
+	int tmc, br;
+	ucchar md0, md2;
+    
+	/* Reset the channel */
+	cpc_writeb(scabase + M_REG(CMD, ch), CMD_CH_RST);
+
+	/* Configure the SCA registers */
+	switch (parity) {
+		case PARITY_NONE:
+			md0 = MD0_BIT_SYNC;
+			break;
+		case PARITY_CRC16_PR0:
+			md0 = MD0_CRC16_0|MD0_CRCC0|MD0_BIT_SYNC;
+			break;
+		case PARITY_CRC16_PR1:
+			md0 = MD0_CRC16_1|MD0_CRCC0|MD0_BIT_SYNC;
+			break;
+		case PARITY_CRC32_PR1_CCITT:
+			md0 = MD0_CRC32|MD0_CRCC0|MD0_BIT_SYNC;
+			break;
+		case PARITY_CRC16_PR1_CCITT:
+		default:
+			md0 = MD0_CRC_CCITT|MD0_CRCC0|MD0_BIT_SYNC;
+			break;
+	}
+	switch (encoding) {
+		case ENCODING_NRZI:
+			md2 = MD2_F_DUPLEX|MD2_ADPLL_X8|MD2_NRZI;
+			break;
+		case ENCODING_FM_MARK:	/* FM1 */
+			md2 = MD2_F_DUPLEX|MD2_ADPLL_X8|MD2_FM|MD2_FM1;
+			break;
+		case ENCODING_FM_SPACE:	/* FM0 */
+			md2 = MD2_F_DUPLEX|MD2_ADPLL_X8|MD2_FM|MD2_FM0;
+			break;
+		case ENCODING_MANCHESTER: /* It's not working... */
+			md2 = MD2_F_DUPLEX|MD2_ADPLL_X8|MD2_FM|MD2_MANCH;
+			break;
+		case ENCODING_NRZ:
+		default:
+			md2 = MD2_F_DUPLEX|MD2_ADPLL_X8|MD2_NRZ;
+			break;
+	}
+	cpc_writeb(scabase + M_REG(MD0, ch), md0);
+	cpc_writeb(scabase + M_REG(MD1, ch), 0);
+	cpc_writeb(scabase + M_REG(MD2, ch), md2);
+ 	cpc_writeb(scabase + M_REG(IDL, ch), 0x7e);
+	cpc_writeb(scabase + M_REG(CTL, ch), CTL_URSKP | CTL_IDLC);
+
+	/* Configure HW media */
+	switch (card->hw.type) {
+		case PC300_RSV:
+			if (conf->media == IF_IFACE_V35) {
+				cpc_writel((plxbase + card->hw.gpioc_reg),
+					   cpc_readl(plxbase + card->hw.gpioc_reg) | PC300_CHMEDIA_MASK(ch));
+			} else {
+				cpc_writel((plxbase + card->hw.gpioc_reg),
+					   cpc_readl(plxbase + card->hw.gpioc_reg) & ~PC300_CHMEDIA_MASK(ch));
+			}
+			break;
+
+		case PC300_X21:
+			break;
+
+		case PC300_TE:
+			te_config(card, ch);
+			break;
+	}
+
+	switch (card->hw.type) {
+		case PC300_RSV:
+		case PC300_X21:
+			if (clktype == CLOCK_INT || clktype == CLOCK_TXINT) {
+				/* Calculate the clkrate parameters */
+				tmc = clock_rate_calc(clkrate, card->hw.clock, &br);
+				cpc_writeb(scabase + M_REG(TMCT, ch), tmc);
+				cpc_writeb(scabase + M_REG(TXS, ch),
+					   (TXS_DTRXC | TXS_IBRG | br));
+				if (clktype == CLOCK_INT) {
+					cpc_writeb(scabase + M_REG(TMCR, ch), tmc);
+					cpc_writeb(scabase + M_REG(RXS, ch), 
+						   (RXS_IBRG | br));
+				} else {
+					cpc_writeb(scabase + M_REG(TMCR, ch), 1);
+					cpc_writeb(scabase + M_REG(RXS, ch), 0);
+				}
+	    			if (card->hw.type == PC300_X21) {
+					cpc_writeb(scabase + M_REG(GPO, ch), 1);
+					cpc_writeb(scabase + M_REG(EXS, ch), EXS_TES1 | EXS_RES1);
+				} else {
+					cpc_writeb(scabase + M_REG(EXS, ch), EXS_TES1);
+				}
+			} else {
+				cpc_writeb(scabase + M_REG(TMCT, ch), 1);
+				if (clktype == CLOCK_EXT) {
+					cpc_writeb(scabase + M_REG(TXS, ch), 
+						   TXS_DTRXC);
+				} else {
+					cpc_writeb(scabase + M_REG(TXS, ch), 
+						   TXS_DTRXC|TXS_RCLK);
+				}
+	    			cpc_writeb(scabase + M_REG(TMCR, ch), 1);
+				cpc_writeb(scabase + M_REG(RXS, ch), 0);
+				if (card->hw.type == PC300_X21) {
+					cpc_writeb(scabase + M_REG(GPO, ch), 0);
+					cpc_writeb(scabase + M_REG(EXS, ch), EXS_TES1 | EXS_RES1);
+				} else {
+					cpc_writeb(scabase + M_REG(EXS, ch), EXS_TES1);
+				}
+			}
+			break;
+
+		case PC300_TE:
+			/* SCA always receives clock from the FALC chip */
+			cpc_writeb(scabase + M_REG(TMCT, ch), 1);
+			cpc_writeb(scabase + M_REG(TXS, ch), 0);
+			cpc_writeb(scabase + M_REG(TMCR, ch), 1);
+			cpc_writeb(scabase + M_REG(RXS, ch), 0);
+			cpc_writeb(scabase + M_REG(EXS, ch), 0);
+			break;
+	}
+
+	/* Enable Interrupts */
+	cpc_writel(scabase + IER0,
+		   cpc_readl(scabase + IER0) |
+		   IR0_M(IR0_RXINTA, ch) |
+		   IR0_DRX(IR0_EFT | IR0_DMIA | IR0_DMIB, ch) |
+		   IR0_DTX(IR0_EFT | IR0_DMIA | IR0_DMIB, ch));
+	cpc_writeb(scabase + M_REG(IE0, ch),
+		   cpc_readl(scabase + M_REG(IE0, ch)) | IE0_RXINTA);
+	cpc_writeb(scabase + M_REG(IE1, ch),
+		   cpc_readl(scabase + M_REG(IE1, ch)) | IE1_CDCD);
+
+	return 0;
+}
+
+int rx_config(pc300dev_t * d)
+{
+	pc300ch_t *chan = (pc300ch_t *) d->chan;
+	pc300_t *card = (pc300_t *) chan->card;
+	uclong scabase = card->hw.scabase;
+	int ch = chan->channel;
+
+	cpc_writeb(scabase + DSR_RX(ch), 0);
+
+	/* General RX settings */
+	cpc_writeb(scabase + M_REG(RRC, ch), 0);
+	cpc_writeb(scabase + M_REG(RNR, ch), 16);
+
+	/* Enable reception */
+	cpc_writeb(scabase + M_REG(CMD, ch), CMD_RX_CRC_INIT);
+	cpc_writeb(scabase + M_REG(CMD, ch), CMD_RX_ENA);
+
+	/* Initialize DMA stuff */
+	chan->rx_first_bd = 0;
+	chan->rx_last_bd = N_DMA_RX_BUF - 1;
+	rx_dma_buf_init(card, ch);
+	cpc_writeb(scabase + DCR_RX(ch), DCR_FCT_CLR);
+	cpc_writeb(scabase + DMR_RX(ch), (DMR_TMOD | DMR_NF));
+	cpc_writeb(scabase + DIR_RX(ch), (DIR_EOM | DIR_BOF));
+
+	/* Start DMA */
+	rx_dma_start(card, ch);
+
+	return 0;
+}
+
+int tx_config(pc300dev_t * d)
+{
+	pc300ch_t *chan = (pc300ch_t *) d->chan;
+	pc300_t *card = (pc300_t *) chan->card;
+	uclong scabase = card->hw.scabase;
+	int ch = chan->channel;
+
+	cpc_writeb(scabase + DSR_TX(ch), 0);
+
+	/* General TX settings */
+	cpc_writeb(scabase + M_REG(TRC0, ch), 0);
+	cpc_writeb(scabase + M_REG(TFS, ch), 32);
+	cpc_writeb(scabase + M_REG(TNR0, ch), 20);
+	cpc_writeb(scabase + M_REG(TNR1, ch), 48);
+	cpc_writeb(scabase + M_REG(TCR, ch), 8);
+
+	/* Enable transmission */
+	cpc_writeb(scabase + M_REG(CMD, ch), CMD_TX_CRC_INIT);
+
+	/* Initialize DMA stuff */
+	chan->tx_first_bd = 0;
+	chan->tx_next_bd = 0;
+	tx_dma_buf_init(card, ch);
+	cpc_writeb(scabase + DCR_TX(ch), DCR_FCT_CLR);
+	cpc_writeb(scabase + DMR_TX(ch), (DMR_TMOD | DMR_NF));
+	cpc_writeb(scabase + DIR_TX(ch), (DIR_EOM | DIR_BOF | DIR_UDRF));
+	cpc_writel(scabase + DTX_REG(CDAL, ch), TX_BD_ADDR(ch, chan->tx_first_bd));
+	cpc_writel(scabase + DTX_REG(EDAL, ch), TX_BD_ADDR(ch, chan->tx_next_bd));
+
+	return 0;
+}
+
+static int cpc_attach(hdlc_device * hdlc, unsigned short encoding,
+		      unsigned short parity)
+{
+	struct net_device * dev = hdlc_to_dev(hdlc);
+	pc300dev_t *d = (pc300dev_t *)dev->priv;
+	pc300ch_t *chan = (pc300ch_t *)d->chan;
+	pc300_t *card = (pc300_t *)chan->card;
+	pc300chconf_t *conf = (pc300chconf_t *)&chan->conf;
+
+	if (card->hw.type == PC300_TE) {
+		if (encoding != ENCODING_NRZ && encoding != ENCODING_NRZI) {
+			return -EINVAL;
+		}
+	} else {
+		if (encoding != ENCODING_NRZ && encoding != ENCODING_NRZI &&
+		    encoding != ENCODING_FM_MARK && encoding != ENCODING_FM_SPACE) {
+			/* Driver doesn't support ENCODING_MANCHESTER yet */
+			return -EINVAL;
+		}
+	}
+
+	if (parity != PARITY_NONE && parity != PARITY_CRC16_PR0 &&
+	    parity != PARITY_CRC16_PR1 && parity != PARITY_CRC32_PR1_CCITT &&
+	    parity != PARITY_CRC16_PR1_CCITT) {
+		return -EINVAL;
+	}
+
+	conf->proto_settings.encoding = encoding;
+	conf->proto_settings.parity = parity;
+	return 0;
+}
+
+void cpc_opench(pc300dev_t * d)
+{
+	pc300ch_t *chan = (pc300ch_t *) d->chan;
+	pc300_t *card = (pc300_t *) chan->card;
+	int ch = chan->channel;
+	uclong scabase = card->hw.scabase;
+
+	ch_config(d);
+
+	rx_config(d);
+
+	tx_config(d);
+
+	/* Assert RTS and DTR */
+	cpc_writeb(scabase + M_REG(CTL, ch),
+		   cpc_readb(scabase + M_REG(CTL, ch)) & ~(CTL_RTS | CTL_DTR));
+}
+
+void cpc_closech(pc300dev_t * d)
+{
+	pc300ch_t *chan = (pc300ch_t *) d->chan;
+	pc300_t *card = (pc300_t *) chan->card;
+	falc_t *pfalc = (falc_t *) & chan->falc;
+	int ch = chan->channel;
+
+	cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_CH_RST);
+	rx_dma_stop(card, ch);
+	tx_dma_stop(card, ch);
+
+	if (card->hw.type == PC300_TE) {
+		memset(pfalc, 0, sizeof(falc_t));
+		cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
+			   cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) &
+			   ~((CPLD_REG2_FALC_TX_CLK | CPLD_REG2_FALC_RX_CLK |
+			      CPLD_REG2_FALC_LED2) << (2 * ch)));
+		/* Reset the FALC chip */
+		cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
+			   cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) |
+			   (CPLD_REG1_FALC_RESET << (2 * ch)));
+		udelay(10000);
+		cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
+			   cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) &
+			   ~(CPLD_REG1_FALC_RESET << (2 * ch)));
+	}
+}
+
+int cpc_open(struct net_device *dev)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+	pc300dev_t *d = (pc300dev_t *) dev->priv;
+	struct ifreq ifr;
+	int result;
+
+#ifdef	PC300_DEBUG_OTHER
+	printk("pc300: cpc_open");
+#endif
+
+	if (hdlc->proto == IF_PROTO_PPP) {
+		d->if_ptr = &hdlc->state.ppp.pppdev;
+	}
+
+	result = hdlc_open(hdlc);
+	if (hdlc->proto == IF_PROTO_PPP) {
+		dev->priv = d;
+	}
+	if (result) {
+		return result;
+	}
+
+	MOD_INC_USE_COUNT;
+	sprintf(ifr.ifr_name, "%s", dev->name);
+	cpc_opench(d);
+	netif_start_queue(dev);
+	return 0;
+}
+
+int cpc_close(struct net_device *dev)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+	pc300dev_t *d = (pc300dev_t *) dev->priv;
+	pc300ch_t *chan = (pc300ch_t *) d->chan;
+	pc300_t *card = (pc300_t *) chan->card;
+	uclong flags;
+
+#ifdef	PC300_DEBUG_OTHER
+	printk("pc300: cpc_close");
+#endif
+
+	netif_stop_queue(dev);
+
+	CPC_LOCK(card, flags);
+	cpc_closech(d);
+	CPC_UNLOCK(card, flags);
+
+	hdlc_close(hdlc);
+	if (hdlc->proto == IF_PROTO_PPP) {
+		d->if_ptr = NULL;
+	}
+#ifdef CONFIG_PC300_MLPPP
+	if (chan->conf.proto == PC300_PROTO_MLPPP) {
+		cpc_tty_unregister_service(d);
+		chan->conf.proto = 0xffff;
+	}
+#endif
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static uclong detect_ram(pc300_t * card)
+{
+	uclong i;
+	ucchar data;
+	uclong rambase = card->hw.rambase;
+
+	card->hw.ramsize = PC300_RAMSIZE;
+	/* Let's find out how much RAM is present on this board */
+	for (i = 0; i < card->hw.ramsize; i++) {
+		data = (ucchar) (i & 0xff);
+		cpc_writeb(rambase + i, data);
+		if (cpc_readb(rambase + i) != data) {
+			break;
+		}
+	}
+	return (i);
+}
+
+static void plx_init(pc300_t * card)
+{
+	struct RUNTIME_9050 *plx_ctl = (struct RUNTIME_9050 *) card->hw.plxbase;
+
+	/* Reset PLX */
+	cpc_writel(&plx_ctl->init_ctrl,
+		   cpc_readl(&plx_ctl->init_ctrl) | 0x40000000);
+	udelay(10000L);
+	cpc_writel(&plx_ctl->init_ctrl,
+		   cpc_readl(&plx_ctl->init_ctrl) & ~0x40000000);
+
+	/* Reload Config. Registers from EEPROM */
+	cpc_writel(&plx_ctl->init_ctrl,
+		   cpc_readl(&plx_ctl->init_ctrl) | 0x20000000);
+	udelay(10000L);
+	cpc_writel(&plx_ctl->init_ctrl,
+		   cpc_readl(&plx_ctl->init_ctrl) & ~0x20000000);
+
+}
+
+static inline void show_version(void)
+{
+	char *rcsvers, *rcsdate, *tmp;
+
+	rcsvers = strchr(rcsid, ' ');
+	rcsvers++;
+	tmp = strchr(rcsvers, ' ');
+	*tmp++ = '\0';
+	rcsdate = strchr(tmp, ' ');
+	rcsdate++;
+	tmp = strrchr(rcsdate, ' ');
+	*tmp = '\0';
+	printk(KERN_INFO "Cyclades-PC300 driver %s %s (built %s %s)\n", 
+		rcsvers, rcsdate, __DATE__, __TIME__);
+}				/* show_version */
+
+static void cpc_init_card(pc300_t * card)
+{
+	int i, devcount = 0;
+	static int board_nbr = 1;
+
+	/* Enable interrupts on the PCI bridge */
+	plx_init(card);
+	cpc_writew(card->hw.plxbase + card->hw.intctl_reg,
+		   cpc_readw(card->hw.plxbase + card->hw.intctl_reg) | 0x0040);
+
+#ifdef USE_PCI_CLOCK
+	/* Set board clock to PCI clock */
+	cpc_writel(card->hw.plxbase + card->hw.gpioc_reg,
+		   cpc_readl(card->hw.plxbase + card->hw.gpioc_reg) | 0x00000004UL);
+	card->hw.clock = PC300_PCI_CLOCK;
+#else
+	/* Set board clock to internal oscillator clock */
+	cpc_writel(card->hw.plxbase + card->hw.gpioc_reg,
+		   cpc_readl(card->hw.plxbase + card->hw.gpioc_reg) & ~0x00000004UL);
+	card->hw.clock = PC300_OSC_CLOCK;
+#endif
+
+	/* Detect actual on-board RAM size */
+	card->hw.ramsize = detect_ram(card);
+
+	/* Set Global SCA-II registers */
+	cpc_writeb(card->hw.scabase + PCR, PCR_PR2);
+	cpc_writeb(card->hw.scabase + BTCR, 0x10);
+	cpc_writeb(card->hw.scabase + WCRL, 0);
+	cpc_writeb(card->hw.scabase + DMER, 0x80);
+
+	if (card->hw.type == PC300_TE) {
+		ucchar reg1;
+
+		/* Check CPLD version */
+		reg1 = cpc_readb(card->hw.falcbase + CPLD_REG1);
+		cpc_writeb(card->hw.falcbase + CPLD_REG1, (reg1 + 0x5a));
+		if (cpc_readb(card->hw.falcbase + CPLD_REG1) == reg1) {
+			/* New CPLD */
+			card->hw.cpld_id = cpc_readb(card->hw.falcbase + CPLD_ID_REG);
+			card->hw.cpld_reg1 = CPLD_V2_REG1;
+			card->hw.cpld_reg2 = CPLD_V2_REG2;
+		} else {
+			/* old CPLD */
+			card->hw.cpld_id = 0;
+			card->hw.cpld_reg1 = CPLD_REG1;
+			card->hw.cpld_reg2 = CPLD_REG2;
+			cpc_writeb(card->hw.falcbase + CPLD_REG1, reg1);
+		}
+
+		/* Enable the board's global clock */
+		cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
+			   cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) |
+			   CPLD_REG1_GLOBAL_CLK);
+
+	}
+
+	for (i = 0; i < card->hw.nchan; i++) {
+		pc300ch_t *chan = &card->chan[i];
+		pc300dev_t *d = &chan->d;
+		hdlc_device *hdlc;
+		struct net_device *dev;
+
+		chan->card = card;
+		chan->channel = i;
+		chan->conf.phys_settings.clock_rate = 0;
+		chan->conf.phys_settings.clock_type = CLOCK_EXT;
+		chan->conf.proto_settings.encoding = ENCODING_NRZ;
+		chan->conf.proto_settings.parity = PARITY_CRC16_PR1_CCITT;
+		switch (card->hw.type) {
+			case PC300_TE:
+				chan->conf.media = IF_IFACE_T1;
+				chan->conf.lcode = PC300_LC_B8ZS;
+				chan->conf.fr_mode = PC300_FR_ESF;
+				chan->conf.lbo = PC300_LBO_0_DB;
+				chan->conf.rx_sens = PC300_RX_SENS_SH;
+				chan->conf.tslot_bitmap = 0xffffffffUL;
+				break;
+
+			case PC300_X21:
+				chan->conf.media = IF_IFACE_X21;
+				break;
+
+			case PC300_RSV:
+			default:
+				chan->conf.media = IF_IFACE_V35;
+				break;
+		}
+		chan->conf.proto = IF_PROTO_PPP;
+		chan->tx_first_bd = 0;
+		chan->tx_next_bd = 0;
+		chan->rx_first_bd = 0;
+		chan->rx_last_bd = N_DMA_RX_BUF - 1;
+		chan->nfree_tx_bd = N_DMA_TX_BUF;
+
+		d->chan = chan;
+		d->tx_skb = NULL;
+		d->trace_on = 0;
+		d->line_on = 0;
+		d->line_off = 0;
+
+		d->hdlc = (hdlc_device *) kmalloc(sizeof(hdlc_device), GFP_KERNEL);
+		if (d->hdlc == NULL)
+			continue;
+		memset(d->hdlc, 0, sizeof(hdlc_device));
+
+		hdlc = d->hdlc;
+		hdlc->xmit = cpc_queue_xmit;
+		hdlc->attach = cpc_attach;
+
+		dev = hdlc_to_dev(hdlc);
+
+		dev->mem_start = card->hw.ramphys;
+		dev->mem_end = card->hw.ramphys + card->hw.ramsize - 1;
+		dev->irq = card->hw.irq;
+		dev->init = NULL;
+		dev->tx_queue_len = PC300_TX_QUEUE_LEN;
+		dev->mtu = PC300_DEF_MTU;
+
+		dev->open = cpc_open;
+		dev->stop = cpc_close;
+		dev->tx_timeout = cpc_tx_timeout;
+		dev->watchdog_timeo = PC300_TX_TIMEOUT;
+		dev->get_stats = cpc_get_stats;
+		dev->set_multicast_list = NULL;
+		dev->set_mac_address = NULL;
+		dev->change_mtu = cpc_change_mtu;
+		dev->do_ioctl = cpc_ioctl;
+
+		if (register_hdlc_device(hdlc) == 0) {
+			dev->priv = d;	/* We need 'priv', hdlc doesn't */
+			printk("%s: Cyclades-PC300/", dev->name);
+			switch (card->hw.type) {
+				case PC300_TE:
+					if (card->hw.bus == PC300_PMC) {
+						printk("TE-M");
+					} else {
+						printk("TE  ");
+					}
+					break;
+
+				case PC300_X21:
+					printk("X21 ");
+					break;
+
+				case PC300_RSV:
+				default:
+					printk("RSV ");
+					break;
+			}
+			printk (" #%d, %ldKB of RAM at 0x%08lx, IRQ%d, channel %d.\n",
+				 board_nbr, card->hw.ramsize / 1024,
+				 card->hw.ramphys, card->hw.irq, i + 1);
+			devcount++;
+		} else {
+			printk ("Dev%d on card(0x%08lx): unable to allocate i/f name.\n",
+				 i + 1, card->hw.ramphys);
+			*(dev->name) = 0;
+			kfree(d->hdlc);
+			continue;
+		}
+	}
+	spin_lock_init(&card->card_lock);
+
+	board_nbr++;
+}
+
+static int __devinit
+cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int first_time = 1;
+	ucchar cpc_rev_id;
+	int err = 0, eeprom_outdated = 0;
+	ucshort device_id;
+	pc300_t *card;
+
+	if (first_time) {
+		first_time = 0;
+		show_version();
+#ifdef CONFIG_PC300_MLPPP
+		cpc_tty_reset_var();
+#endif
+	}
+
+	card = (pc300_t *) kmalloc(sizeof(pc300_t), GFP_KERNEL);
+	if (card == NULL) {
+		printk("PC300 found at RAM 0x%08lx, "
+		       "but could not allocate card structure.\n",
+		       pci_resource_start(pdev, 3));
+		return -ENOMEM;
+	}
+	memset(card, 0, sizeof(pc300_t));
+
+	/* read PCI configuration area */
+	device_id = ent->device;
+	card->hw.irq = pdev->irq;
+	card->hw.iophys = pci_resource_start(pdev, 1);
+	card->hw.iosize = pci_resource_len(pdev, 1);
+	card->hw.scaphys = pci_resource_start(pdev, 2);
+	card->hw.scasize = pci_resource_len(pdev, 2);
+	card->hw.ramphys = pci_resource_start(pdev, 3);
+	card->hw.alloc_ramsize = pci_resource_len(pdev, 3);
+	card->hw.falcphys = pci_resource_start(pdev, 4);
+	card->hw.falcsize = pci_resource_len(pdev, 4);
+	card->hw.plxphys = pci_resource_start(pdev, 5);
+	card->hw.plxsize = pci_resource_len(pdev, 5);
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &cpc_rev_id);
+
+	switch (device_id) {
+		case PCI_DEVICE_ID_PC300_RX_1:
+		case PCI_DEVICE_ID_PC300_TE_1:
+		case PCI_DEVICE_ID_PC300_TE_M_1:
+			card->hw.nchan = 1;
+			break;
+
+		case PCI_DEVICE_ID_PC300_RX_2:
+		case PCI_DEVICE_ID_PC300_TE_2:
+		case PCI_DEVICE_ID_PC300_TE_M_2:
+		default:
+			card->hw.nchan = PC300_MAXCHAN;
+			break;
+	}
+#ifdef PC300_DEBUG_PCI
+	printk("cpc (bus=0x0%x,pci_id=0x%x,", pdev->bus->number, pdev->devfn);
+	printk("rev_id=%d) IRQ%d\n", cpc_rev_id, card->hw.irq);
+	printk("cpc:found  ramaddr=0x%08lx plxaddr=0x%08lx "
+	       "ctladdr=0x%08lx falcaddr=0x%08lx\n",
+	       card->hw.ramphys, card->hw.plxphys, card->hw.scaphys,
+	       card->hw.falcphys);
+#endif
+	/* Although we don't use this I/O region, we should
+	 * request it from the kernel anyway, to avoid problems
+	 * with other drivers accessing it. */
+	if (!request_region(card->hw.iophys, card->hw.iosize, "PLX Registers")) {
+		/* In case we can't allocate it, warn user */
+		printk("WARNING: couldn't allocate I/O region for PC300 board "
+		       "at 0x%08lx!\n", card->hw.ramphys);
+	}
+
+	if (card->hw.plxphys) {
+		pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, card->hw.plxphys);
+	} else {
+		eeprom_outdated = 1;
+		card->hw.plxphys = pci_resource_start(pdev, 0);
+		card->hw.plxsize = pci_resource_len(pdev, 0);
+	}
+
+	if (!request_mem_region(card->hw.plxphys, card->hw.plxsize,
+				"PLX Registers")) {
+		printk("PC300 found at RAM 0x%08lx, "
+		       "but could not allocate PLX mem region.\n",
+		       card->hw.ramphys);
+		err = -ENODEV;
+		goto err_release_io;
+	}
+	if (!request_mem_region(card->hw.ramphys, card->hw.alloc_ramsize,
+				"On-board RAM")) {
+		printk("PC300 found at RAM 0x%08lx, "
+		       "but could not allocate RAM mem region.\n",
+		       card->hw.ramphys);
+		err = -ENODEV;
+		goto err_release_plx;
+	}
+	if (!request_mem_region(card->hw.scaphys, card->hw.scasize,
+				"SCA-II Registers")) {
+		printk("PC300 found at RAM 0x%08lx, "
+		       "but could not allocate SCA mem region.\n",
+		       card->hw.ramphys);
+		err = -ENODEV;
+		goto err_release_ram;
+	}
+
+	if ((err = pci_enable_device(pdev)) != 0)
+		goto err_release_sca;
+
+	card->hw.plxbase = (uclong) ioremap(card->hw.plxphys, card->hw.plxsize);
+	card->hw.rambase = (uclong) ioremap(card->hw.ramphys,
+					    card->hw.alloc_ramsize);
+	card->hw.scabase = (uclong) ioremap(card->hw.scaphys, card->hw.scasize);
+	switch (device_id) {
+		case PCI_DEVICE_ID_PC300_TE_1:
+		case PCI_DEVICE_ID_PC300_TE_2:
+		case PCI_DEVICE_ID_PC300_TE_M_1:
+		case PCI_DEVICE_ID_PC300_TE_M_2:
+			request_mem_region(card->hw.falcphys, card->hw.falcsize,
+					   "FALC Registers");
+			card->hw.falcbase = (uclong) ioremap(card->hw.falcphys,
+							     card->hw.falcsize);
+			break;
+
+		case PCI_DEVICE_ID_PC300_RX_1:
+		case PCI_DEVICE_ID_PC300_RX_2:
+		default:
+			card->hw.falcbase = 0;
+			break;
+	}
+
+#ifdef PC300_DEBUG_PCI
+	printk("cpc: relocate ramaddr=0x%08lx plxaddr=0x%08lx "
+	       "ctladdr=0x%08lx falcaddr=0x%08lx\n",
+	       card->hw.rambase, card->hw.plxbase, card->hw.scabase,
+	       card->hw.falcbase);
+#endif
+
+	/* Set PCI drv pointer to the card structure */
+	pdev->driver_data = card;
+
+	/* Set board type */
+	switch (device_id) {
+		case PCI_DEVICE_ID_PC300_TE_1:
+		case PCI_DEVICE_ID_PC300_TE_2:
+		case PCI_DEVICE_ID_PC300_TE_M_1:
+		case PCI_DEVICE_ID_PC300_TE_M_2:
+			card->hw.type = PC300_TE;
+
+			if ((device_id == PCI_DEVICE_ID_PC300_TE_M_1) ||
+			    (device_id == PCI_DEVICE_ID_PC300_TE_M_2)) {
+				card->hw.bus = PC300_PMC;
+				/* Set PLX register offsets */
+				card->hw.gpioc_reg = 0x54;
+				card->hw.intctl_reg = 0x4c;
+			} else {
+				card->hw.bus = PC300_PCI;
+				/* Set PLX register offsets */
+				card->hw.gpioc_reg = 0x50;
+				card->hw.intctl_reg = 0x4c;
+			}
+			break;
+
+		case PCI_DEVICE_ID_PC300_RX_1:
+		case PCI_DEVICE_ID_PC300_RX_2:
+		default:
+			card->hw.bus = PC300_PCI;
+			/* Set PLX register offsets */
+			card->hw.gpioc_reg = 0x50;
+			card->hw.intctl_reg = 0x4c;
+
+			if ((cpc_readl(card->hw.plxbase + card->hw.gpioc_reg) & PC300_CTYPE_MASK)) {
+				card->hw.type = PC300_X21;
+			} else {
+				card->hw.type = PC300_RSV;
+			}
+			break;
+	}
+
+	/* Allocate IRQ */
+	if (request_irq(card->hw.irq, cpc_intr, SA_SHIRQ, "Cyclades-PC300", card)) {
+		printk ("PC300 found at RAM 0x%08lx, but could not allocate IRQ%d.\n",
+			 card->hw.ramphys, card->hw.irq);
+		goto err_io_unmap;
+	}
+
+	cpc_init_card(card);
+
+	if (eeprom_outdated)
+		printk("WARNING: PC300 with outdated EEPROM.\n");
+	return 0;
+
+err_io_unmap:
+	iounmap((void *) card->hw.plxbase);
+	iounmap((void *) card->hw.scabase);
+	iounmap((void *) card->hw.rambase);
+	if (card->hw.type == PC300_TE) {
+		iounmap((void *) card->hw.falcbase);
+		release_mem_region(card->hw.falcphys, card->hw.falcsize);
+	}
+err_release_sca:
+	release_mem_region(card->hw.scaphys, card->hw.scasize);
+err_release_ram:
+	release_mem_region(card->hw.ramphys, card->hw.alloc_ramsize);
+err_release_plx:
+	release_mem_region(card->hw.plxphys, card->hw.plxsize);
+err_release_io:
+	release_region(card->hw.iophys, card->hw.iosize);
+	kfree(card);
+	return -ENODEV;
+}
+
+static void __devexit cpc_remove_one(struct pci_dev *pdev)
+{
+	pc300_t *card = (pc300_t *) pdev->driver_data;
+
+	if (card->hw.rambase != 0) {
+		int i;
+
+		/* Disable interrupts on the PCI bridge */
+		cpc_writew(card->hw.plxbase + card->hw.intctl_reg,
+			   cpc_readw(card->hw.plxbase + card->hw.intctl_reg) & ~(0x0040));
+
+		for (i = 0; i < card->hw.nchan; i++) {
+			unregister_hdlc_device(card->chan[i].d.hdlc);
+		}
+		iounmap((void *) card->hw.plxbase);
+		iounmap((void *) card->hw.scabase);
+		iounmap((void *) card->hw.rambase);
+		release_mem_region(card->hw.plxphys, card->hw.plxsize);
+		release_mem_region(card->hw.ramphys, card->hw.alloc_ramsize);
+		release_mem_region(card->hw.scaphys, card->hw.scasize);
+		release_region(card->hw.iophys, card->hw.iosize);
+		if (card->hw.type == PC300_TE) {
+			iounmap((void *) card->hw.falcbase);
+			release_mem_region(card->hw.falcphys, card->hw.falcsize);
+		}
+		if (card->hw.irq)
+			free_irq(card->hw.irq, card);
+		kfree(card);
+	}
+}
+
+static struct pci_driver cpc_driver = {
+	name:"pc300",
+	id_table:cpc_pci_dev_id,
+	probe:cpc_init_one,
+	remove:cpc_remove_one,
+	suspend:NULL,
+	resume:NULL,
+};
+
+static int __init cpc_init(void)
+{
+	return pci_module_init(&cpc_driver);
+}
+
+static void __exit cpc_cleanup_module(void)
+{
+	pci_unregister_driver(&cpc_driver);
+}
+
+module_init(cpc_init);
+module_exit(cpc_cleanup_module);
diff -Nru a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wan/pc300_tty.c	Thu May  2 17:22:17 2002
@@ -0,0 +1,1146 @@
+/*
+ * pc300_tty.c	Cyclades-PC300(tm) TTY Driver.
+ *
+ * Author:	Regina Kodato <reginak@cyclades.com>
+ *
+ * Copyright:	(c) 1999-2002 Cyclades Corp.
+ *
+ *	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.
+ *   
+ *  $Log: pc300_tty.c,v $
+ *  Revision 3.7  2002/03/07 14:17:09  henrique
+ *  License data fixed
+ *
+ *  Revision 3.6  2001/12/10 12:29:42  regina
+ *  Fix the MLPPP bug
+ *
+ *  Revision 3.5  2001/10/31 11:20:05  regina
+ *  automatic pppd starts
+ *
+ *  Revision 3.4  2001/08/06 12:01:51  regina
+ *  problem in DSR_DE bit
+ *
+ *  Revision 3.3  2001/07/26 22:58:41  regina
+ *  update EDA value
+ *
+ *  Revision 3.2  2001/07/12 13:11:20  regina
+ *  bug fix - DCD-OFF in pc300 tty driver
+ *
+ *	DMA transmission bug fix
+ *  
+ *  Revision 3.1  2001/06/22 13:13:02  regina
+ *  MLPPP implementation
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/malloc.h>
+#include <linux/if.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/skbuff.h>
+
+/* TTY includes */
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+
+#include "pc300.h"
+
+/* defines and macros */
+/* TTY Global definitions */
+#define	CPC_TTY_NPORTS	8	/* maximum number of the sync tty connections */
+#define	CPC_TTY_MAJOR	CYCLADES_MAJOR	
+#define CPC_TTY_MINOR_START	240	/* minor of the first PC300 interface */
+
+#define CPC_TTY_MAX_MTU	2000	
+
+/* tty interface state */
+#define	CPC_TTY_ST_IDLE	0
+#define CPC_TTY_ST_INIT	1	/* configured with MLPPP and up */
+#define CPC_TTY_ST_OPEN	2	/* opened by application */
+
+#define	CPC_TTY_LOCK(card,flags)\
+	do {\
+		spin_lock_irqsave(&card->card_lock, flags);	\
+	} while (0)
+
+#define CPC_TTY_UNLOCK(card,flags)	\
+	do {\
+		spin_unlock_irqrestore(&card->card_lock, flags);	\
+	} while (0)
+
+//#define	CPC_TTY_DBG(format,a...)	printk(format,##a)
+#define	CPC_TTY_DBG(format,a...)
+
+/* data structures */
+typedef struct _st_cpc_rx_buf {
+	struct _st_cpc_rx_buf	*next;
+	int		size;
+	unsigned char	data[1];
+} st_cpc_rx_buf;
+
+struct st_cpc_rx_list {
+	st_cpc_rx_buf	*first;
+	st_cpc_rx_buf	*last;
+};
+
+typedef	struct _st_cpc_tty_area {
+	int		state;		/* state of the TTY interface */
+	int		num_open;	
+	unsigned int 	tty_minor;	/* minor this interface */
+	volatile struct st_cpc_rx_list buf_rx;	/* ptr. to reception buffer */
+	unsigned char*	buf_tx;		/* ptr. to transmission buffer */
+	pc300dev_t*	pc300dev;	/* ptr. to info struct in PC300 driver */
+	unsigned char	name[20];	/* interf. name + "-tty" */
+	struct tty_struct *tty;		
+	struct tq_struct tty_tx_task_queue; /* tx task - tx interrupt */
+	struct tq_struct tty_rx_task_queue; /* rx task - rx interrupt */
+	} st_cpc_tty_area;
+
+/* TTY data structures */
+static struct tty_struct *cpc_tty_serial_table[CPC_TTY_NPORTS];
+static struct termios *cpc_tty_serial_termios[CPC_TTY_NPORTS];
+static struct termios *cpc_tty_serial_termios_locked[CPC_TTY_NPORTS];
+static struct tty_driver serial_drv, callout_drv;
+
+/* local variables */
+st_cpc_tty_area	cpc_tty_area[CPC_TTY_NPORTS];
+
+int cpc_tty_cnt=0;	/* number of intrfaces configured with MLPPP */
+int cpc_tty_refcount;
+int cpc_tty_unreg_flag = 0;
+
+/* TTY functions prototype */
+static int cpc_tty_open(struct tty_struct *tty, struct file *flip);
+static void cpc_tty_close(struct tty_struct *tty, struct file *flip);
+static int cpc_tty_write(struct tty_struct *tty, int from_user,
+				const unsigned char *buf, int count);
+static int cpc_tty_write_room(struct tty_struct *tty);
+static int cpc_tty_chars_in_buffer(struct tty_struct *tty);
+static int cpc_tty_ioctl(struct tty_struct *tty, struct file *file,
+				unsigned int cmd, unsigned long arg);
+static void cpc_tty_flush_buffer(struct tty_struct *tty);
+static void cpc_tty_hangup(struct tty_struct *tty);
+static void cpc_tty_rx_task(void *data);
+static void cpc_tty_tx_task(void *data);
+static int cpc_tty_send_to_card(pc300dev_t *dev,void *buf, int len);
+static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx);
+static void cpc_tty_dtr_off(pc300dev_t *pc300dev);
+static void cpc_tty_dtr_on(pc300dev_t *pc300dev);
+
+/* functions called by PC300 driver */
+void cpc_tty_init(pc300dev_t *dev);
+void cpc_tty_unregister_service(pc300dev_t *pc300dev);
+void cpc_tty_receive(pc300dev_t *pc300dev);
+void cpc_tty_trigger_poll(pc300dev_t *pc300dev);
+void cpc_tty_reset_var(void);
+
+/*
+ * PC300 TTY clear DTR signal
+ */
+static void cpc_tty_dtr_off(pc300dev_t *pc300dev)
+{
+	pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; 
+	pc300_t *card = (pc300_t *) pc300chan->card; 
+	int ch = pc300chan->channel; 
+	unsigned long flags; 
+
+	CPC_TTY_DBG("%s-tty: Clear signal DTR\n",
+		((struct net_device*)(pc300dev->hdlc))->name);
+	CPC_TTY_LOCK(card, flags); 
+	cpc_writeb(card->hw.scabase + M_REG(CTL,ch), 
+		cpc_readb(card->hw.scabase+M_REG(CTL,ch))& CTL_DTR); 
+	CPC_TTY_UNLOCK(card,flags); 
+}
+
+/*
+ * PC300 TTY set DTR signal to ON
+ */
+static void cpc_tty_dtr_on(pc300dev_t *pc300dev)
+{
+	pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; 
+	pc300_t *card = (pc300_t *) pc300chan->card; 
+	int ch = pc300chan->channel; 
+	unsigned long flags; 
+
+	CPC_TTY_DBG("%s-tty: Set signal DTR\n",
+		((struct net_device*)(pc300dev->hdlc))->name);
+	CPC_TTY_LOCK(card, flags); 
+	cpc_writeb(card->hw.scabase + M_REG(CTL,ch), 
+		cpc_readb(card->hw.scabase+M_REG(CTL,ch))& ~CTL_DTR); 
+	CPC_TTY_UNLOCK(card,flags); 
+}
+
+/*
+ * PC300 TTY initialization routine
+ *
+ * This routine is called by the PC300 driver during board configuration 
+ * (ioctl=SIOCSP300CONF). At this point the adapter is completely
+ * initialized.
+ * o verify kernel version (only 2.4.x)
+ * o register TTY driver
+ * o init cpc_tty_area struct
+ */
+void cpc_tty_init(pc300dev_t *pc300dev)
+{
+	int port, aux;
+	st_cpc_tty_area * cpc_tty;
+
+	if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) {
+		printk("%s-tty: Error: TTY driver is supported on 2.4.X kernel!\n",
+			((struct net_device*)(pc300dev->hdlc))->name);
+		return;
+	}
+	
+	/* hdlcX - X=interface number */
+	port = ((struct net_device*)(pc300dev->hdlc))->name[4] - '0';
+	if (port >= CPC_TTY_NPORTS) {
+		printk("%s-tty: invalid interface selected (0-%i): %i", 
+			((struct net_device*)(pc300dev->hdlc))->name,
+			CPC_TTY_NPORTS-1,port);
+		return;
+	}
+
+	if (cpc_tty_cnt == 0) { /* first TTY connection -> register driver */
+		CPC_TTY_DBG("%s-tty: driver init, major:%i, minor range:%i=%i\n",
+			((struct net_device*)(pc300dev->hdlc))->name,
+			CPC_TTY_MAJOR, CPC_TTY_MINOR_START,
+			CPC_TTY_MINOR_START+CPC_TTY_NPORTS);
+		/* initialize tty driver struct */
+		memset(&serial_drv,0,sizeof(struct tty_driver));
+		serial_drv.magic = TTY_DRIVER_MAGIC;
+		serial_drv.driver_name = "pc300_tty";
+		serial_drv.name = "ttyCP";
+		serial_drv.major = CPC_TTY_MAJOR;
+		serial_drv.minor_start = CPC_TTY_MINOR_START;
+		serial_drv.num = CPC_TTY_NPORTS;
+		serial_drv.type = TTY_DRIVER_TYPE_SERIAL;
+		serial_drv.subtype = SERIAL_TYPE_NORMAL;
+
+		serial_drv.init_termios = tty_std_termios;
+		serial_drv.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
+		serial_drv.flags = TTY_DRIVER_REAL_RAW;
+		serial_drv.refcount = &cpc_tty_refcount;
+
+		/* tty data structures */
+		serial_drv.table = cpc_tty_serial_table;
+		serial_drv.termios = cpc_tty_serial_termios;
+		serial_drv.termios_locked = cpc_tty_serial_termios_locked;
+
+		/* interface routines from the upper tty layer to the tty driver */
+		serial_drv.open = cpc_tty_open;
+		serial_drv.close = cpc_tty_close;
+		serial_drv.write = cpc_tty_write; 
+		serial_drv.write_room = cpc_tty_write_room; 
+		serial_drv.chars_in_buffer = cpc_tty_chars_in_buffer; 
+		serial_drv.ioctl = cpc_tty_ioctl; 
+		serial_drv.flush_buffer = cpc_tty_flush_buffer; 
+		serial_drv.hangup = cpc_tty_hangup;
+
+		/* the callout device is just like normal device except for major */
+	   	/* number and the subtype code */ 
+		callout_drv = serial_drv; 
+		callout_drv.name = "cucp"; 
+		callout_drv.major = CPC_TTY_MAJOR + 1;
+		callout_drv.subtype = SERIAL_TYPE_CALLOUT;
+		callout_drv.read_proc = 0;
+		callout_drv.proc_entry = 0; 
+		
+		/* register the TTY driver */
+		if (tty_register_driver(&serial_drv)) { 
+			printk("%s-tty: Failed to register serial driver! ",
+				((struct net_device*)(pc300dev->hdlc))->name);
+		   	return;
+		} 
+
+		if (tty_register_driver(&callout_drv)) {
+			CPC_TTY_DBG("%s-tty: Failed to register callout driver! ",
+				((struct net_device*)(pc300dev->hdlc))->name);
+			return;
+		}
+		memset((void *)cpc_tty_area, 0,
+								sizeof(st_cpc_tty_area) * CPC_TTY_NPORTS);
+	}
+
+	cpc_tty = &cpc_tty_area[port];
+	
+	if (cpc_tty->state != CPC_TTY_ST_IDLE) {
+		CPC_TTY_DBG("%s-tty: TTY port %i, already in use.\n",
+					((struct net_device*)(pc300dev->hdlc))->name,port);
+		return;
+	}
+
+	cpc_tty_cnt++;
+	cpc_tty->state = CPC_TTY_ST_INIT; 
+	cpc_tty->num_open= 0;
+	cpc_tty->tty_minor = port + CPC_TTY_MINOR_START;
+	cpc_tty->pc300dev = pc300dev; 
+	
+	cpc_tty->tty_tx_task_queue.routine = cpc_tty_tx_task; 
+	cpc_tty->tty_tx_task_queue.data = (void *)cpc_tty; 
+	
+	cpc_tty->tty_rx_task_queue.routine = cpc_tty_rx_task; 
+	cpc_tty->tty_rx_task_queue.data = (void *) port; 
+	
+	cpc_tty->buf_rx.first = cpc_tty->buf_rx.last = 0;
+
+	pc300dev->cpc_tty = (void *)cpc_tty; 
+	
+	aux = strlen(((struct net_device*)(pc300dev->hdlc))->name);
+	memcpy(cpc_tty->name,((struct net_device*)(pc300dev->hdlc))->name,aux);
+	memcpy(&cpc_tty->name[aux], "-tty", 5);
+	
+	cpc_open((struct net_device *)pc300dev->hdlc);
+	cpc_tty_dtr_off(pc300dev);
+
+	CPC_TTY_DBG("%s: Initializing TTY Sync Driver, tty major#%d minor#%i\n",
+			cpc_tty->name,CPC_TTY_MAJOR,cpc_tty->tty_minor); 
+	return; 
+} 
+
+/*
+ * PC300 TTY OPEN routine
+ *
+ * This routine is called by the tty driver to open the interface 
+ * o verify minor
+ * o allocate buffer to Rx and Tx
+ */
+static int cpc_tty_open(struct tty_struct *tty, struct file *flip)
+{
+	int port ;
+	st_cpc_tty_area *cpc_tty;
+
+	if (!tty) { 
+		return -ENODEV;
+	} 
+
+	port = minor(tty->device) - tty->driver.minor_start; 
+
+	if ((port < 0) || (port >= CPC_TTY_NPORTS)){ 
+		CPC_TTY_DBG("pc300_tty: open invalid minor %i\n",MINOR(tty->device));
+		return -ENODEV;
+	} 
+
+	cpc_tty = &cpc_tty_area[port];
+	
+	if (cpc_tty->state == CPC_TTY_ST_IDLE){
+		CPC_TTY_DBG("%s: open - invalid interface, minor=%i\n",
+					cpc_tty->name, MINOR(tty->device));
+		return -ENODEV;
+	}
+
+	if (cpc_tty->num_open == 0) { /* first open of this tty */
+		if (!cpc_tty_area[port].buf_tx){
+			cpc_tty_area[port].buf_tx = kmalloc(CPC_TTY_MAX_MTU,GFP_KERNEL);
+			if (cpc_tty_area[port].buf_tx == 0){
+				CPC_TTY_DBG("%s: error in memory allocation\n",cpc_tty->name);
+				return -ENOMEM;
+			}
+		} 
+
+		if (cpc_tty_area[port].buf_rx.first) {
+			unsigned char * aux;
+			while (cpc_tty_area[port].buf_rx.first) {
+				aux = (unsigned char *)cpc_tty_area[port].buf_rx.first;
+				cpc_tty_area[port].buf_rx.first = cpc_tty_area[port].buf_rx.first->next;
+				kfree(aux);
+			}
+			cpc_tty_area[port].buf_rx.first = NULL;
+			cpc_tty_area[port].buf_rx.last = NULL;
+		}
+
+		cpc_tty_area[port].state = CPC_TTY_ST_OPEN;
+		cpc_tty_area[port].tty = tty;
+		tty->driver_data = &cpc_tty_area[port];
+
+		cpc_tty_dtr_on(cpc_tty->pc300dev);
+	} 
+
+	cpc_tty->num_open++;
+
+	CPC_TTY_DBG("%s: opening TTY driver\n", cpc_tty->name);
+	
+	/* avisar driver PC300 */ 
+	return 0; 
+}
+
+/*
+ * PC300 TTY CLOSE routine
+ *
+ * This routine is called by the tty driver to close the interface 
+ * o call close channel in PC300 driver (cpc_closech)
+ * o free Rx and Tx buffers
+ */
+
+static void cpc_tty_close(struct tty_struct *tty, struct file *flip)
+{
+	st_cpc_tty_area    *cpc_tty;
+	unsigned long flags;
+	int res;
+
+	if (!tty || !tty->driver_data ) {
+		CPC_TTY_DBG("hdlx-tty: no TTY in close \n");
+		return;
+	}
+
+	cpc_tty = (st_cpc_tty_area *) tty->driver_data;
+
+	if ((cpc_tty->tty != tty)|| (cpc_tty->state != CPC_TTY_ST_OPEN)) {
+		CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);
+		return;
+	}
+   	
+	if (!cpc_tty->num_open) {
+		CPC_TTY_DBG("%s: TTY is closed\n",cpc_tty->name);
+		return;
+	}
+
+	if (--cpc_tty->num_open > 0) {
+		CPC_TTY_DBG("%s: TTY closed\n",cpc_tty->name);
+		return;
+	}
+
+	cpc_tty_dtr_off(cpc_tty->pc300dev);
+
+	CPC_TTY_LOCK(cpc_tty->pc300dev->chan->card, flags);  /* lock irq */ 
+	cpc_tty->tty = NULL;
+	cpc_tty->state = CPC_TTY_ST_INIT;
+	CPC_TTY_UNLOCK(cpc_tty->pc300dev->chan->card, flags); /* unlock irq */ 
+	
+	if (cpc_tty->buf_rx.first) {
+		unsigned char * aux;
+		while (cpc_tty->buf_rx.first) {
+			aux = (unsigned char *)cpc_tty->buf_rx.first;
+			cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next;
+			kfree(aux);
+		}
+		cpc_tty->buf_rx.first = NULL;
+		cpc_tty->buf_rx.last = NULL;
+	}
+	
+	if (cpc_tty->buf_tx) {
+		kfree(cpc_tty->buf_tx);
+		cpc_tty->buf_tx = NULL;
+	}
+
+	CPC_TTY_DBG("%s: TTY closed\n",cpc_tty->name);
+	
+	if (!cpc_tty_refcount && cpc_tty_unreg_flag) {
+		cpc_tty_unreg_flag = 0;
+		CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name);
+		if ((res=tty_unregister_driver(&serial_drv))) { 
+			CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
+							cpc_tty->name,res);
+		}
+		if ((res=tty_unregister_driver(&callout_drv))) { 
+			CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
+							cpc_tty->name,res);
+		}
+	}
+	return; 
+} 
+
+/*
+ * PC300 TTY WRITE routine
+ *
+ * This routine is called by the tty driver to write a series of characters
+ * to the tty device. The characters may come from user or kernel space.
+ * o verify the DCD signal
+ * o send characters to board and start the transmission
+ */
+static int cpc_tty_write(struct tty_struct *tty, int from_user,
+			const unsigned char *buf, int count)
+{
+	st_cpc_tty_area    *cpc_tty; 
+	pc300ch_t *pc300chan; 
+	pc300_t *card; 
+	int ch; 
+	unsigned long flags; 
+	struct net_device_stats *stats; 
+
+	if (!tty || !tty->driver_data ) { 
+		CPC_TTY_DBG("hdlcX-tty: no TTY in write\n");
+		return -ENODEV;
+	} 
+
+	cpc_tty = (st_cpc_tty_area *) tty->driver_data; 
+
+	if ((cpc_tty->tty != tty) ||  (cpc_tty->state != CPC_TTY_ST_OPEN)) { 
+		CPC_TTY_DBG("%s: TTY is not opened\n", cpc_tty->name);
+		return -ENODEV; 
+	}
+
+	if (count > CPC_TTY_MAX_MTU) { 
+		CPC_TTY_DBG("%s: count is invalid\n",cpc_tty->name);
+		return -EINVAL;        /* frame too big */ 
+	}
+
+	CPC_TTY_DBG("%s: cpc_tty_write %s data len=%i\n",cpc_tty->name,
+		(from_user)?"from user" : "from kernel",count);
+	
+	pc300chan = (pc300ch_t *)((pc300dev_t*)cpc_tty->pc300dev)->chan; 
+	stats = &((pc300dev_t*)cpc_tty->pc300dev)->hdlc->stats;
+	card = (pc300_t *) pc300chan->card;
+	ch = pc300chan->channel; 
+
+	/* verify DCD signal*/ 
+	if (cpc_readb(card->hw.scabase + M_REG(ST3,ch)) & ST3_DCD) { 
+		/* DCD is OFF */ 
+		CPC_TTY_DBG("%s : DCD is OFF\n", cpc_tty->name);
+		stats->tx_errors++;
+		stats->tx_carrier_errors++;
+		CPC_TTY_LOCK(card, flags); 
+		cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_BUF_CLR); 
+		
+		if (card->hw.type == PC300_TE) { 
+			cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, 
+				cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) & 
+				~(CPLD_REG2_FALC_LED1 << (2 *ch))); 
+		}
+
+		CPC_TTY_UNLOCK(card, flags); 
+
+		return -EINVAL; 
+	}
+
+	if (from_user) { 
+		unsigned char *buf_tmp; 
+
+		buf_tmp = cpc_tty->buf_tx;
+		if (copy_from_user(buf_tmp, buf, count)) { 
+			/* failed to copy from user */
+			CPC_TTY_DBG("%s: error in copy from user\n",cpc_tty->name);
+			return -EINVAL; 
+		}
+
+		if (cpc_tty_send_to_card(cpc_tty->pc300dev, (void*) buf_tmp,count)) { 
+			/* failed to send */ 
+			CPC_TTY_DBG("%s: transmission error\n",cpc_tty->name);
+			return 0; 
+		}
+	} else {
+		if (cpc_tty_send_to_card(cpc_tty->pc300dev, (void*)buf, count)) { 
+		   /* failed to send */
+		   CPC_TTY_DBG("%s: trasmition error\n", cpc_tty->name);
+		   return 0;
+		}
+	}
+	return count; 
+} 
+
+/*
+ * PC300 TTY Write Room routine
+ * 
+ * This routine returns the numbers of characteres the tty driver will accept
+ * for queuing to be written. 
+ * o return MTU
+ */
+static int cpc_tty_write_room(struct tty_struct *tty)
+{
+	st_cpc_tty_area    *cpc_tty; 
+
+	if (!tty || !tty->driver_data ) { 
+		CPC_TTY_DBG("hdlcX-tty: no TTY to write room\n");
+		return -ENODEV;
+	}
+
+	cpc_tty = (st_cpc_tty_area *) tty->driver_data; 
+
+	if ((cpc_tty->tty != tty) ||  (cpc_tty->state != CPC_TTY_ST_OPEN)) { 
+		CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);
+		return -ENODEV; 
+	}
+   	
+	CPC_TTY_DBG("%s: write room\n",cpc_tty->name);
+	
+	return CPC_TTY_MAX_MTU;
+} 
+
+/*
+ * PC300 TTY chars in buffer routine
+ * 
+ * This routine returns the chars number in the transmission buffer 
+ * o returns 0
+ */
+static int cpc_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	st_cpc_tty_area    *cpc_tty; 
+
+	if (!tty || !tty->driver_data ) {
+		CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n");
+		return -ENODEV; 
+	}
+
+	cpc_tty = (st_cpc_tty_area *) tty->driver_data; 
+
+	if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) { 
+		CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);
+		return -ENODEV; 
+	}
+   
+	return(0); 
+} 
+
+/*
+ * PC300 TTY IOCTL routine
+ *
+ * This routine treats TIOCMBIS (set DTR signal) and TIOCMBIC (clear DTR
+ * signal)IOCTL commands. 
+ */
+static int cpc_tty_ioctl(struct tty_struct *tty, struct file *file,
+		unsigned int cmd, unsigned long arg)
+
+{
+	st_cpc_tty_area    *cpc_tty; 
+
+	if (!tty || !tty->driver_data ) {
+	   	CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n");	
+		return -ENODEV; 
+	}
+
+	cpc_tty = (st_cpc_tty_area *) tty->driver_data; 
+
+	if ((cpc_tty->tty != tty) ||  (cpc_tty->state != CPC_TTY_ST_OPEN)) { 
+		CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);
+		return -ENODEV; 
+	}
+
+	CPC_TTY_DBG("%s: IOCTL cmd %x\n",cpc_tty->name,cmd);
+	
+	switch (cmd) { 
+		case TIOCMBIS :    /* set DTR */
+			cpc_tty_dtr_on(cpc_tty->pc300dev);
+			break; 
+
+		case TIOCMBIC:     /* clear DTR */ 
+			cpc_tty_dtr_off(cpc_tty->pc300dev);
+			break; 
+		default :
+			return -ENOIOCTLCMD;
+	}
+	return 0;
+} 
+
+/*
+ * PC300 TTY Flush Buffer routine
+ *
+ * This routine resets the transmission buffer 
+ */
+static void cpc_tty_flush_buffer(struct tty_struct *tty)
+{ 
+	st_cpc_tty_area    *cpc_tty; 
+	
+	if (!tty || !tty->driver_data ) {
+	   	CPC_TTY_DBG("hdlcX-tty: no TTY to flush buffer\n");	
+		return; 
+	}
+
+	cpc_tty = (st_cpc_tty_area *) tty->driver_data; 
+
+	if ((cpc_tty->tty != tty) ||  (cpc_tty->state != CPC_TTY_ST_OPEN)) { 
+		CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);
+		return; 
+	}
+
+	CPC_TTY_DBG("%s: call wake_up_interruptible\n",cpc_tty->name);
+	
+	wake_up_interruptible(&tty->write_wait); 
+
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup){
+		CPC_TTY_DBG("%s: call line disc. wake up\n",cpc_tty->name);
+		tty->ldisc.write_wakeup(tty); 
+	} 
+
+	return; 
+} 
+
+/*
+ * PC300 TTY Hangup routine
+ *
+ * This routine is called by the tty driver to hangup the interface 
+ * o clear DTR signal
+ */
+
+static void cpc_tty_hangup(struct tty_struct *tty)
+{ 
+	st_cpc_tty_area    *cpc_tty; 
+	int res;
+
+	if (!tty || !tty->driver_data ) {
+		CPC_TTY_DBG("hdlcX-tty: no TTY to hangup\n");	
+		return ; 
+	}
+
+	cpc_tty = (st_cpc_tty_area *) tty->driver_data; 
+
+	if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) {
+		CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);
+		return ;
+	}
+	if (!cpc_tty_refcount && cpc_tty_unreg_flag) {
+		cpc_tty_unreg_flag = 0;
+		CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name);
+		if ((res=tty_unregister_driver(&serial_drv))) { 
+			CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
+							cpc_tty->name,res);
+		}
+		if ((res=tty_unregister_driver(&callout_drv))) { 
+			CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
+							cpc_tty->name,res);
+		}
+	}
+	cpc_tty_dtr_off(cpc_tty->pc300dev);
+}
+
+/*
+ * PC300 TTY RX task routine
+ * This routine treats RX task
+ * o verify read buffer
+ * o call the line disc. read
+ * o free memory
+ */
+static void cpc_tty_rx_task(void * data)
+{
+	int port, i, j;
+	st_cpc_tty_area *cpc_tty; 
+	volatile st_cpc_rx_buf * buf;
+	char flags=0,flg_rx=1; 
+
+	if (cpc_tty_cnt == 0) return;
+
+	for (i=0; (i < 4) && flg_rx ; i++) {
+		flg_rx = 0;
+		port = (int) data;
+		for (j=0; j < CPC_TTY_NPORTS; j++) {
+			cpc_tty = &cpc_tty_area[port];
+		
+			if ((buf=cpc_tty->buf_rx.first) != 0) {
+															
+				if (cpc_tty->tty && (cpc_tty->tty->ldisc.receive_buf)) { 
+					CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name);
+					cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, buf->data, 
+													&flags, buf->size);
+				}	
+				cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next;
+				kfree((unsigned char *)buf);
+				buf = cpc_tty->buf_rx.first;
+				flg_rx = 1;
+			}
+			if (++port == CPC_TTY_NPORTS) port = 0;
+		}
+	}
+} 
+
+/*
+ * PC300 TTY RX task routine
+ *
+ * This routine treats RX interrupt. 
+ * o read all frames in card
+ * o verify the frame size
+ * o read the frame in rx buffer
+ */
+static void cpc_tty_rx_disc_frame(pc300ch_t *pc300chan)
+{
+	volatile pcsca_bd_t * ptdescr; 
+	volatile unsigned char status; 
+	pc300_t *card = (pc300_t *)pc300chan->card; 
+	int ch = pc300chan->channel; 
+
+	/* dma buf read */ 
+	ptdescr = (pcsca_bd_t *)(card->hw.rambase + 
+				RX_BD_ADDR(ch, pc300chan->rx_first_bd)); 
+	while (pc300chan->rx_first_bd != pc300chan->rx_last_bd) { 
+		status = cpc_readb(&ptdescr->status); 
+		cpc_writeb(&ptdescr->status, 0); 
+		cpc_writeb(&ptdescr->len, 0); 
+		pc300chan->rx_first_bd = (pc300chan->rx_first_bd + 1) & 
+					(N_DMA_RX_BUF - 1); 
+		if (status & DST_EOM) { 
+			break; /* end of message */
+		}
+		ptdescr = (pcsca_bd_t *)(card->hw.rambase + cpc_readl(&ptdescr->next)); 
+	}
+}
+
+void cpc_tty_receive(pc300dev_t *pc300dev)
+{
+	st_cpc_tty_area    *cpc_tty; 
+	pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; 
+	pc300_t *card = (pc300_t *)pc300chan->card; 
+	int ch = pc300chan->channel; 
+	volatile pcsca_bd_t * ptdescr; 
+	struct net_device_stats *stats = &pc300dev->hdlc->stats; 
+	int rx_len, rx_aux; 
+	volatile unsigned char status; 
+	unsigned short first_bd = pc300chan->rx_first_bd;
+	st_cpc_rx_buf	*new;
+	unsigned char dsr_rx;
+
+	if (pc300dev->cpc_tty == NULL) { 
+		return; 
+	}
+
+	dsr_rx = cpc_readb(card->hw.scabase + DSR_RX(ch));
+
+	cpc_tty = (st_cpc_tty_area *)pc300dev->cpc_tty; 
+
+	while (1) { 
+		rx_len = 0;
+		ptdescr = (pcsca_bd_t *)(card->hw.rambase + RX_BD_ADDR(ch, first_bd));
+		while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) {
+			rx_len += cpc_readw(&ptdescr->len);
+			first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1);
+			if (status & DST_EOM) {
+				break;
+			}
+			ptdescr=(pcsca_bd_t*)(card->hw.rambase+cpc_readl(&ptdescr->next));
+		}
+			
+		if (!rx_len) { 
+			if (dsr_rx & DSR_BOF) {
+				/* update EDA */ 
+				cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), 
+						RX_BD_ADDR(ch, pc300chan->rx_last_bd)); 
+			}
+			return; 
+		}
+		
+		if (rx_len > CPC_TTY_MAX_MTU) { 
+			/* Free RX descriptors */ 
+			CPC_TTY_DBG("%s: frame size is invalid.\n",cpc_tty->name);
+			stats->rx_errors++; 
+			stats->rx_frame_errors++; 
+			cpc_tty_rx_disc_frame(pc300chan);
+			continue;
+		} 
+		
+		new = (st_cpc_rx_buf *) kmalloc(rx_len + sizeof(st_cpc_rx_buf), GFP_ATOMIC);
+		if (new == 0) {
+			cpc_tty_rx_disc_frame(pc300chan);
+			continue;
+		}
+		
+		/* dma buf read */ 
+		ptdescr = (pcsca_bd_t *)(card->hw.rambase + 
+				RX_BD_ADDR(ch, pc300chan->rx_first_bd)); 
+
+		rx_len = 0;	/* counter frame size */
+		
+		while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) {
+			rx_aux = cpc_readw(&ptdescr->len);
+			if ((status & (DST_OVR | DST_CRC | DST_RBIT |  DST_SHRT | DST_ABT))
+				|| (rx_aux > BD_DEF_LEN)) {
+				CPC_TTY_DBG("%s: reception error\n", cpc_tty->name);
+				stats->rx_errors++; 
+				if (status & DST_OVR) { 
+					stats->rx_fifo_errors++; 
+				}
+				if (status & DST_CRC) { 
+					stats->rx_crc_errors++; 
+				}
+				if ((status & (DST_RBIT | DST_SHRT | DST_ABT)) ||
+					(rx_aux > BD_DEF_LEN))	{ 
+					stats->rx_frame_errors++; 
+				} 
+				/* discard remainig descriptors used by the bad frame */ 
+				CPC_TTY_DBG("%s: reception error - discard descriptors",
+						cpc_tty->name);
+				cpc_tty_rx_disc_frame(pc300chan);
+				rx_len = 0;
+				kfree((unsigned char *)new);
+				break; /* read next frame - while(1) */
+			}
+
+			if (cpc_tty->state != CPC_TTY_ST_OPEN) {
+				/* Free RX descriptors */ 
+				cpc_tty_rx_disc_frame(pc300chan);
+				stats->rx_dropped++; 
+				rx_len = 0; 
+				kfree((unsigned char *)new);
+				break; /* read next frame - while(1) */
+			}
+
+			/* read the segment of the frame */
+			if (rx_aux != 0) {
+				memcpy_fromio((new->data + rx_len), 
+					(void *)(card->hw.rambase + 
+					 cpc_readl(&ptdescr->ptbuf)), rx_aux);
+				rx_len += rx_aux; 
+			}
+			cpc_writeb(&ptdescr->status,0); 
+			cpc_writeb(&ptdescr->len, 0); 
+			pc300chan->rx_first_bd = (pc300chan->rx_first_bd + 1) & 
+					(N_DMA_RX_BUF -1); 
+			if (status & DST_EOM)break;
+			
+			ptdescr = (pcsca_bd_t *) (card->hw.rambase + 
+					cpc_readl(&ptdescr->next)); 
+		}
+		/* update pointer */ 
+		pc300chan->rx_last_bd = (pc300chan->rx_first_bd - 1) & 
+					(N_DMA_RX_BUF - 1) ; 
+		if (!(dsr_rx & DSR_BOF)) {
+			/* update EDA */ 
+			cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), 
+					RX_BD_ADDR(ch, pc300chan->rx_last_bd)); 
+		}
+		if (rx_len != 0) { 
+			stats->rx_bytes += rx_len; 
+		
+			if (pc300dev->trace_on) { 
+				cpc_tty_trace(pc300dev, new->data,rx_len, 'R'); 
+			} 
+			new->size = rx_len;
+			new->next = 0;
+			if (cpc_tty->buf_rx.first == 0) {
+				cpc_tty->buf_rx.first = new;
+				cpc_tty->buf_rx.last = new;
+			} else {
+				cpc_tty->buf_rx.last->next = new;
+				cpc_tty->buf_rx.last = new;
+			}
+			schedule_task(&(cpc_tty->tty_rx_task_queue));
+			stats->rx_packets++;
+		}
+	} 
+} 
+
+/*
+ * PC300 TTY TX task routine
+ * 
+ * This routine treats TX interrupt. 
+ * o if need call line discipline wakeup
+ * o call wake_up_interruptible
+ */
+static void cpc_tty_tx_task(void *data)
+{
+	st_cpc_tty_area *cpc_tty = (st_cpc_tty_area *) data; 
+	struct tty_struct *tty; 
+
+	CPC_TTY_DBG("%s: cpc_tty_tx_task init\n",cpc_tty->name);
+	
+	if ((tty = cpc_tty->tty) == 0) { 
+		CPC_TTY_DBG("%s: the interface is not opened\n",cpc_tty->name);
+		return; 
+	}
+
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup){
+		CPC_TTY_DBG("%s:call line disc. wakeup\n",cpc_tty->name);
+		tty->ldisc.write_wakeup (tty); 
+	}
+
+	wake_up_interruptible(&tty->write_wait); 
+}
+
+/*
+ * PC300 TTY send to card routine
+ * 
+ * This routine send data to card. 
+ * o clear descriptors
+ * o write data to DMA buffers
+ * o start the transmission
+ */
+static int cpc_tty_send_to_card(pc300dev_t *dev,void* buf, int len)
+{
+	pc300ch_t *chan = (pc300ch_t *)dev->chan; 
+	pc300_t *card = (pc300_t *)chan->card; 
+	int ch = chan->channel; 
+	struct net_device_stats *stats = &dev->hdlc->stats; 
+	unsigned long flags; 
+	volatile pcsca_bd_t * ptdescr; 
+	int i, nchar;
+	int tosend = len;
+	int nbuf = ((len - 1)/BD_DEF_LEN) + 1;
+	unsigned char *pdata=buf;
+
+	CPC_TTY_DBG("%s:cpc_tty_send_to_cars len=%i", 
+			(st_cpc_tty_area *)dev->cpc_tty->name,len);	
+
+	if (nbuf >= card->chan[ch].nfree_tx_bd) {
+		return 1;
+	}
+	
+	/* write buffer to DMA buffers */ 
+	CPC_TTY_DBG("%s: call dma_buf_write\n",
+			(st_cpc_tty_area *)dev->cpc_tty->name);	
+	for (i = 0 ; i < nbuf ; i++) {
+		ptdescr = (pcsca_bd_t *)(card->hw.rambase + 
+			TX_BD_ADDR(ch, card->chan[ch].tx_next_bd));
+		nchar = (BD_DEF_LEN > tosend) ? tosend : BD_DEF_LEN;
+		if (cpc_readb(&ptdescr->status) & DST_OSB) {
+			memcpy_toio((void *)(card->hw.rambase + 
+				cpc_readl(&ptdescr->ptbuf)), 
+				&pdata[len - tosend], 
+				nchar);
+			card->chan[ch].nfree_tx_bd--;
+			if ((i + 1) == nbuf) {
+				/* This must be the last BD to be used */
+				cpc_writeb(&ptdescr->status, DST_EOM);
+			} else {
+				cpc_writeb(&ptdescr->status, 0);
+			}
+			cpc_writew(&ptdescr->len, nchar);
+		} else {
+			CPC_TTY_DBG("%s: error in dma_buf_write\n",
+					(st_cpc_tty_area *)dev->cpc_tty->name);	
+			stats->tx_dropped++;
+			return 1; 
+		}
+		tosend -= nchar;
+		card->chan[ch].tx_next_bd = 
+			(card->chan[ch].tx_next_bd + 1) & (N_DMA_TX_BUF - 1);
+	}
+
+	if (dev->trace_on) { 
+		cpc_tty_trace(dev, buf, len,'T'); 
+	}
+
+	/* start transmission */ 
+	CPC_TTY_DBG("%s: start transmission\n",
+		(st_cpc_tty_area *)dev->cpc_tty->name);	
+	
+	CPC_TTY_LOCK(card, flags); 
+	cpc_writeb(card->hw.scabase + DTX_REG(EDAL, ch), 
+			TX_BD_ADDR(ch, chan->tx_next_bd)); 
+	cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_ENA); 
+	cpc_writeb(card->hw.scabase + DSR_TX(ch), DSR_DE); 
+
+	if (card->hw.type == PC300_TE) { 
+		cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, 
+			cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) |
+			(CPLD_REG2_FALC_LED1 << (2 * ch))); 
+	}
+	CPC_TTY_UNLOCK(card, flags); 
+	return 0; 
+} 
+
+/*
+ *	PC300 TTY trace routine
+ *
+ *  This routine send trace of connection to application. 
+ *  o clear descriptors
+ *  o write data to DMA buffers
+ *  o start the transmission
+ */
+
+static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx)
+{
+	struct sk_buff *skb; 
+
+	if ((skb = dev_alloc_skb(10 + len)) == NULL) { 
+		/* out of memory */ 
+		CPC_TTY_DBG("%s: tty_trace - out of memory\n",
+			((struct net_device *)(dev->hdlc))->name);
+		return; 
+	}
+
+	skb_put (skb, 10 + len); 
+	skb->dev = (struct net_device *) dev->hdlc; 
+	skb->protocol = htons(ETH_P_CUST); 
+	skb->mac.raw = skb->data; 
+	skb->pkt_type = PACKET_HOST; 
+	skb->len = 10 + len; 
+
+	memcpy(skb->data,((struct net_device *)(dev->hdlc))->name,5);
+	skb->data[5] = '['; 
+	skb->data[6] = rxtx; 
+	skb->data[7] = ']'; 
+	skb->data[8] = ':'; 
+	skb->data[9] = ' '; 
+	memcpy(&skb->data[10], buf, len); 
+	netif_rx(skb); 
+} 	
+
+/*
+ *	PC300 TTY unregister service routine
+ *
+ *	This routine unregister one interface. 
+ */
+void cpc_tty_unregister_service(pc300dev_t *pc300dev)
+{
+	st_cpc_tty_area *cpc_tty; 
+	ulong flags;
+	int res;
+
+	if ((cpc_tty= (st_cpc_tty_area *) pc300dev->cpc_tty) == 0) { 
+		CPC_TTY_DBG("%s: interface is not TTY\n",
+			((struct net_device *)(pc300dev->hdlc))->name);
+		return; 
+	}
+	CPC_TTY_DBG("%s: cpc_tty_unregister_service", cpc_tty->name);
+
+	if (cpc_tty->pc300dev != pc300dev) { 
+		CPC_TTY_DBG("%s: invalid tty ptr=%s\n", 
+		((struct net_device *)(pc300dev->hdlc))->name, cpc_tty->name);
+		return; 
+	}
+
+	if (--cpc_tty_cnt == 0) { 
+		if (cpc_tty_refcount) {
+			CPC_TTY_DBG("%s: unregister is not possible, refcount=%d",
+							cpc_tty->name, cpc_tty_refcount);
+			cpc_tty_cnt++;
+			cpc_tty_unreg_flag = 1;
+			return;
+		} else { 
+			CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name);
+			if ((res=tty_unregister_driver(&serial_drv))) { 
+				CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
+								cpc_tty->name,res);
+			}
+			if ((res=tty_unregister_driver(&callout_drv))) { 
+				CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
+								cpc_tty->name,res);
+			}
+		}
+	}
+	CPC_TTY_LOCK(pc300dev->chan->card,flags);
+	cpc_tty->tty = NULL; 
+	CPC_TTY_UNLOCK(pc300dev->chan->card, flags);
+	cpc_tty->tty_minor = 0; 
+	cpc_tty->state = CPC_TTY_ST_IDLE; 
+} 
+
+/*
+ * PC300 TTY trigger poll routine
+ * This routine is called by pc300driver to treats Tx interrupt. 
+ */
+void cpc_tty_trigger_poll(pc300dev_t *pc300dev)
+{
+	st_cpc_tty_area *cpc_tty = (st_cpc_tty_area *)pc300dev->cpc_tty; 
+	if (!cpc_tty) {
+		return;
+	}
+	schedule_task(&(cpc_tty->tty_tx_task_queue)); 
+} 
+
+/*
+ * PC300 TTY reset var routine
+ * This routine is called by pc300driver to init the TTY area. 
+ */
+
+void cpc_tty_reset_var(void)
+{
+	int i ; 
+
+	CPC_TTY_DBG("hdlcX-tty: reset variables\n");
+	/* reset  the tty_driver structure - serial_drv */ 
+	memset(&serial_drv, 0, sizeof(struct tty_driver));
+	memset(&callout_drv, 0, sizeof(struct tty_driver));
+	for (i=0; i < CPC_TTY_NPORTS; i++){
+		memset(&cpc_tty_area[i],0, sizeof(st_cpc_tty_area)); 
+	}
+}
diff -Nru a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
--- a/drivers/net/wan/sbni.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/wan/sbni.c	Thu May  2 17:22:16 2002
@@ -330,10 +330,14 @@
 	outb( 0, ioaddr + CSR0 );
 
 	if( irq < 2 ) {
-		autoirq_setup( 5 );
+		unsigned long irq_mask, delay;
+
+		irq_mask = probe_irq_on();
 		outb( EN_INT | TR_REQ, ioaddr + CSR0 );
 		outb( PR_RES, ioaddr + CSR1 );
-		irq = autoirq_report( 5 );
+		delay = jiffies + HZ/20;
+		while (time_before(jiffies, delay)) ;
+		irq = probe_irq_off(irq_mask);
 		outb( 0, ioaddr + CSR0 );
 
 		if( !irq ) {
diff -Nru a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
--- a/drivers/net/wan/sdla.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/wan/sdla.c	Thu May  2 17:22:17 2002
@@ -1348,8 +1348,10 @@
 		return(-EINVAL);
 
 	dev->base_addr = map->base_addr;
-	request_region(dev->base_addr, SDLA_IO_EXTENTS, dev->name);
-
+	if (!request_region(dev->base_addr, SDLA_IO_EXTENTS, dev->name)){
+		printk(KERN_WARNING "SDLA: io-port 0x%04lx in use \n", dev->base_addr);
+		return(-EINVAL);
+	}
 	/* test for card types, S502A, S502E, S507, S508                 */
 	/* these tests shut down the card completely, so clear the state */
 	flp->type = SDLA_UNKNOWN;
diff -Nru a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c
--- a/drivers/net/wan/sdla_chdlc.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/wan/sdla_chdlc.c	Thu May  2 17:22:17 2002
@@ -2680,18 +2680,20 @@
 		printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname);
 
                 if(card->u.c.slarp_timer) {
+			u32 addr_net = htonl(chdlc_priv_area->IP_address);
 
-			printk(KERN_INFO "%s: Bad IP address %s received\n",
+			printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u received\n",
 				card->devname,
-				in_ntoa(ntohl(chdlc_priv_area->IP_address)));
+			       NIPQUAD(addr_net));
                         printk(KERN_INFO "%s: from remote station.\n",
 				card->devname);
 
                 }else{ 
+			u32 addr_net = htonl(chdlc_priv_area->IP_address);
 
-                        printk(KERN_INFO "%s: Bad IP address %s issued\n",
-				card->devname,
-				in_ntoa(ntohl(chdlc_priv_area->IP_address)));
+                        printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u issued\n",
+			       card->devname,
+			       NIPQUAD(addr_net));
                         printk(KERN_INFO "%s: to remote station. Local\n",
 				card->devname);
 			printk(KERN_INFO "%s: IP address must be A.B.C.1\n",
@@ -2810,16 +2812,16 @@
 		}
 
                if(err) {
-			printk(KERN_INFO "%s: Add route %s failed (%d)\n", 
-				card->devname, in_ntoa(remote_IP_addr), err);
+			printk(KERN_INFO "%s: Add route %u.%u.%u.%u failed (%d)\n", 
+				card->devname, NIPQUAD(remote_IP_addr), err);
 		} else {
 			((chdlc_private_area_t *)dev->priv)->route_status = ROUTE_ADDED;
 			printk(KERN_INFO "%s: Dynamic route added.\n",
 				card->devname);
-			printk(KERN_INFO "%s:    Local IP addr : %s\n",
-				card->devname, in_ntoa(local_IP_addr));
-			printk(KERN_INFO "%s:    Remote IP addr: %s\n",
-				card->devname, in_ntoa(remote_IP_addr));
+			printk(KERN_INFO "%s:    Local IP addr : %u.%u.%u.%u\n",
+				card->devname, NIPQUAD(local_IP_addr));
+			printk(KERN_INFO "%s:    Remote IP addr: %u.%u.%u.%u\n",
+				card->devname, NIPQUAD(remote_IP_addr));
 			chdlc_priv_area->route_removed = 0;
 		}
 		break;
@@ -2851,13 +2853,13 @@
 		if(err) {
 			printk(KERN_INFO
 				"%s: Remove route %s failed, (err %d)\n",
-					card->devname, in_ntoa(remote_IP_addr),
+					card->devname, NIPQUAD(remote_IP_addr),
 					err);
 		} else {
 			((chdlc_private_area_t *)dev->priv)->route_status =
 				NO_ROUTE;
-                        printk(KERN_INFO "%s: Dynamic route removed: %s\n",
-                                        card->devname, in_ntoa(local_IP_addr)); 
+                        printk(KERN_INFO "%s: Dynamic route removed: %u.%u.%u.%u\n",
+                                        card->devname, NIPQUAD(local_IP_addr)); 
 			chdlc_priv_area->route_removed = 1;
 		}
 		break;
diff -Nru a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c
--- a/drivers/net/wan/sdla_fr.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/wan/sdla_fr.c	Thu May  2 17:22:17 2002
@@ -152,7 +152,6 @@
 #include <asm/io.h>		/* for inb(), outb(), etc. */
 #include <linux/time.h>	 	/* for do_gettimeofday */	
 #include <linux/in.h>		/* sockaddr_in */
-#include <linux/inet.h>		/* in_ntoa(), etc... */
 #include <asm/errno.h>
 
 #include <linux/ip.h>
@@ -2809,16 +2808,15 @@
 		set_fs(fs);           /* restore old block */
 
 		if (err) {
-
 			printk(KERN_INFO 
 				"%s: Route Add failed.  Error: %d\n", 
 					card->devname,err);
-			printk(KERN_INFO "%s: Address: %s\n",
-				chan->name, in_ntoa(chan->ip_remote));
+			printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n",
+				chan->name, NIPQUAD(chan->ip_remote));
 
 		}else {
-			printk(KERN_INFO "%s: Route Added Successfully: %s\n",
-				card->devname,in_ntoa(chan->ip_remote));
+			printk(KERN_INFO "%s: Route Added Successfully: %u.%u.%u.%U\n",
+				card->devname,NIPQUAD(chan->ip_remote));
 			chan->route_flag = ROUTE_ADDED;
 		}
 		break;
@@ -2841,17 +2839,15 @@
 		set_fs(fs);    
 		
 		if (err) {
-
 			printk(KERN_INFO 
 				"%s: Deleting of route failed.  Error: %d\n", 
 					card->devname,err);
-			printk(KERN_INFO "%s: Address: %s\n",
-				dev->name,in_ntoa(chan->ip_remote) );
+			printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n",
+				dev->name,NIPQUAD(chan->ip_remote) );
 
 		} else {
-
-			printk(KERN_INFO "%s: Route Removed Sucessfuly: %s\n", 
-				card->devname,in_ntoa(ip_tmp));
+			printk(KERN_INFO "%s: Route Removed Sucessfuly: %u.%u.%u.%u\n", 
+				card->devname,NIPQUAD(ip_tmp));
 			chan->route_flag = NO_ROUTE;
 		}
 		break;
@@ -2887,8 +2883,8 @@
 		if (err) {
 			printk(KERN_INFO "%s: Adding of route failed.  Error: %d\n", 
 						card->devname,err);
-			printk(KERN_INFO "%s: Address: %s\n",
-				chan->name, in_ntoa(dev->pa_dstaddr) );
+			printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n",
+				chan->name, NIPQUAD(dev->pa_dstaddr) );
 			}
 		else {
 			chan->route_flag = ROUTE_ADDED;
@@ -2902,11 +2898,10 @@
 		set_fs(fs);           /* restore old block */
 
 		if (err) {
-
 		     printk(KERN_INFO "%s: Deleting of route failed.  Error: %d\n", 
 				card->devname,err);
-		     printk(KERN_INFO "%s: Address: %s\n",
-				dev->name,in_ntoa(dev->pa_dstaddr) );
+		     printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n",
+				dev->name,NIPQUAD(dev->pa_dstaddr) );
 		} else {
 
 		     printk(KERN_INFO "%s: Removed route.\n",
@@ -4337,8 +4332,8 @@
 	case 0x08:  // Inverse ARP request  -- Send Reply, add route.
 			
 		/* Check for valid Address */
-		printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %s\n", 
-			card->devname, in_ntoa(arphdr->ar_sip));
+		printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %u.%u.%u.%u\n", 
+			card->devname, NIPQUAD(arphdr->ar_sip));
 
 
 		/* Check that the network address is the same as ours, only
@@ -4348,15 +4343,14 @@
 		if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF && 
 		    (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != 
 		    (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){
-
 			printk(KERN_INFO 
-				"%s: Invalid PtP address. %s  InARP ignored.\n", 
-					card->devname,in_ntoa(arphdr->ar_sip));
+				"%s: Invalid PtP address. %u.%u.%u.%u  InARP ignored.\n", 
+					card->devname,NIPQUAD(arphdr->ar_sip));
 
-			printk(KERN_INFO "%s: mask %s\n", 
-				card->devname, in_ntoa(in_dev->ifa_list->ifa_mask));
-				printk(KERN_INFO "%s: local %s\n", 
-				card->devname,in_ntoa(in_dev->ifa_list->ifa_local));
+			printk(KERN_INFO "%s: mask %u.%u.%u.%u\n", 
+				card->devname, NIPQUAD(in_dev->ida_list->ifa_mask));
+				printk(KERN_INFO "%s: local %u.%u.%u.%u\n", 
+				card->devname,NIPQUAD(in_dev->ida_list->ifa_local));
 			return -1;
 		}
 
@@ -4401,8 +4395,8 @@
 	case 0x09:  // Inverse ARP reply
 
 		/* Check for valid Address */
-		printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", 
-				card->devname, in_ntoa(arphdr->ar_sip));
+		printk(KERN_INFO "%s: Recvd PtP addr %u.%u.%u.%u -InArp Reply\n", 
+				card->devname, NIPQUAD(arphdr->ar_sip));
 
 
 		/* Compare network addresses, only if network mask
@@ -4450,8 +4444,8 @@
                 case 0x08:  // Inverse ARP request  -- Send Reply, add route.
 
                         /* Check for valid Address */
-                        printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", 
-				((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
+                        printk(KERN_INFO "%s: Recvd PtP addr %u.%u.%u.%u -InArp Req\n", 
+				((fr_channel_t *)dev->priv)->name, NIPQUAD(arphdr->ar_sip));
 
 
 			if (dev->pa_mask != 0xFFFFFFFF){
@@ -4492,8 +4486,8 @@
                 case 0x09:  // Inverse ARP reply
 
                         /* Check for valid Address */
-                        printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", 
-				((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
+                        printk(KERN_INFO "%s: Recvd PtP addr %u.%u.%u.%u -InArp Reply\n", 
+				((fr_channel_t *)dev->priv)->name, NIPQUAD(arphdr->ar_sip));
 
                         if ((dev->pa_mask & arphdr->ar_sip) != (dev->pa_mask & dev->pa_addr)) {
                                 printk(KERN_INFO "%s: Invalid PtP address.  InARP ignored.\n", 
diff -Nru a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c
--- a/drivers/net/wan/sdla_ppp.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/wan/sdla_ppp.c	Thu May  2 17:22:16 2002
@@ -102,7 +102,6 @@
 #include <linux/if_arp.h>	/* ARPHRD_* defines */
 #include <asm/byteorder.h>	/* htons(), etc. */
 #include <linux/in.h>		/* sockaddr_in */
-#include <linux/inet.h>		/* in_aton(), in_ntoa() prototypes */
 
 
 /* ---- 2.4.X KERNEL SUPPORT -----------------------*/
@@ -2269,10 +2268,11 @@
 			struct in_device *in_dev = dev->ip_ptr;
 			if (in_dev != NULL ) {
 				struct in_ifaddr *ifa = in_dev->ifa_list;
-				printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", 
-					card->devname, in_ntoa(ifa->ifa_local));
-				printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", 
-						card->devname, in_ntoa(ifa->ifa_address));
+
+				printk(KERN_INFO "%s: Assigned Lcl. Addr: %u.%u.%u.%u\n", 
+					card->devname, NIPQUAD(ifa->ifa_local));
+				printk(KERN_INFO "%s: Assigned Rmt. Addr: %u.%u.%u.%u\n", 
+						card->devname, NIPQUAD(ifa->ifa_address));
 			}else{
 				printk(KERN_INFO 
 				"%s: Error: Failed to add a route for PPP interface %s\n",
@@ -2294,10 +2294,10 @@
 				"%s: An error occurred in IP assignment.\n", 
 				card->devname);
 		} else {
-			printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", 
-					card->devname, in_ntoa(dev->pa_addr));
-			printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", 
-					card->devname, in_ntoa(dev->pa_dstaddr));
+			printk(KERN_INFO "%s: Assigned Lcl. Addr: %u.%u.%u.%u\n", 
+					card->devname, NIPQUAD(dev->pa_addr));
+			printk(KERN_INFO "%s: Assigned Rmt. Addr: %u.%u.%u.%U\n", 
+					card->devname, NIPQUAD(dev->pa_dstaddr));
 		}
 	}
 
@@ -2408,16 +2408,8 @@
 			/* Debugging code used to check that IP addresses
                          * obtained from the kernel are correct */
 
-			{
-			char laddr[20];
-			char raddr[20];
-			strcpy(laddr,in_ntoa(cfg.ip_local));
-			strcpy(raddr,in_ntoa(cfg.ip_remote));
-
-                        NEX_PRINTK(KERN_INFO "Local %s Remote %s Name %s\n",
-					laddr,raddr, dev->name);
-			
-			}	
+                        NEX_PRINTK(KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n",
+					NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name);
 			break;
 
 		case WANOPT_PPP_HOST:
@@ -2436,18 +2428,9 @@
 
 			/* Debugging code used to check that IP addresses
                          * obtained from the kernel are correct */
-			{
-			char laddr[20];
-			char raddr[20];
-			strcpy(laddr,in_ntoa(cfg.ip_local));
-			strcpy(raddr,in_ntoa(cfg.ip_remote));
-
-                        NEX_PRINTK (KERN_INFO "Local %s Remote %s Name %s\n",
-					laddr,raddr, dev->name);
+                        NEX_PRINTK (KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n",
+					NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name);
 			
-			}	
-
-
 			break;
 	
 		case WANOPT_PPP_PEER:
@@ -3130,10 +3113,10 @@
 	if (err) {
 		printk (KERN_INFO "%s: Adding of route failed: %i\n",
 			card->devname,err);
-		printk (KERN_INFO "%s:	Local : %s\n",
-			card->devname,in_ntoa(ppp_priv_area->ip_local));
-		printk (KERN_INFO "%s:	Remote: %s\n",
-			card->devname,in_ntoa(ppp_priv_area->ip_remote));
+		printk (KERN_INFO "%s:	Local : %u.%u.%u.%u\n",
+			card->devname,NIPQUAD(ppp_priv_area->ip_local));
+		printk (KERN_INFO "%s:	Remote: %u.%u.%u.%u\n",
+			card->devname,NIPQUAD(ppp_priv_area->ip_remote));
 	}
 	return err;
 }
@@ -3212,8 +3195,8 @@
 			 card->devname, err);
 		return;
 	}else{
-		printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfuly\n",
-			card->devname, in_ntoa(ip_addr));
+		printk (KERN_INFO "%s: PPP Deleting dynamic route %u.%u.%u.%u successfuly\n",
+			card->devname, NIPQUAD(ip_addr));
 	}
 	return;
 }
diff -Nru a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
--- a/drivers/net/wan/sealevel.c	Thu May  2 17:22:17 2002
+++ b/drivers/net/wan/sealevel.c	Thu May  2 17:22:17 2002
@@ -219,12 +219,11 @@
 	 *	Get the needed I/O space
 	 */
 	 
-	if(check_region(iobase, 8))
+	if(!request_region(iobase, 8, "Sealevel 4021")) 
 	{	
 		printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase);
 		return NULL;
 	}
-	request_region(iobase, 8, "Sealevel 4021");
 	
 	b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL);
 	if(!b)
diff -Nru a/drivers/net/wd.c b/drivers/net/wd.c
--- a/drivers/net/wd.c	Thu May  2 17:22:16 2002
+++ b/drivers/net/wd.c	Thu May  2 17:22:16 2002
@@ -235,18 +235,23 @@
 		int reg4 = inb(ioaddr+4);
 		if (ancient || reg1 == 0xff) {	/* Ack!! No way to read the IRQ! */
 			short nic_addr = ioaddr+WD_NIC_OFFSET;
+			unsigned long irq_mask, delay;
 
 			/* We have an old-style ethercard that doesn't report its IRQ
 			   line.  Do autoirq to find the IRQ line. Note that this IS NOT
 			   a reliable way to trigger an interrupt. */
 			outb_p(E8390_NODMA + E8390_STOP, nic_addr);
 			outb(0x00, nic_addr+EN0_IMR);	/* Disable all intrs. */
-			autoirq_setup(0);
+			
+			irq_mask = probe_irq_on();
 			outb_p(0xff, nic_addr + EN0_IMR);	/* Enable all interrupts. */
 			outb_p(0x00, nic_addr + EN0_RCNTLO);
 			outb_p(0x00, nic_addr + EN0_RCNTHI);
 			outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */
-			dev->irq = autoirq_report(2);
+			delay = jiffies + HZ/50;
+			while (time_before(jiffies, delay)) ;
+			dev->irq = probe_irq_off(irq_mask);
+			
 			outb_p(0x00, nic_addr+EN0_IMR);	/* Mask all intrs. again. */
 
 			if (ei_debug > 2)
diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids
--- a/drivers/pci/pci.ids	Thu May  2 17:22:15 2002
+++ b/drivers/pci/pci.ids	Thu May  2 17:22:15 2002
@@ -2924,10 +2924,12 @@
 	0105  Cyclom_8Y above first megabyte
 	0200  Cyclom_Z below first megabyte
 	0201  Cyclom_Z above first megabyte
-	0300  PC300 RX 2
-	0301  PC300 RX 1
-	0310  PC300 TE 2
-	0311  PC300 TE 1
+	0300  PC300/RSV or /X21 (2 ports)
+	0301  PC300/RSV or /X21 (1 ports)
+	0310  PC300/TE (2 ports)
+	0311  PC300/TE (1 port)
+	0320  PC300/TE-M (2 ports)
+	0321  PC300/TE-M (1 port)
 120f  Essential Communications
 	0001  Roadrunner serial HIPPI
 1210  Hyperparallel Technologies
diff -Nru a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
--- a/drivers/s390/block/dasd.c	Thu May  2 17:22:17 2002
+++ b/drivers/s390/block/dasd.c	Thu May  2 17:22:17 2002
@@ -716,13 +716,6 @@
 		goto out_blk_size;
 	memset (blk_size[major], 0, (1 << MINORBITS) * sizeof (int));
 
-        /* init blksize_size */
-	blksize_size[major] =
-	    (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
-	if (!blksize_size[major])
-		goto out_blksize_size;
-	memset (blksize_size[major], 0, (1 << MINORBITS) * sizeof (int));
-
 	/* finally do the gendisk stuff */
 	major_info->gendisk.part = kmalloc ((1 << MINORBITS) *
 					    sizeof (struct hd_struct),
@@ -741,10 +734,6 @@
 
         /* error handling - free the prior allocated memory */  
       out_gendisk:
-	kfree (blksize_size[major]);
-	blksize_size[major] = NULL;
-
-      out_blksize_size:
 	kfree (blk_size[major]);
 	blk_size[major] = NULL;
 
@@ -801,7 +790,6 @@
 	kfree (major_info->gendisk.part);
 
 	kfree (blk_size[major]);
-	kfree (blksize_size[major]);
 
 	blk_clear(major);
 
@@ -3339,7 +3327,6 @@
                                  sizes.s2b_shift) >> 1;
                 else
                         device->major_info->gendisk.sizes[minor + i] = 0;
-                blksize_size[major][minor + i] = device->sizes.bp_block;
 		blk_queue_max_sectors(device->request_queue,
 		 device->discipline->max_blocks << device->sizes.s2b_shift);
 		device->major_info->gendisk.part[minor+i].start_sect = 0;
@@ -3369,7 +3356,6 @@
         for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
                 destroy_buffers(MKDEV(major,minor+i));
                 device->major_info->gendisk.sizes[minor + i] = 0;
-                blksize_size[major][minor + i] = 0;
         }
         if (device->request_queue) {
             blk_cleanup_queue (device->request_queue);
diff -Nru a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
--- a/drivers/s390/block/xpram.c	Thu May  2 17:22:17 2002
+++ b/drivers/s390/block/xpram.c	Thu May  2 17:22:17 2002
@@ -189,7 +189,6 @@
 /* The following items are obtained through kmalloc() in init_module() */
 
 Xpram_Dev *xpram_devices = NULL;
-int *xpram_blksizes = NULL;
 int *xpram_offsets = NULL;   /* partition offsets */
 
 #define MIN(x,y) ((x) < (y) ? (x) : (y))
@@ -1062,16 +1061,6 @@
 		PRINT_DEBUG(" device(%d) offset = %d kB, size = %d kB\n",i, xpram_offsets[i], xpram_sizes[i]);
 #endif
 
-	xpram_blksizes = kmalloc(xpram_devs * sizeof(int), GFP_KERNEL);
-	if (!xpram_blksizes) {
-		PRINT_ERR("Not enough memory for xpram_blksizes\n");
-                PRINT_ERR("Giving up xpram\n");
-		goto fail_malloc_blksizes;
-	}
-	for (i=0; i < xpram_devs; i++) /* all the same blocksize */
-		xpram_blksizes[i] = xpram_blksize;
-	blksize_size[major]=xpram_blksizes;
-
 	/* 
 	 * allocate the devices -- we can't have them static, as the number
 	 * can be specified at load time
@@ -1142,10 +1131,7 @@
 	}
 	kfree(xpram_devices);
 #endif /* V24 */
- fail_malloc_blksizes:
 	kfree (xpram_offsets);
-	kfree (xpram_blksizes);
-	blksize_size[major] = NULL;
  fail_malloc_devices:
  fail_malloc:
 #if (XPRAM_VERSION == 22)
@@ -1183,7 +1169,6 @@
 #if (XPRAM_VERSION == 22)
 	blk_dev[major].request_fn = NULL;
 #endif /* V22 */
-	kfree(blksize_size[major]);
 	kfree(xpram_offsets);
 	blk_clear(major);
 
diff -Nru a/drivers/s390/char/tape34xx.c b/drivers/s390/char/tape34xx.c
--- a/drivers/s390/char/tape34xx.c	Thu May  2 17:22:16 2002
+++ b/drivers/s390/char/tape34xx.c	Thu May  2 17:22:16 2002
@@ -1344,11 +1344,13 @@
 	ccw1_t *ccw;
 	__u8 *data;
 	kdev_t dev = mk_kdev(tapeblock_major, ti->blk_minor);
-	unsigned bsize = block_size(dev);
+	struct block_device *bdev = bdget(kdev_t_to_nr(dev));
+	unsigned bsize = block_size(bdev);
 	int s2b = bsize/queue_hardsect_size(&ti->request_queue);
 	int realcount;
 	int size,bhct = 0;
 	struct buffer_head* bh;
+	bdput(bdev);
 	for (bh = req->bh; bh; bh = bh->b_reqnext) {
 		if (bh->b_size > bsize)
 			for (size = 0; size < bh->b_size; size += bsize)
diff -Nru a/drivers/s390/char/tapeblock.c b/drivers/s390/char/tapeblock.c
--- a/drivers/s390/char/tapeblock.c	Thu May  2 17:22:16 2002
+++ b/drivers/s390/char/tapeblock.c	Thu May  2 17:22:16 2002
@@ -74,8 +74,8 @@
 void 
 tapeblock_setup(tape_info_t* ti) {
     blk_size[tapeblock_major][ti->blk_minor]=0; // this will be detected
-    blksize_size[tapeblock_major][ti->blk_minor]=2048; // blocks are 2k by default.
     blk_init_queue (&ti->request_queue, tape_request_fn); 
+    blk_queue_hardsect_size(&ti->request_queue, 2048);
 #ifdef CONFIG_DEVFS_FS
     tapeblock_mkdevfstree(ti);
 #endif
@@ -103,8 +103,6 @@
     PRINT_WARN(KERN_ERR " tape gets major %d for block device\n", result);
     blk_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC);
     memset(blk_size[tapeblock_major],0,256*sizeof(int));
-    blksize_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC);
-    memset(blksize_size[tapeblock_major],0,256*sizeof(int));
     max_sectors[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC);
     memset(max_sectors[tapeblock_major],0,256*sizeof(int));
     blkfront = kmalloc(sizeof(tape_frontend_t),GFP_KERNEL);
@@ -585,6 +583,6 @@
 	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 	losize=(hisize+losize)/2+1;
     }
-    blk_size[tapeblock_major][ti->blk_minor]=(losize)*(blksize_size[tapeblock_major][ti->blk_minor]/1024);
+    blk_size[tapeblock_major][ti->blk_minor]=losize*2;
     return 0;
 }
diff -Nru a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
--- a/drivers/sbus/char/jsflash.c	Thu May  2 17:22:17 2002
+++ b/drivers/sbus/char/jsflash.c	Thu May  2 17:22:17 2002
@@ -135,7 +135,6 @@
 
 /*
  */
-static int jsfd_blksizes[JSF_MAX];
 static int jsfd_sizes[JSF_MAX];
 static u64 jsfd_bytesizes[JSF_MAX];
 
@@ -665,7 +664,6 @@
 		return -EIO;
 	}
 
-	blksize_size[JSFD_MAJOR] = jsfd_blksizes;
 	blk_size[JSFD_MAJOR] = jsfd_sizes;
 
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
@@ -676,7 +674,6 @@
 
 		jdp->refcnt = 0;
 
-		jsfd_blksizes[i] = 1024;
 		jsfd_bytesizes[i] = jdp->dsize;
 		jsfd_sizes[i] = jsfd_bytesizes[i] >> 10;
 		register_disk(NULL, MKDEV(JSFD_MAJOR, i), 1, &jsfd_fops,
diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
--- a/drivers/scsi/BusLogic.c	Thu May  2 17:22:17 2002
+++ b/drivers/scsi/BusLogic.c	Thu May  2 17:22:17 2002
@@ -2792,8 +2792,8 @@
 	released, thereby preventing it from being incorrectly identified as
 	any other type of Host Adapter.
       */
-      request_region(HostAdapter->IO_Address, HostAdapter->AddressCount,
-		     "BusLogic");
+      if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount,
+		     "BusLogic")) continue;
       /*
 	Register the SCSI Host structure.
       */
@@ -2834,11 +2834,20 @@
 	  */
 	  release_region(HostAdapter->IO_Address,
 			 HostAdapter->AddressCount);
-	  request_region(HostAdapter->IO_Address,
-			 HostAdapter->AddressCount,
-			 HostAdapter->FullModelName);
-	  BusLogic_InitializeHostStructure(HostAdapter, Host);
-	  BusLogicHostAdapterCount++;
+	  if(!request_region(HostAdapter->IO_Address,
+			     HostAdapter->AddressCount,
+			     HostAdapter->FullModelName)) {
+		  printk(KERN_WARNING "BusLogic: Release and re-register of "
+			 "port 0x%04lx failed \n", HostAdapter->IO_Address);
+		  BusLogic_DestroyCCBs(HostAdapter);
+		  BusLogic_ReleaseResources(HostAdapter);
+		  BusLogic_UnregisterHostAdapter(HostAdapter);
+		  scsi_unregister(Host);
+	  }
+	  else {
+		  BusLogic_InitializeHostStructure(HostAdapter, Host);
+		  BusLogicHostAdapterCount++;
+	  }
 	}
       else
 	{
diff -Nru a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
--- a/drivers/scsi/aha152x.c	Thu May  2 17:22:15 2002
+++ b/drivers/scsi/aha152x.c	Thu May  2 17:22:15 2002
@@ -13,9 +13,14 @@
  * General Public License for more details.
  *
  *
- * $Id: aha152x.c,v 2.4 2000/12/16 12:53:56 fischer Exp $
+ * $Id: aha152x.c,v 2.5 2002/04/14 11:24:53 fischer Exp $
  *
  * $Log: aha152x.c,v $
+ * Revision 2.5  2002/04/14 11:24:53  fischer
+ * - isapnp support
+ * - abort fixed
+ * - 2.5 support
+ *
  * Revision 2.4  2000/12/16 12:53:56  fischer
  * - allow REQUEST SENSE to be queued
  * - handle shared PCI interrupts
@@ -222,7 +227,9 @@
 #endif
 
 #include <linux/sched.h>
+#include <asm/irq.h>
 #include <asm/io.h>
+#include <linux/version.h>
 #include <linux/blk.h>
 #include "scsi.h"
 #include "sd.h"
@@ -306,15 +313,17 @@
 
 #define DELAY_DEFAULT 1000
 
-/* possible irq range */
 #if defined(PCMCIA)
 #define IRQ_MIN 0
 #define IRQ_MAX 16
 #else
 #define IRQ_MIN 9
+#if defined(__PPC)
+#define IRQ_MAX (NR_IRQS-1)
+#else
 #define IRQ_MAX 12
 #endif
-#define IRQS    IRQ_MAX-IRQ_MIN+1
+#endif
 
 enum {
 	not_issued	= 0x0001,	/* command not yet issued */
@@ -417,7 +426,7 @@
 	char *conf;
 } setup[2];
 
-static struct Scsi_Host *aha152x_host[IRQS];
+static struct Scsi_Host *aha152x_host[2];
 
 /*
  * internal states of the host
@@ -593,6 +602,7 @@
 #define SCDONE(SCpnt)		SCDATA(SCpnt)->done
 #define SCSEM(SCpnt)		SCDATA(SCpnt)->sem
 
+#define SG_ADDRESS(buffer)	((char *) (page_address((buffer)->page)+(buffer)->offset))
 
 /* state handling */
 static void seldi_run(struct Scsi_Host *shpnt);
@@ -668,7 +678,6 @@
 
 /* possible i/o addresses for the AIC-6260; default first */
 static unsigned short ports[] = { 0x340, 0x140 };
-#define PORT_COUNT (sizeof(ports) / sizeof(unsigned short))
 
 #if !defined(SKIP_BIOSTEST)
 /* possible locations for the Adaptec BIOS; defaults first */
@@ -684,7 +693,6 @@
 	0xeb800,		/* VTech Platinum SMP */
 	0xf0000,
 };
-#define ADDRESS_COUNT (sizeof(addresses) / sizeof(unsigned int))
 
 /* signatures for various AIC-6[23]60 based controllers.
    The point in detecting signatures is to avoid useless and maybe
@@ -726,8 +734,6 @@
 	{ "DTC3520A Host Adapter BIOS", 0x318a, 26 },
 		/* DTC 3520A ISA SCSI */
 };
-
-#define SIGNATURE_COUNT (sizeof(signatures) / sizeof(struct signature))
 #endif
 
 
@@ -806,7 +812,7 @@
 #if defined(PCMCIA) || !defined(MODULE)
 void aha152x_setup(char *str, int *ints)
 {
-	if(setup_count>2) {
+	if(setup_count>=ARRAY_SIZE(setup)) {
 		printk(KERN_ERR "aha152x: you can only configure up to two controllers\n");
 		return;
 	}
@@ -849,7 +855,7 @@
 #endif
 	int count=setup_count;
 
-	get_options(str, sizeof(ints)/sizeof(int), ints);
+	get_options(str, ARRAY_SIZE(ints), ints);
 	aha152x_setup(str,ints);
 
 	return count<setup_count;
@@ -903,10 +909,10 @@
 
 #if !defined(PCMCIA)
 	int i;
-	for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++)
+	for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++)
 		;
 
-	if (i == PORT_COUNT)
+	if (i == ARRAY_SIZE(ports))
 		return 0;
 #endif
 
@@ -939,12 +945,25 @@
 	return 1;
 }
 
+static inline struct Scsi_Host *lookup_irq(int irqno)
+{
+	int i;
+
+	for(i=0; i<ARRAY_SIZE(aha152x_host); i++)
+		if(aha152x_host[i] && aha152x_host[i]->irq==irqno)
+			return aha152x_host[i];
+
+	return 0;
+}
+
 static void swintr(int irqno, void *dev_id, struct pt_regs *regs)
 {
-	struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN];
+	struct Scsi_Host *shpnt = lookup_irq(irqno);
 
-	if (!shpnt)
-        	printk(KERN_ERR "aha152x%d: catched software interrupt for unknown controller.\n", HOSTNO);
+	if (!shpnt) {
+        	printk(KERN_ERR "aha152x%d: catched software interrupt %d for unknown controller.\n", HOSTNO, irqno);
+		return;
+	}
 
 	HOSTDATA(shpnt)->swint++;
 
@@ -966,7 +985,7 @@
 #endif
 	tpnt->proc_name = "aha152x"; 
 
-	for (i = 0; i < IRQS; i++)
+	for (i = 0; i < ARRAY_SIZE(aha152x_host); i++)
 		aha152x_host[i] = (struct Scsi_Host *) NULL;
 
 	if (setup_count) {
@@ -981,7 +1000,7 @@
 	}
 
 #if defined(SETUP0)
-	if (setup_count < 2) {
+	if (setup_count < ARRAY_SIZE(setup)) {
 		struct aha152x_setup override = SETUP0;
 
 		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
@@ -1002,7 +1021,7 @@
 #endif
 
 #if defined(SETUP1)
-	if (setup_count < 2) {
+	if (setup_count < ARRAY_SIZE(setup)) {
 		struct aha152x_setup override = SETUP1;
 
 		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
@@ -1023,7 +1042,7 @@
 #endif
 
 #if defined(MODULE)
-	if (setup_count<2 && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) {
+	if (setup_count<ARRAY_SIZE(setup) && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) {
 		if(aha152x[0]!=0) {
 			setup[setup_count].conf        = "";
 			setup[setup_count].io_port     = aha152x[0];
@@ -1066,7 +1085,7 @@
 			       setup[setup_count].ext_trans);
 	}
 
-	if (setup_count < 2 && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) {
+	if (setup_count<ARRAY_SIZE(setup) && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) {
 		if(aha152x1[0]!=0) {
 			setup[setup_count].conf        = "";
 			setup[setup_count].io_port     = aha152x1[0];
@@ -1110,7 +1129,7 @@
 #endif
 
 #ifdef __ISAPNP__
-	while ( setup_count<2 && (dev=isapnp_find_dev(NULL, ISAPNP_VENDOR('A','D','P'), ISAPNP_FUNCTION(0x1505), dev)) ) {
+	while ( setup_count<ARRAY_SIZE(setup) && (dev=isapnp_find_dev(NULL, ISAPNP_VENDOR('A','D','P'), ISAPNP_FUNCTION(0x1505), dev)) ) {
 		if (dev->prepare(dev) < 0)
 			continue;
 		if (dev->active)
@@ -1145,11 +1164,11 @@
 
 
 #if defined(AUTOCONF)
-	if (setup_count < 2) {
+	if (setup_count<ARRAY_SIZE(setup)) {
 #if !defined(SKIP_BIOSTEST)
 		ok = 0;
-		for (i = 0; i < ADDRESS_COUNT && !ok; i++)
-			for (j = 0; (j < SIGNATURE_COUNT) && !ok; j++)
+		for (i = 0; i < ARRAY_SIZE(addresses) && !ok; i++)
+			for (j = 0; j<ARRAY_SIZE(signatures) && !ok; j++)
 				ok = isa_check_signature(addresses[i] + signatures[j].sig_offset,
 								signatures[j].signature, signatures[j].sig_length);
 
@@ -1162,7 +1181,7 @@
 #endif				/* !SKIP_BIOSTEST */
 
 		ok = 0;
-		for (i = 0; i < PORT_COUNT && setup_count < 2; i++) {
+		for (i = 0; i < ARRAY_SIZE(ports) && setup_count < 2; i++) {
 			if ((setup_count == 1) && (setup[0].io_port == ports[i]))
 				continue;
 
@@ -1217,7 +1236,7 @@
 	for (i=0; i<setup_count; i++) {
 		struct Scsi_Host *shpnt;
 
-		aha152x_host[setup[i].irq - IRQ_MIN] = shpnt =
+		aha152x_host[registered_count] = shpnt =
 		    scsi_register(tpnt, sizeof(struct aha152x_hostdata));
 
 		if(!shpnt) {
@@ -1341,7 +1360,7 @@
 			scsi_unregister(shpnt);
 			registered_count--;
 			release_region(shpnt->io_port, IO_RANGE);
-			aha152x_host[shpnt->irq - IRQ_MIN] = 0;
+			aha152x_host[registered_count] = 0;
 			shpnt = 0;
 			continue;
 		}
@@ -1349,9 +1368,7 @@
 
 		printk(KERN_INFO "aha152x%d: trying software interrupt, ", HOSTNO);
 		SETPORT(DMACNTRL0, SWINT|INTEN);
-		spin_unlock_irq(shpnt->host_lock);
 		mdelay(1000);
-		spin_lock_irq(shpnt->host_lock);
 		free_irq(shpnt->irq, shpnt);
 
 		if (!HOSTDATA(shpnt)->swint) {
@@ -1367,7 +1384,7 @@
 
 			registered_count--;
 			release_region(shpnt->io_port, IO_RANGE);
-			aha152x_host[shpnt->irq - IRQ_MIN] = 0;
+			aha152x_host[registered_count] = 0;
 			scsi_unregister(shpnt);
 			shpnt=NULL;
 			continue;
@@ -1382,10 +1399,11 @@
 		if (request_irq(shpnt->irq, intr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) < 0) {
 			printk(KERN_ERR "aha152x%d: failed to reassign interrupt.\n", HOSTNO);
 
-			scsi_unregister(shpnt);
 			registered_count--;
 			release_region(shpnt->io_port, IO_RANGE);
-			shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0;
+			aha152x_host[registered_count] = 0;
+			scsi_unregister(shpnt);
+			shpnt=NULL;
 			continue;
 		}
 	}
@@ -1494,7 +1512,7 @@
 	   SCp.phase            : current state of the command */
 	if (SCpnt->use_sg) {
 		SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->request_buffer;
-		SCpnt->SCp.ptr              = SCpnt->SCp.buffer->address;
+		SCpnt->SCp.ptr              = SG_ADDRESS(SCpnt->SCp.buffer);
 		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
 		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
 	} else {
@@ -1584,7 +1602,6 @@
 	if(HOSTDATA(shpnt)->debug & debug_eh) {
 		printk(DEBUG_LEAD "abort(%p)", CMDINFO(SCpnt), SCpnt);
 		show_queues(shpnt);
-		mdelay(1000);
 	}
 #endif
 
@@ -1622,9 +1639,19 @@
 
 static void timer_expired(unsigned long p)
 {
-	struct semaphore *sem = (void *)p;
+	Scsi_Cmnd	 *SCp   = (Scsi_Cmnd *)p;
+	struct semaphore *sem   = SCSEM(SCp);
+	struct Scsi_Host *shpnt = SCp->host;
+
+	/* remove command from issue queue */
+	if(remove_SC(&ISSUE_SC, SCp)) {
+		printk(KERN_INFO "aha152x: ABORT timed out - removed from issue queue\n");
+		kfree(SCp->host_scribble);
+		SCp->host_scribble=0;
+	} else {
+		printk(KERN_INFO "aha152x: ABORT timed out - not on issue queue\n");
+	}
 
-	printk(KERN_INFO "aha152x: timer expired\n");
 	up(sem);
 }
 
@@ -1645,7 +1672,6 @@
 	if(HOSTDATA(shpnt)->debug & debug_eh) {
 		printk(INFO_LEAD "aha152x_device_reset(%p)", CMDINFO(SCpnt), SCpnt);
 		show_queues(shpnt);
-		mdelay(1000);
 	}
 #endif
 
@@ -1663,13 +1689,13 @@
 	cmnd.request_bufflen = 0;
 
 	init_timer(&timer);
-	timer.data     = (unsigned long) &sem;
+	timer.data     = (unsigned long) &cmnd;
 	timer.expires  = jiffies + 100*HZ;   /* 10s */
 	timer.function = (void (*)(unsigned long)) timer_expired;
-	add_timer(&timer);
 
 	aha152x_internal_queue(&cmnd, &sem, resetting, 0, internal_done);
 
+	add_timer(&timer);
 	down(&sem);
 
 	del_timer(&timer);
@@ -1719,7 +1745,6 @@
 	if(HOSTDATA(shpnt)->debug & debug_eh) {
 		printk(DEBUG_LEAD "aha152x_bus_reset(%p)", CMDINFO(SCpnt), SCpnt);
 		show_queues(shpnt);
-		mdelay(1000);
 	}
 #endif
 
@@ -1878,7 +1903,7 @@
 static void run(void)
 {
 	int i;
-	for (i = 0; i < IRQS; i++) {
+	for (i = 0; i<ARRAY_SIZE(aha152x_host); i++) {
 		struct Scsi_Host *shpnt = aha152x_host[i];
 		if (shpnt && HOSTDATA(shpnt)->service) {
 			HOSTDATA(shpnt)->service=0;
@@ -1894,10 +1919,10 @@
 
 static void intr(int irqno, void *dev_id, struct pt_regs *regs)
 {
-	struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN];
+	struct Scsi_Host *shpnt = lookup_irq(irqno);
 
 	if (!shpnt) {
-		printk(KERN_ERR "aha152x: catched interrupt for unknown controller.\n");
+		printk(KERN_ERR "aha152x: catched interrupt %d for unknown controller.\n", irqno);
 		return;
 	}
 
@@ -2681,7 +2706,7 @@
                                		/* advance to next buffer */
                                		CURRENT_SC->SCp.buffers_residual--;
                                		CURRENT_SC->SCp.buffer++;
-                               		CURRENT_SC->SCp.ptr           = CURRENT_SC->SCp.buffer->address;
+                               		CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
                                		CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
 				} 
                 	}
@@ -2791,7 +2816,7 @@
 			/* advance to next buffer */
 			CURRENT_SC->SCp.buffers_residual--;
 			CURRENT_SC->SCp.buffer++;
-			CURRENT_SC->SCp.ptr           = CURRENT_SC->SCp.buffer->address;
+			CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
 			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
 		}
 
@@ -2821,13 +2846,13 @@
 		CURRENT_SC->resid += data_count;
 
 		if(CURRENT_SC->use_sg) {
-			data_count -= CURRENT_SC->SCp.ptr - CURRENT_SC->SCp.buffer->address;
+			data_count -= CURRENT_SC->SCp.ptr - SG_ADDRESS(CURRENT_SC->SCp.buffer);
 			while(data_count>0) {
 				CURRENT_SC->SCp.buffer--;
 				CURRENT_SC->SCp.buffers_residual++;
 				data_count -= CURRENT_SC->SCp.buffer->length;
 			}
-			CURRENT_SC->SCp.ptr           = CURRENT_SC->SCp.buffer->address - data_count;
+			CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer) - data_count;
 			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count;
 		} else {
 			CURRENT_SC->SCp.ptr           -= data_count;
@@ -2955,10 +2980,9 @@
 	int pending;
 
 	DO_LOCK(flags);
-	if(HOSTDATA(shpnt)->in_intr!=0)
-	{
+	if(HOSTDATA(shpnt)->in_intr!=0) {
 		DO_UNLOCK(flags);
-		/* _error never returns.. */
+		/* aha152x_error never returns.. */
 		aha152x_error(shpnt, "bottom-half already running!?");
 	}
 	HOSTDATA(shpnt)->in_intr++;
@@ -3765,7 +3789,7 @@
 	unsigned long flags;
 	int thislength;
 
-	for (i = 0, shpnt = (struct Scsi_Host *) NULL; i < IRQS; i++)
+	for (i = 0, shpnt = (struct Scsi_Host *) NULL; i<ARRAY_SIZE(aha152x_host); i++)
 		if (aha152x_host[i] && aha152x_host[i]->host_no == hostno)
 			shpnt = aha152x_host[i];
 
diff -Nru a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h
--- a/drivers/scsi/aha152x.h	Thu May  2 17:22:17 2002
+++ b/drivers/scsi/aha152x.h	Thu May  2 17:22:17 2002
@@ -2,7 +2,7 @@
 #define _AHA152X_H
 
 /*
- * $Id: aha152x.h,v 2.4 2000/12/16 12:48:48 fischer Exp $
+ * $Id: aha152x.h,v 2.5 2002/04/14 11:24:12 fischer Exp $
  */
 
 #if defined(__KERNEL__)
@@ -27,7 +27,7 @@
    (unless we support more than 1 cmd_per_lun this should do) */
 #define AHA152X_MAXQUEUE 7
 
-#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 2.4 $"
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 2.5 $"
 
 /* Initial value of Scsi_Host entry */
 #define AHA152X { proc_name:			"aha152x",		\
diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
--- a/drivers/scsi/cpqfcTSinit.c	Thu May  2 17:22:15 2002
+++ b/drivers/scsi/cpqfcTSinit.c	Thu May  2 17:22:15 2002
@@ -41,9 +41,9 @@
 #include <linux/timer.h>
 #include <linux/ioport.h>  // request_region() prototype
 #include <linux/vmalloc.h> // ioremap()
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
+//#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
 #include <linux/completion.h>
-#endif
+//#endif
 #ifdef __alpha__
 #define __KERNEL_SYSCALLS__
 #endif
@@ -532,7 +532,7 @@
 
 	// must be super user to send stuff directly to the
 	// controller and/or physical drives...
-	if( !suser() )
+	if( !capable(CAP_SYS_ADMIN) )
 	  return -EPERM;
 
 	// copy the caller's struct to our space.
diff -Nru a/drivers/scsi/cpqfcTSstructs.h b/drivers/scsi/cpqfcTSstructs.h
--- a/drivers/scsi/cpqfcTSstructs.h	Thu May  2 17:22:16 2002
+++ b/drivers/scsi/cpqfcTSstructs.h	Thu May  2 17:22:16 2002
@@ -226,7 +226,6 @@
 #define ELS_PRLI_ACC 0x22  // {FCP-SCSI} Process Login Accept
 #define ELS_RJT 0x1000000
 #define SCSI_REPORT_LUNS 0x0A0
-#define REPORT_LUNS 0xA0 // SCSI-3 command op-code
 #define FCP_TARGET_RESET 0x200
 
 #define ELS_LILP_FRAME 0x00000711 // 1st payload word of LILP frame
diff -Nru a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
--- a/drivers/scsi/megaraid.c	Thu May  2 17:22:15 2002
+++ b/drivers/scsi/megaraid.c	Thu May  2 17:22:15 2002
@@ -3009,11 +3009,10 @@
 
 		if (!(flag & BOARD_QUARTZ)) {
 			/* Request our IO Range */
-			if (check_region (megaBase, 16)) {
+			if (!request_region(megaBase, 16, "megaraid")) {
 				printk(KERN_WARNING "megaraid: Couldn't register I/O range!\n");
 				goto err_unregister;
 			}
-			request_region(megaBase, 16, "megaraid");
 		}
 
 		/* Request our IRQ */
diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c	Thu May  2 17:22:15 2002
+++ b/drivers/scsi/scsi_error.c	Thu May  2 17:22:15 2002
@@ -1013,13 +1013,7 @@
 			SCpnt->flags &= ~IS_RESETTING;
 			goto maybe_retry;
 		}
-		/*
-		 * Examine the sense data to figure out how to proceed from here.
-		 * If there is no sense data, we will be forced into the error
-		 * handler thread, where we get to examine the thing in a lot more
-		 * detail.
-		 */
-		return scsi_check_sense(SCpnt);
+		return SUCCESS;
 	default:
 		return FAILED;
 	}
@@ -2001,6 +1995,7 @@
 
 	return rtn;
 }
+
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -Nru a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c
--- a/drivers/scsi/scsi_merge.c	Thu May  2 17:22:17 2002
+++ b/drivers/scsi/scsi_merge.c	Thu May  2 17:22:17 2002
@@ -136,7 +136,7 @@
  			 * hardware have no practical limit.
 			 */
 			bounce_limit = BLK_BOUNCE_ANY;
-		else
+		else if (SHpnt->pci_dev)
 			bounce_limit = SHpnt->pci_dev->dma_mask;
 	} else if (SHpnt->unchecked_isa_dma)
 		bounce_limit = BLK_BOUNCE_ISA;
diff -Nru a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c
--- a/drivers/scsi/scsicam.c	Thu May  2 17:22:15 2002
+++ b/drivers/scsi/scsicam.c	Thu May  2 17:22:15 2002
@@ -41,7 +41,7 @@
 		err = blkdev_get(bdev, FMODE_READ, 0, BDEV_FILE);
 		if (err)
 			goto fail;
-		bh = __bread(bdev, 0, block_size(rdev));
+		bh = __bread(bdev, 0, block_size(bdev));
 		if (!bh)
 			goto fail2;
 		memcpy(res, bh->b_data + 0x1be, 66);
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Thu May  2 17:22:16 2002
+++ b/drivers/scsi/sd.c	Thu May  2 17:22:16 2002
@@ -5,29 +5,28 @@
  *      Linux scsi disk driver
  *              Initial versions: Drew Eckhardt
  *              Subsequent revisions: Eric Youngdale
+ *	Modification history:
+ *       - Drew Eckhardt <drew@colorado.edu> original
+ *       - Eric Youngdale <eric@andante.org> add scatter-gather, multiple 
+ *         outstanding request, and other enhancements.
+ *         Support loadable low-level scsi drivers.
+ *       - Jirka Hanika <geo@ff.cuni.cz> support more scsi disks using 
+ *         eight major numbers.
+ *       - Richard Gooch <rgooch@atnf.csiro.au> support devfs.
+ *	 - Torben Mathiasen <tmm@image.dk> Resource allocation fixes in 
+ *	   sd_init and cleanups.
+ *	 - Alex Davis <letmein@erols.com> Fix problem where partition info
+ *	   not being read in sd_open. Fix problem where removable media 
+ *	   could be ejected after sd_open.
+ *	 - Douglas Gilbert <dgilbert@interlog.com> cleanup for lk 2.5 series
  *
- *      <drew@colorado.edu>
- *
- *       Modified by Eric Youngdale ericy@andante.org to
- *       add scatter-gather, multiple outstanding request, and other
- *       enhancements.
- *
- *       Modified by Eric Youngdale eric@andante.org to support loadable
- *       low-level scsi drivers.
- *
- *       Modified by Jirka Hanika geo@ff.cuni.cz to support more
- *       scsi disks using eight major numbers.
- *
- *       Modified by Richard Gooch rgooch@atnf.csiro.au to support devfs.
- *	
- *	 Modified by Torben Mathiasen tmm@image.dk
- *       Resource allocation fixes in sd_init and cleanups.
- *	
- *	 Modified by Alex Davis <letmein@erols.com>
- *       Fix problem where partition info not being read in sd_open.
- *	
- *	 Modified by Alex Davis <letmein@erols.com>
- *       Fix problem where removable media could be ejected after sd_open.
+ *	Logging policy (needs CONFIG_SCSI_LOGGING defined):
+ *	 - setting up transfer: SCSI_LOG_HLQUEUE levels 1 and 2
+ *	 - end of transfer (bh + scsi_lib): SCSI_LOG_HLCOMPLETE level 1
+ *	 - entering sd_ioctl: SCSI_LOG_IOCTL level 1
+ *	 - entering other commands: SCSI_LOG_HLQUEUE level 3
+ *	Note: when the logging level is set by the user, it must be greater
+ *	than the level indicated above to trigger output.	
  */
 
 #include <linux/config.h>
@@ -50,6 +49,7 @@
 #include <asm/io.h>
 
 #define MAJOR_NR SCSI_DISK0_MAJOR
+#define LOCAL_END_REQUEST
 #include <linux/blk.h>
 #include <linux/blkpg.h>
 #include "scsi.h"
@@ -61,6 +61,8 @@
 
 #include <linux/genhd.h>
 
+static char sd_version_str[] = "Version: 2.0.3 (20020417)";
+
 #define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i))
 
 #define SCSI_DISKS_PER_MAJOR	16
@@ -79,17 +81,21 @@
 #define SD_TIMEOUT (30 * HZ)
 #define SD_MOD_TIMEOUT (75 * HZ)
 
+#define SD_DSK_ARR_LUMP 6 /* amount to over allocate sd_dsk_arr by */
+
+
 struct hd_struct *sd;
 
-static Scsi_Disk *rscsi_disks;
+static Scsi_Disk ** sd_dsk_arr;
+static rwlock_t sd_dsk_arr_lock = RW_LOCK_UNLOCKED;
+
 static int *sd_sizes;
-static int *sd_blocksizes;
 static int *sd_max_sectors;
 
 static int check_scsidisk_media_change(kdev_t);
 static int fop_revalidate_scsidisk(kdev_t);
 
-static int sd_init_onedisk(int);
+static int sd_init_onedisk(Scsi_Disk * sdkp, int dsk_nr);
 
 static int sd_init(void);
 static void sd_finish(void);
@@ -118,36 +124,81 @@
 	init_command:sd_init_command,
 };
 
-static void rw_intr(Scsi_Cmnd * SCpnt);
+static void sd_rw_intr(Scsi_Cmnd * SCpnt);
+
+static Scsi_Disk * sd_get_sdisk(int index);
+
 
 #if defined(CONFIG_PPC)
-/*
- * Moved from arch/ppc/pmac_setup.c.  This is where it really belongs.
- */
+/**
+ *	sd_find_target - find kdev_t of first scsi disk that matches
+ *	given host and scsi_id. 
+ *	@host: Scsi_Host object pointer that owns scsi device of interest
+ *	@scsi_id: scsi (target) id number of device of interest
+ *
+ *	Returns kdev_t of first scsi device that matches arguments or
+ *	NODEV of no match.
+ *
+ *	Notes: Looks like a hack, should scan for <host,channel,id,lin>
+ *	tuple.
+ *	[Architectural dependency: ppc only.] Moved here from 
+ *	arch/ppc/pmac_setup.c.
+ **/
 kdev_t __init
-sd_find_target(void *host, int tgt)
+sd_find_target(void *hp, int scsi_id)
 {
-    Scsi_Disk *dp;
-    int i;
-    for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp)
-        if (dp->device != NULL && dp->device->host == host
-            && dp->device->id == tgt)
-            return MKDEV_SD(i);
-    return NODEV;
+	Scsi_Disk *sdkp;
+	Scsi_Device *sdp;
+	Scsi_Host *shp = hp;
+	int dsk_nr;
+	unsigned long iflags;
+
+	SCSI_LOG_HLQUEUE(3, printk("sd_find_target: host_nr=%d, "
+			    "scsi_id=%d\n", shp->host_no, scsi_id));
+	read_lock_irqsave(&sd_dsk_arr_lock, iflags);
+	for (dsk_nr = 0; dsk_nr < sd_template.dev_max; ++dsk_nr) {
+		if (NULL == (sdkp = sd_dsk_arr[dsk_nr]))
+			continue;
+		sdp = sdkp->device;
+		if (sdp && (sdp->host == shp) && (sdp->id == scsi_id)) {
+			read_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
+			return MKDEV_SD(k);
+		}
+	}
+	read_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
+	return NODEV;
 }
 #endif
 
-static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
+/**
+ *	sd_ioctl - process an ioctl
+ *	@inode: only i_rdev member may be used
+ *	@filp: only f_mode and f_flags may be used
+ *	@cmd: ioctl command number
+ *	@arg: this is third argument given to ioctl(2) system call.
+ *	Often contains a pointer.
+ *
+ *	Returns 0 if successful (some ioctls return postive numbers on
+ *	success as well). Returns a negated errno value in case of error.
+ *
+ *	Note: most ioctls are forward onto the block subsystem or further
+ *	down in the scsi subsytem.
+ **/
+static int sd_ioctl(struct inode * inode, struct file * filp, 
+		    unsigned int cmd, unsigned long arg)
 {
 	kdev_t dev = inode->i_rdev;
+        Scsi_Disk * sdkp;
 	struct Scsi_Host * host;
-	Scsi_Device * SDev;
+	Scsi_Device * sdp;
 	int diskinfo[4];
+	int dsk_nr = DEVICE_NR(dev);
     
-	SDev = rscsi_disks[DEVICE_NR(dev)].device;
-	if (!SDev)
+	SCSI_LOG_IOCTL(1, printk("sd_ioctl: dsk_nr=%d, cmd=0x%x\n",
+		       dsk_nr, cmd));
+	sdkp = sd_get_sdisk(dsk_nr);
+	if ((NULL == sdkp) || (NULL == (sdp = sdkp->device)))
 		return -ENODEV;
-
 	/*
 	 * If we are in the middle of error recovery, don't let anyone
 	 * else try and use this device.  Also, if error recovery fails, it
@@ -155,10 +206,8 @@
 	 * access to the device is prohibited.
 	 */
 
-	if( !scsi_block_when_processing_errors(SDev) )
-	{
+	if( !scsi_block_when_processing_errors(sdp) )
 		return -ENODEV;
-	}
 
 	switch (cmd) 
 	{
@@ -168,58 +217,59 @@
 			if(!loc)
 				return -EINVAL;
 
-			host = rscsi_disks[DEVICE_NR(dev)].device->host;
+			host = sdp->host;
 	
 			/* default to most commonly used values */
 	
 		        diskinfo[0] = 0x40;
 	        	diskinfo[1] = 0x20;
-	        	diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11;
+	        	diskinfo[2] = sdkp->capacity >> 11;
 	
-			/* override with calculated, extended default, or driver values */
+			/* override with calculated, extended default, 
+			   or driver values */
 	
 			if(host->hostt->bios_param != NULL)
-				host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)],
-					    dev,
-					    &diskinfo[0]);
-			else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)],
-					dev, &diskinfo[0]);
+				host->hostt->bios_param(sdkp, dev, 
+							&diskinfo[0]);
+			else
+				scsicam_bios_param(sdkp, dev, &diskinfo[0]);
 			if (put_user(diskinfo[0], &loc->heads) ||
 				put_user(diskinfo[1], &loc->sectors) ||
 				put_user(diskinfo[2], &loc->cylinders) ||
-				put_user((unsigned) get_start_sect(inode->i_rdev),
+				put_user((unsigned) 
+					     get_start_sect(inode->i_rdev),
 					 (unsigned long *) &loc->start))
 				return -EFAULT;
 			return 0;
 		}
 		case HDIO_GETGEO_BIG:
 		{
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			struct hd_big_geometry *loc = 
+					(struct hd_big_geometry *) arg;
 
 			if(!loc)
 				return -EINVAL;
-
-			host = rscsi_disks[DEVICE_NR(dev)].device->host;
+			host = sdp->host;
 
 			/* default to most commonly used values */
-
 			diskinfo[0] = 0x40;
 			diskinfo[1] = 0x20;
-			diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11;
+			diskinfo[2] = sdkp->capacity >> 11;
 
-			/* override with calculated, extended default, or driver values */
-
-			if(host->hostt->bios_param != NULL)
-				host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)],
-					    dev,
-					    &diskinfo[0]);
-			else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)],
-					dev, &diskinfo[0]);
+			/* override with calculated, extended default, 
+			   or driver values */
+			if(host->hostt->bios_param != NULL) 
+				host->hostt->bios_param(sdkp, dev,
+							&diskinfo[0]);
+			else
+				scsicam_bios_param(sdkp, dev, &diskinfo[0]);
 
 			if (put_user(diskinfo[0], &loc->heads) ||
 				put_user(diskinfo[1], &loc->sectors) ||
-				put_user(diskinfo[2], (unsigned int *) &loc->cylinders) ||
-				put_user((unsigned)get_start_sect(inode->i_rdev),
+				put_user(diskinfo[2], 
+					 (unsigned int *) &loc->cylinders) ||
+				put_user((unsigned)
+					   get_start_sect(inode->i_rdev),
 					 (unsigned long *)&loc->start))
 				return -EFAULT;
 			return 0;
@@ -243,15 +293,14 @@
 			return revalidate_scsidisk(dev, 1);
 
 		default:
-			return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device,
-					  cmd, (void *) arg);
+			return scsi_ioctl(sdp, cmd, (void *) arg);
 	}
 }
 
-static void sd_devname(unsigned int disknum, char *buffer)
+static void sd_dskname(unsigned int dsk_nr, char *buffer)
 {
-	if (disknum < 26)
-		sprintf(buffer, "sd%c", 'a' + disknum);
+	if (dsk_nr < 26)
+		sprintf(buffer, "sd%c", 'a' + dsk_nr);
 	else {
 		unsigned int min1;
 		unsigned int min2;
@@ -259,67 +308,88 @@
 		 * For larger numbers of disks, we need to go to a new
 		 * naming scheme.
 		 */
-		min1 = disknum / 26;
-		min2 = disknum % 26;
+		min1 = dsk_nr / 26;
+		min2 = dsk_nr % 26;
 		sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
 	}
 }
 
+/**
+ *	sd_find_queue - yields queue associated with device
+ *	@dev: kernel device descriptor (kdev_t)
+ *
+ *	Returns NULL if no match, otherwise returns pointer to associated
+ *	request queue.
+ *
+ *	Note: this function is invoked (often) from the block subsystem
+ *	and should not wait on anything (sd_get_sdisk() does have a read
+ *	spinlock).
+ **/
 static request_queue_t *sd_find_queue(kdev_t dev)
 {
-	Scsi_Disk *dpnt;
- 	int target;
- 	target = DEVICE_NR(dev);
+	Scsi_Disk *sdkp;
+ 	int dsk_nr = DEVICE_NR(dev);
 
-	dpnt = &rscsi_disks[target];
-	if (!dpnt)
+	sdkp = sd_get_sdisk(dsk_nr);
+	if (sdkp && sdkp->device)
+		return &sdkp->device->request_queue;
+	else
 		return NULL;	/* No such device */
-	return &dpnt->device->request_queue;
 }
 
+/**
+ *	sd_init_command - build a scsi (read or write) command from
+ *	information in the request structure.
+ *	@SCpnt: pointer to mid-level's per scsi command structure that
+ *	contains request and into which the scsi command is written
+ *
+ *	Returns 1 if successful and 0 if error (or cannot be done now).
+ **/
 static int sd_init_command(Scsi_Cmnd * SCpnt)
 {
-	int dev, devm, block, this_count;
-	Scsi_Disk *dpnt;
+	int dsk_nr, part_nr, block, this_count;
+	Scsi_Device *sdp;
 #if CONFIG_SCSI_LOGGING
 	char nbuff[6];
 #endif
-
 	/*
 	 * don't support specials for nwo
 	 */
 	if (!(SCpnt->request.flags & REQ_CMD))
 		return 0;
 
-	devm = SD_PARTITION(SCpnt->request.rq_dev);
-	dev = DEVICE_NR(SCpnt->request.rq_dev);
+	part_nr = SD_PARTITION(SCpnt->request.rq_dev);
+	dsk_nr = DEVICE_NR(SCpnt->request.rq_dev);
 
 	block = SCpnt->request.sector;
 	this_count = SCpnt->request_bufflen >> 9;
 
-	SCSI_LOG_HLQUEUE(1, printk("Doing sd request, dev = %d, block = %d\n", devm, block));
+	SCSI_LOG_HLQUEUE(1, printk("sd_command_init: dsk_nr=%d, block=%d, "
+			    "count=%d\n", dsk_nr, block, this_count));
 
-	dpnt = &rscsi_disks[dev];
-	if (devm >= (sd_template.dev_max << 4) || (devm & 0xf) ||
-	    !dpnt ||
-	    !dpnt->device->online ||
- 	    block + SCpnt->request.nr_sectors > sd[devm].nr_sects) {
-		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));
+	sdp = SCpnt->device;
+	/* >>>>> the "(part_nr & 0xf)" excludes 15th partition, why?? */
+	/* >>>>> this change is not in the lk 2.5 series */
+	if (part_nr >= (sd_template.dev_max << 4) || (part_nr & 0xf) ||
+	    !sdp || !sdp->online ||
+ 	    block + SCpnt->request.nr_sectors > sd[part_nr].nr_sects) {
+		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", 
+				 SCpnt->request.nr_sectors));
 		SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
 		return 0;
 	}
 
-	if (dpnt->device->changed) {
+	if (sdp->changed) {
 		/*
-		 * quietly refuse to do anything to a changed disc until the changed
-		 * bit has been reset
+		 * quietly refuse to do anything to a changed disc until 
+		 * the changed bit has been reset
 		 */
 		/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
 		return 0;
 	}
-	SCSI_LOG_HLQUEUE(2, sd_devname(devm, nbuff));
-	SCSI_LOG_HLQUEUE(2, printk("%s : real dev = /dev/%d, block = %d\n",
-				   nbuff, dev, block));
+	SCSI_LOG_HLQUEUE(2, sd_dskname(dsk_nr, nbuff));
+	SCSI_LOG_HLQUEUE(2, printk("%s : [part_nr=%d], block=%d\n",
+				   nbuff, part_nr, block));
 
 	/*
 	 * If we have a 1K hardware sectorsize, prevent access to single
@@ -332,27 +402,27 @@
 	 * and not force the scsi disk driver to use bounce buffers
 	 * for this.
 	 */
-	if (dpnt->device->sector_size == 1024) {
+	if (sdp->sector_size == 1024) {
 		if ((block & 1) || (SCpnt->request.nr_sectors & 1)) {
-			printk("sd.c:Bad block number requested");
+			printk(KERN_ERR "sd: Bad block number requested");
 			return 0;
 		} else {
 			block = block >> 1;
 			this_count = this_count >> 1;
 		}
 	}
-	if (dpnt->device->sector_size == 2048) {
+	if (sdp->sector_size == 2048) {
 		if ((block & 3) || (SCpnt->request.nr_sectors & 3)) {
-			printk("sd.c:Bad block number requested");
+			printk(KERN_ERR "sd: Bad block number requested");
 			return 0;
 		} else {
 			block = block >> 2;
 			this_count = this_count >> 2;
 		}
 	}
-	if (dpnt->device->sector_size == 4096) {
+	if (sdp->sector_size == 4096) {
 		if ((block & 7) || (SCpnt->request.nr_sectors & 7)) {
-			printk("sd.c:Bad block number requested");
+			printk(KERN_ERR "sd: Bad block number requested");
 			return 0;
 		} else {
 			block = block >> 3;
@@ -360,7 +430,7 @@
 		}
 	}
 	if (rq_data_dir(&SCpnt->request) == WRITE) {
-		if (!dpnt->device->writeable) {
+		if (!sdp->writeable) {
 			return 0;
 		}
 		SCpnt->cmnd[0] = WRITE_6;
@@ -368,13 +438,16 @@
 	} else if (rq_data_dir(&SCpnt->request) == READ) {
 		SCpnt->cmnd[0] = READ_6;
 		SCpnt->sc_data_direction = SCSI_DATA_READ;
-	} else
-		panic("Unknown sd command %lx\n", SCpnt->request.flags);
+	} else {
+		printk(KERN_ERR "sd: Unknown command %lx\n", 
+		       SCpnt->request.flags);
+/* overkill 	panic("Unknown sd command %lx\n", SCpnt->request.flags); */
+		return 0;
+	}
 
-	SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
-				   nbuff,
-		   (rq_data_dir(&SCpnt->request) == WRITE) ? "writing" : "reading",
-				 this_count, SCpnt->request.nr_sectors));
+	SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", 
+		nbuff, (rq_data_dir(&SCpnt->request) == WRITE) ? 
+		"writing" : "reading", this_count, SCpnt->request.nr_sectors));
 
 	SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
 			 ((SCpnt->lun << 5) & 0xe0) : 0;
@@ -407,7 +480,7 @@
 	 * host adapter, it's safe to assume that we can at least transfer
 	 * this many bytes between each connect / disconnect.
 	 */
-	SCpnt->transfersize = dpnt->device->sector_size;
+	SCpnt->transfersize = sdp->sector_size;
 	SCpnt->underflow = this_count << 9;
 
 	SCpnt->allowed = MAX_RETRIES;
@@ -418,7 +491,7 @@
 	 * This is the completion routine we use.  This is matched in terms
 	 * of capability to this function.
 	 */
-	SCpnt->done = rw_intr;
+	SCpnt->done = sd_rw_intr;
 
 	/*
 	 * This indicates that the command is ready from our end to be
@@ -427,31 +500,46 @@
 	return 1;
 }
 
+/**
+ *	sd_open - open a scsi disk device
+ *	@inode: only i_rdev member may be used
+ *	@filp: only f_mode and f_flags may be used
+ *
+ *	Returns 0 if successful. Returns a negated errno value in case 
+ *	of error.
+ *
+ *	Note: This can be called from a user context (e.g. fsck(1) )
+ *	or from within the kernel (e.g. as a result of a mount(1) ).
+ *	In the latter case @inode and @filp carry an abridged amount
+ *	of information as noted above.
+ **/
 static int sd_open(struct inode *inode, struct file *filp)
 {
-	int target, retval = -ENXIO;
-	Scsi_Device * SDev;
-	target = DEVICE_NR(inode->i_rdev);
+	int retval = -ENXIO;
+	Scsi_Device * sdp;
+	Scsi_Disk * sdkp;
+	int dsk_nr = DEVICE_NR(inode->i_rdev);
 
-	SCSI_LOG_HLQUEUE(1, printk("target=%d, max=%d\n", target, sd_template.dev_max));
+	SCSI_LOG_HLQUEUE(3, printk("sd_open: dsk_nr=%d, part_nr=%d\n", 
+			    dsk_nr, SD_PARTITION(inode->i_rdev)));
 
-	if (target >= sd_template.dev_max || !rscsi_disks[target].device)
+	sdkp = sd_get_sdisk(dsk_nr);
+	if ((NULL == sdkp) || (NULL == (sdp = sdkp->device)))
 		return -ENXIO;	/* No such device */
 
 	/*
 	 * If the device is in error recovery, wait until it is done.
 	 * If the device is offline, then disallow any access to it.
 	 */
-	if (!scsi_block_when_processing_errors(rscsi_disks[target].device)) {
+	if (!scsi_block_when_processing_errors(sdp))
 		return -ENXIO;
-	}
 	/*
-	 * Make sure that only one process can do a check_change_disk at one time.
-	 * This is also used to lock out further access when the partition table
-	 * is being re-read.
+	 * Make sure that only one process can do a check_change_disk at 
+	 * one time.  This is also used to lock out further access when 
+	 * the partition table is being re-read.
 	 */
 
-	while (rscsi_disks[target].device->busy) {
+	while (sdp->busy) {
 		barrier();
 		cpu_relax();
 	}
@@ -459,22 +547,21 @@
 	 * The following code can sleep.
 	 * Module unloading must be prevented
 	 */
-	SDev = rscsi_disks[target].device;
-	if (SDev->host->hostt->module)
-		__MOD_INC_USE_COUNT(SDev->host->hostt->module);
+	if (sdp->host->hostt->module)
+		__MOD_INC_USE_COUNT(sdp->host->hostt->module);
 	if (sd_template.module)
 		__MOD_INC_USE_COUNT(sd_template.module);
-	SDev->access_count++;
+	sdp->access_count++;
 
-	if (rscsi_disks[target].device->removable) {
-		SDev->allow_revalidate = 1;
+	if (sdp->removable) {
+		sdp->allow_revalidate = 1;
 		check_disk_change(inode->i_rdev);
-		SDev->allow_revalidate = 0;
+		sdp->allow_revalidate = 0;
 
 		/*
 		 * If the drive is empty, just let the open fail.
 		 */
-		if ((!rscsi_disks[target].ready) && !(filp->f_flags & O_NDELAY)) {
+		if ((!sdkp->ready) && !(filp->f_flags & O_NDELAY)) {
 			retval = -ENOMEDIUM;
 			goto error_out;
 		}
@@ -484,7 +571,7 @@
 		 * have the open fail if the user expects to be able to write
 		 * to the thing.
 		 */
-		if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2)) {
+		if ((sdkp->write_prot) && (filp->f_mode & FMODE_WRITE)) {
 			retval = -EROFS;
 			goto error_out;
 		}
@@ -495,7 +582,7 @@
 	 * and don't pretend that
 	 * the open actually succeeded.
 	 */
-	if (!SDev->online) {
+	if (!sdp->online) {
 		goto error_out;
 	}
 	/*
@@ -506,42 +593,57 @@
 		goto error_out;
 	}
 
-	if (SDev->removable)
-		if (SDev->access_count==1)
-			if (scsi_block_when_processing_errors(SDev))
-				scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL);
+	if (sdp->removable)
+		if (sdp->access_count==1)
+			if (scsi_block_when_processing_errors(sdp))
+				scsi_ioctl(sdp, SCSI_IOCTL_DOORLOCK, NULL);
 
-	
 	return 0;
 
 error_out:
-	SDev->access_count--;
-	if (SDev->host->hostt->module)
-		__MOD_DEC_USE_COUNT(SDev->host->hostt->module);
+	sdp->access_count--;
+	if (sdp->host->hostt->module)
+		__MOD_DEC_USE_COUNT(sdp->host->hostt->module);
 	if (sd_template.module)
 		__MOD_DEC_USE_COUNT(sd_template.module);
 	return retval;	
 }
 
-static int sd_release(struct inode *inode, struct file *file)
-{
-	int target;
-	Scsi_Device * SDev;
-
-	target = DEVICE_NR(inode->i_rdev);
-	SDev = rscsi_disks[target].device;
-	if (!SDev)
-		return -ENODEV;
-
-	SDev->access_count--;
-
-	if (SDev->removable) {
-		if (!SDev->access_count)
-			if (scsi_block_when_processing_errors(SDev))
-				scsi_ioctl(SDev, SCSI_IOCTL_DOORUNLOCK, NULL);
+/**
+ *	sd_release - invoked when the (last) close(2) is called on this
+ *	scsi disk.
+ *	@inode: only i_rdev member may be used
+ *	@filp: only f_mode and f_flags may be used
+ *
+ *	Returns 0. 
+ *
+ *	Note: may block (uninterruptible) if error recovery is underway
+ *	on this disk.
+ **/
+static int sd_release(struct inode *inode, struct file *filp)
+{
+	Scsi_Disk * sdkp;
+	int dsk_nr = DEVICE_NR(inode->i_rdev);
+	Scsi_Device * sdp;
+
+	SCSI_LOG_HLQUEUE(3, printk("sd_release: dsk_nr=%d, part_nr=%d\n", 
+			    dsk_nr, SD_PARTITION(inode->i_rdev)));
+	sdkp = sd_get_sdisk(dsk_nr);
+	if ((NULL == sdkp) || (NULL == (sdp = sdkp->device)))
+		return -ENODEV; /* open uses ENXIO ?? */
+
+	/* ... and what if there are packets in flight and this close()
+	 * is followed by a "rmmod sd_mod" */
+
+	sdp->access_count--;
+
+	if (sdp->removable) {
+		if (!sdp->access_count)
+			if (scsi_block_when_processing_errors(sdp))
+				scsi_ioctl(sdp, SCSI_IOCTL_DOORUNLOCK, NULL);
 	}
-	if (SDev->host->hostt->module)
-		__MOD_DEC_USE_COUNT(SDev->host->hostt->module);
+	if (sdp->host->hostt->module)
+		__MOD_DEC_USE_COUNT(sdp->host->hostt->module);
 	if (sd_template.module)
 		__MOD_DEC_USE_COUNT(sd_template.module);
 	return 0;
@@ -559,7 +661,7 @@
 
 /*
  *    If we need more than one SCSI disk major (i.e. more than
- *      16 SCSI disks), we'll have to kmalloc() more gendisks later.
+ *      16 SCSI disks), we'll have to vmalloc() more gendisks later.
  */
 
 static struct gendisk sd_gendisk =
@@ -574,30 +676,34 @@
 
 #define SD_GENDISK(i)    sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR]
 
-/*
- * rw_intr is the interrupt routine for the device driver.
- * It will be notified on the end of a SCSI read / write, and
- * will take one of several actions based on success or failure.
- */
-
-static void rw_intr(Scsi_Cmnd * SCpnt)
+/**
+ *	sd_rw_intr - bottom half handler: called when the lower level
+ *	driver has completed (successfully or otherwise) a scsi command.
+ *	@SCpnt: mid-level's per command structure.
+ *
+ *	Note: potentially run from within an ISR. Must not block.
+ **/
+static void sd_rw_intr(Scsi_Cmnd * SCpnt)
 {
 	int result = SCpnt->result;
-#if CONFIG_SCSI_LOGGING
-	char nbuff[6];
-#endif
 	int this_count = SCpnt->bufflen >> 9;
 	int good_sectors = (result == 0 ? this_count : 0);
 	int block_sectors = 1;
+	long error_sector;
+#if CONFIG_SCSI_LOGGING
+	char nbuff[6];
 
-	SCSI_LOG_HLCOMPLETE(1, sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff));
-
-	SCSI_LOG_HLCOMPLETE(1, printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff,
-				      SCpnt->host->host_no,
-				      result,
-				      SCpnt->sense_buffer[0],
-				      SCpnt->sense_buffer[2]));
-
+	SCSI_LOG_HLCOMPLETE(1, sd_dskname(DEVICE_NR(SCpnt->request.rq_dev), 
+			    nbuff));
+	SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", 
+				      nbuff, result));
+	if (0 != result) {
+		SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[0,2,asc,ascq]"
+				"=%x,%x,%x,%x\n", SCpnt->sense_buffer[0],
+			SCpnt->sense_buffer[2], SCpnt->sense_buffer[12],
+			SCpnt->sense_buffer[13]));
+	}
+#endif
 	/*
 	   Handle MEDIUM ERRORs that indicate partial success.  Since this is a
 	   relatively rare error condition, no care is taken to avoid
@@ -605,10 +711,11 @@
 	 */
 
 	/* An error occurred */
-	if (driver_byte(result) != 0) {
-		/* Sense data is valid */
-		if (SCpnt->sense_buffer[0] == 0xF0 && SCpnt->sense_buffer[2] == MEDIUM_ERROR) {
-			long error_sector = (SCpnt->sense_buffer[3] << 24) |
+	if (driver_byte(result) != 0 && 	/* An error occured */
+	    SCpnt->sense_buffer[0] != 0xF0) {	/* Sense data is valid */
+		switch (SCpnt->sense_buffer[2]) {
+		case MEDIUM_ERROR:
+			error_sector = (SCpnt->sense_buffer[3] << 24) |
 			(SCpnt->sense_buffer[4] << 16) |
 			(SCpnt->sense_buffer[5] << 8) |
 			SCpnt->sense_buffer[6];
@@ -641,13 +748,30 @@
 			good_sectors = error_sector - SCpnt->request.sector;
 			if (good_sectors < 0 || good_sectors >= this_count)
 				good_sectors = 0;
-		}
-		if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
+			break;
+
+		case RECOVERED_ERROR:
+			/*
+			 * An error occured, but it recovered.  Inform the
+			 * user, but make sure that it's not treated as a
+			 * hard error.
+			 */
+			print_sense("sd", SCpnt);
+			result = 0;
+			SCpnt->sense_buffer[0] = 0x0;
+			good_sectors = this_count;
+			break;
+
+		case ILLEGAL_REQUEST:
 			if (SCpnt->device->ten == 1) {
 				if (SCpnt->cmnd[0] == READ_10 ||
 				    SCpnt->cmnd[0] == WRITE_10)
 					SCpnt->device->ten = 0;
 			}
+			break;
+
+		default:
+			break;
 		}
 	}
 	/*
@@ -657,28 +781,33 @@
 	 */
 	scsi_io_completion(SCpnt, good_sectors, block_sectors);
 }
-/*
- * requeue_sd_request() is the request handler function for the sd driver.
- * Its function in life is to take block device requests, and translate
- * them to SCSI commands.
- */
-
 
+/**
+ *	check_scsidisk_media_change - self descriptive
+ *	@full_dev: kernel device descriptor (kdev_t)
+ *
+ *	Returns 0 if not applicable or no change; 1 if change
+ *
+ *	Note: this function is invoked from the block subsystem.
+ **/
 static int check_scsidisk_media_change(kdev_t full_dev)
 {
 	int retval;
-	int target;
-	int flag = 0;
-	Scsi_Device * SDev;
-
-	target = DEVICE_NR(full_dev);
-	SDev = rscsi_disks[target].device;
-
-	if (target >= sd_template.dev_max || !SDev) {
-		printk("SCSI disk request error: invalid device.\n");
+	int flag = 0;	/* <<<< what is this for?? */
+	Scsi_Disk * sdkp;
+	Scsi_Device * sdp;
+	int dsk_nr = DEVICE_NR(full_dev);
+
+	sdkp = sd_get_sdisk(dsk_nr);
+
+	SCSI_LOG_HLQUEUE(3, printk("check_scsidisk_media_change: "
+			    "dsk_nr=%d\n", dsk_nr));
+	if ((NULL == sdkp) || (NULL == (sdp = sdkp->device))) {
+		printk(KERN_ERR "check_scsidisk_media_change: dsk_nr=%d, "
+		       "invalid device\n", dsk_nr);
 		return 0;
 	}
-	if (!SDev->removable)
+	if (!sdp->removable)
 		return 0;
 
 	/*
@@ -687,9 +816,9 @@
 	 * can deal with it then.  It is only because of unrecoverable errors
 	 * that we would ever take a device offline in the first place.
 	 */
-	if (SDev->online == FALSE) {
-		rscsi_disks[target].ready = 0;
-		SDev->changed = 1;
+	if (sdp->online == FALSE) {
+		sdkp->ready = 0;
+		sdp->changed = 1;
 		return 1;	/* This will force a flush, if called from
 				 * check_disk_change */
 	}
@@ -701,8 +830,8 @@
 	 * as this will spin up the drive.
 	 */
 	retval = -ENODEV;
-	if (scsi_block_when_processing_errors(SDev))
-		retval = scsi_ioctl(SDev, SCSI_IOCTL_START_UNIT, NULL);
+	if (scsi_block_when_processing_errors(sdp))
+		retval = scsi_ioctl(sdp, SCSI_IOCTL_START_UNIT, NULL);
 
 	if (retval) {		/* Unable to test, unit probably not ready.
 				 * This usually means there is no disc in the
@@ -710,8 +839,8 @@
 				 * it out later once the drive is available
 				 * again.  */
 
-		rscsi_disks[target].ready = 0;
-		SDev->changed = 1;
+		sdkp->ready = 0;
+		sdp->changed = 1;
 		return 1;	/* This will force a flush, if called from
 				 * check_disk_change */
 	}
@@ -721,15 +850,26 @@
 	 * struct and tested at open !  Daniel Roche ( dan@lectra.fr )
 	 */
 
-	rscsi_disks[target].ready = 1;	/* FLOPTICAL */
+	sdkp->ready = 1;	/* FLOPTICAL */
 
-	retval = SDev->changed;
+	retval = sdp->changed;
 	if (!flag)
-		SDev->changed = 0;
+		sdp->changed = 0;
 	return retval;
 }
 
-static int sd_init_onedisk(int i)
+/**
+ *	sd_init_onedisk - called the first time a new disk is seen,
+ *	performs read_capacity, disk spin up (as required), etc.
+ *	@sdkp: pointer to associated Scsi_Disk object
+ *	@dsk_nr: disk number within this driver (e.g. 0->/dev/sda,
+ *	1->/dev/sdb, etc)
+ *
+ *	Returns dsk_nr (pointless)
+ *
+ *	Note: this function is local to this driver.
+ **/
+static int sd_init_onedisk(Scsi_Disk * sdkp, int dsk_nr)
 {
 	unsigned char cmd[10];
 	char nbuff[6];
@@ -737,19 +877,23 @@
 	unsigned long spintime_value = 0;
 	int the_result, retries, spintime;
 	int sector_size;
+	Scsi_Device *sdp;
 	Scsi_Request *SRpnt;
 
+	SCSI_LOG_HLQUEUE(3, printk("sd_init_onedisk: dsk_nr=%d\n", 
+			    dsk_nr));
 	/*
 	 * Get the name of the disk, in case we need to log it somewhere.
 	 */
-	sd_devname(i, nbuff);
+	sd_dskname(dsk_nr, nbuff);
 
 	/*
 	 * If the device is offline, don't try and read capacity or any
 	 * of the other niceties.
 	 */
-	if (rscsi_disks[i].device->online == FALSE)
-		return i;
+	sdp = sdkp->device;
+	if (sdp->online == FALSE)
+		return dsk_nr;
 
 	/*
 	 * We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
@@ -757,17 +901,19 @@
 	 * just after a scsi bus reset.
 	 */
 
-	SRpnt = scsi_allocate_request(rscsi_disks[i].device);
+	SRpnt = scsi_allocate_request(sdp);
 	if (!SRpnt) {
-		printk(KERN_WARNING "(sd_init_onedisk:) Request allocation failure.\n");
-		return i;
+		printk(KERN_WARNING "(sd_init_onedisk:) Request allocation "
+		       "failure.\n");
+		return dsk_nr;
 	}
 
 	buffer = kmalloc(512, GFP_DMA);
 	if (!buffer) {
-		printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation failure.\n");
+		printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation "
+		       "failure.\n");
 		scsi_release_request(SRpnt);
-		return i;
+		return dsk_nr;
 	}
 
 	spintime = 0;
@@ -779,8 +925,8 @@
 
 		while (retries < 3) {
 			cmd[0] = TEST_UNIT_READY;
-			cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
-				 ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
+			cmd[1] = (sdp->scsi_level <= SCSI_2) ?
+				 ((sdp->lun << 5) & 0xe0) : 0;
 			memset((void *) &cmd[2], 0, 8);
 			SRpnt->sr_cmd_len = 0;
 			SRpnt->sr_sense_buffer[0] = 0;
@@ -806,23 +952,24 @@
 		    && ((driver_byte(the_result) & DRIVER_SENSE) != 0)
 		    && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION
 		    && SRpnt->sr_sense_buffer[12] == 0x3A ) {
-			rscsi_disks[i].capacity = 0x1fffff;
+			sdkp->capacity = 0x1fffff;
 			sector_size = 512;
-			rscsi_disks[i].device->changed = 1;
-			rscsi_disks[i].ready = 0;
+			sdp->changed = 1;
+			sdkp->ready = 0;
 			break;
 		}
 
 		/* Look for non-removable devices that return NOT_READY.
 		 * Issue command to spin up drive for these cases. */
-		if (the_result && !rscsi_disks[i].device->removable &&
+		if (the_result && !sdp->removable &&
 		    SRpnt->sr_sense_buffer[2] == NOT_READY) {
 			unsigned long time1;
 			if (!spintime) {
-				printk("%s: Spinning up disk...", nbuff);
+				printk(KERN_NOTICE "%s: Spinning up disk...",
+				       nbuff);
 				cmd[0] = START_STOP;
-				cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
-				 	 ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
+				cmd[1] = (sdp->scsi_level <= SCSI_2) ?
+				 	 ((sdp->lun << 5) & 0xe0) : 0;
 				cmd[1] |= 1;	/* Return immediately */
 				memset((void *) &cmd[2], 0, 8);
 				cmd[4] = 1;	/* Start spin cycle */
@@ -831,8 +978,9 @@
 				SRpnt->sr_sense_buffer[2] = 0;
 
 				SRpnt->sr_data_direction = SCSI_DATA_READ;
-				scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
-					    0/*512*/, SD_TIMEOUT, MAX_RETRIES);
+				scsi_wait_req(SRpnt, (void *)cmd, 
+					      (void *) buffer, 0/*512*/, 
+					      SD_TIMEOUT, MAX_RETRIES);
 				spintime_value = jiffies;
 			}
 			spintime = 1;
@@ -855,8 +1003,8 @@
 	retries = 3;
 	do {
 		cmd[0] = READ_CAPACITY;
-		cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
-			 ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
+		cmd[1] = (sdp->scsi_level <= SCSI_2) ?
+			 ((sdp->lun << 5) & 0xe0) : 0;
 		memset((void *) &cmd[2], 0, 8);
 		memset((void *) buffer, 0, 8);
 		SRpnt->sr_cmd_len = 0;
@@ -888,8 +1036,8 @@
 	 */
 
 	if (the_result) {
-		printk("%s : READ CAPACITY failed.\n"
-		       "%s : status = %x, message = %02x, host = %d, driver = %02x \n",
+		printk(KERN_NOTICE "%s : READ CAPACITY failed.\n"
+		       "%s : status=%x, message=%02x, host=%d, driver=%02x \n",
 		       nbuff, nbuff,
 		       status_byte(the_result),
 		       msg_byte(the_result),
@@ -901,97 +1049,85 @@
 		else
 			printk("%s : sense not available. \n", nbuff);
 
-		printk("%s : block size assumed to be 512 bytes, disk size 1GB.  \n",
-		       nbuff);
-		rscsi_disks[i].capacity = 0x1fffff;
+		printk(KERN_NOTICE "%s : block size assumed to be 512 "
+		       "bytes, disk size 1GB.  \n", nbuff);
+		sdkp->capacity = 0x1fffff;
 		sector_size = 512;
 
 		/* Set dirty bit for removable devices if not ready -
 		 * sometimes drives will not report this properly. */
-		if (rscsi_disks[i].device->removable &&
+		if (sdp->removable &&
 		    SRpnt->sr_sense_buffer[2] == NOT_READY)
-			rscsi_disks[i].device->changed = 1;
+			sdp->changed = 1;
 
 	} else {
 		/*
 		 * FLOPTICAL, if read_capa is ok, drive is assumed to be ready
 		 */
-		rscsi_disks[i].ready = 1;
+		sdkp->ready = 1;
 
-		rscsi_disks[i].capacity = 1 + ((buffer[0] << 24) |
-					       (buffer[1] << 16) |
-					       (buffer[2] << 8) |
-					       buffer[3]);
+		sdkp->capacity = 1 + ((buffer[0] << 24) |
+				      (buffer[1] << 16) |
+				      (buffer[2] << 8) |
+				      buffer[3]);
 
 		sector_size = (buffer[4] << 24) |
 		    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
 
 		if (sector_size == 0) {
 			sector_size = 512;
-			printk("%s : sector size 0 reported, assuming 512.\n",
-			       nbuff);
+			printk(KERN_NOTICE "%s : sector size 0 reported, "
+			       "assuming 512.\n", nbuff);
 		}
 		if (sector_size != 512 &&
 		    sector_size != 1024 &&
 		    sector_size != 2048 &&
 		    sector_size != 4096 &&
 		    sector_size != 256) {
-			printk("%s : unsupported sector size %d.\n",
-			       nbuff, sector_size);
+			printk(KERN_NOTICE "%s : unsupported sector size "
+			       "%d.\n", nbuff, sector_size);
 			/*
 			 * The user might want to re-format the drive with
 			 * a supported sectorsize.  Once this happens, it
 			 * would be relatively trivial to set the thing up.
 			 * For this reason, we leave the thing in the table.
 			 */
-			rscsi_disks[i].capacity = 0;
+			sdkp->capacity = 0;
 		}
-		if (sector_size > 1024) {
-			int m;
-
-			/*
-			 * We must fix the sd_blocksizes and sd_hardsizes
-			 * to allow us to read the partition tables.
-			 * The disk reading code does not allow for reading
-			 * of partial sectors.
-			 */
-			for (m = i << 4; m < ((i + 1) << 4); m++) {
-				sd_blocksizes[m] = sector_size;
-			}
-		} {
+		{
 			/*
 			 * The msdos fs needs to know the hardware sector size
 			 * So I have created this table. See ll_rw_blk.c
 			 * Jacques Gelinas (Jacques@solucorp.qc.ca)
 			 */
 			int hard_sector = sector_size;
-			int sz = rscsi_disks[i].capacity * (hard_sector/256);
-			request_queue_t *queue = &rscsi_disks[i].device->request_queue;
+			int sz = sdkp->capacity * (hard_sector/256);
+			request_queue_t *queue = &sdp->request_queue;
 
 			blk_queue_hardsect_size(queue, hard_sector);
-			printk("SCSI device %s: "
+			printk(KERN_NOTICE "SCSI device %s: "
 			       "%d %d-byte hdwr sectors (%d MB)\n",
-			       nbuff, rscsi_disks[i].capacity,
+			       nbuff, sdkp->capacity,
 			       hard_sector, (sz/2 - sz/1250 + 974)/1950);
 		}
 
 		/* Rescale capacity to 512-byte units */
 		if (sector_size == 4096)
-			rscsi_disks[i].capacity <<= 3;
+			sdkp->capacity <<= 3;
 		if (sector_size == 2048)
-			rscsi_disks[i].capacity <<= 2;
+			sdkp->capacity <<= 2;
 		if (sector_size == 1024)
-			rscsi_disks[i].capacity <<= 1;
+			sdkp->capacity <<= 1;
 		if (sector_size == 256)
-			rscsi_disks[i].capacity >>= 1;
+			sdkp->capacity >>= 1;
 	}
 
 
 	/*
 	 * Unless otherwise specified, this is not write protected.
 	 */
-	rscsi_disks[i].write_prot = 0;
-	if (rscsi_disks[i].device->removable && rscsi_disks[i].ready) {
+	sdkp->write_prot = 0;
+	if (sdp->removable && sdkp->ready) {
 		/* FLOPTICAL */
 
 		/*
@@ -1005,12 +1141,16 @@
 		 * we're only interested in the header anyway, this should
 		 * be fine.
 		 *   -- Matthew Dharm (mdharm-scsi@one-eyed-alien.net)
+		 *
+		 * As it turns out, some devices return an error for
+		 * every MODE_SENSE request except one for page 0.
+		 * So, we should also try that. --aeb
 		 */
 
 		memset((void *) &cmd[0], 0, 8);
 		cmd[0] = MODE_SENSE;
-		cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
-			 ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
+		cmd[1] = (sdp->scsi_level <= SCSI_2) ?
+			 ((sdp->lun << 5) & 0xe0) : 0;
 		cmd[2] = 0x3f;	/* Get all pages */
 		cmd[4] = 255;   /* Ask for 255 bytes, even tho we want just the first 8 */
 		SRpnt->sr_cmd_len = 0;
@@ -1025,11 +1165,13 @@
 		the_result = SRpnt->sr_result;
 
 		if (the_result) {
-			printk("%s: test WP failed, assume Write Enabled\n", nbuff);
+			printk("%s: test WP failed, assume Write Enabled\n",
+			       nbuff);
+			/* alternatively, try page 0 */
 		} else {
-			rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0);
-			printk("%s: Write Protect is %s\n", nbuff,
-			       rscsi_disks[i].write_prot ? "on" : "off");
+			sdkp->write_prot = ((buffer[2] & 0x80) != 0);
+			printk(KERN_NOTICE "%s: Write Protect is %s\n", nbuff,
+			       sdkp->write_prot ? "on" : "off");
 		}
 
 	}			/* check for write protect */
@@ -1041,7 +1183,7 @@
 	SRpnt = NULL;
 
 	kfree(buffer);
-	return i;
+	return dsk_nr;
 }
 
 /*
@@ -1051,14 +1193,25 @@
 
 static int sd_registered;
 
+/**
+ *	sd_init- called during driver initialization (after
+ *	sd_detect() is called for each scsi device present).
+ *
+ *	Returns 0 is successful (or already called); 1 if error
+ *
+ *	Note: this function is invoked from the scsi mid-level.
+ **/
 static int sd_init()
 {
-	int i, maxparts;
+	int k, maxparts;
+	Scsi_Disk * sdkp;
 
+	SCSI_LOG_HLQUEUE(3, printk("sd_init: dev_noticed=%d\n",
+			    sd_template.dev_noticed));
 	if (sd_template.dev_noticed == 0)
 		return 0;
 
-	if (!rscsi_disks)
+	if (NULL == sd_dsk_arr)
 		sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
 
 	if (sd_template.dev_max > N_SD_MAJORS * SCSI_DISKS_PER_MAJOR)
@@ -1070,77 +1223,80 @@
 		return 0;
 
 	if (!sd_registered) {
-		for (i = 0; i < N_USED_SD_MAJORS; i++) {
-			if (devfs_register_blkdev(SD_MAJOR(i), "sd",
+		for (k = 0; k < N_USED_SD_MAJORS; k++) {
+			if (devfs_register_blkdev(SD_MAJOR(k), "sd",
 						  &sd_fops)) {
-				printk("Unable to get major %d for SCSI disk\n",
-				       SD_MAJOR(i));
+				printk(KERN_NOTICE "Unable to get major %d "
+				       "for SCSI disk\n", SD_MAJOR(k));
 				return 1;
 			}
 		}
 		sd_registered++;
 	}
 	/* We do not support attaching loadable devices yet. */
-	if (rscsi_disks)
+	if (sd_dsk_arr)
 		return 0;
 
 	/* allocate memory */
-#define init_mem_lth(x,n)	x = kmalloc((n) * sizeof(*x), GFP_ATOMIC)
+#define init_mem_lth(x,n)	x = vmalloc((n) * sizeof(*x))
 #define zero_mem_lth(x,n)	memset(x, 0, (n) * sizeof(*x))
 
-	init_mem_lth(rscsi_disks, sd_template.dev_max);
+	init_mem_lth(sd_dsk_arr, sd_template.dev_max);
+	if (sd_dsk_arr) {
+		zero_mem_lth(sd_dsk_arr, sd_template.dev_max);
+		for (k = 0; k < sd_template.dev_max; ++k) {
+			sdkp = vmalloc(sizeof(Scsi_Disk));
+			if (NULL == sdkp)
+				goto cleanup_mem;
+			memset(sdkp, 0, sizeof(Scsi_Disk));
+			sd_dsk_arr[k] = sdkp;
+		}
+	}
 	init_mem_lth(sd_sizes, maxparts);
-	init_mem_lth(sd_blocksizes, maxparts);
 	init_mem_lth(sd, maxparts);
 	init_mem_lth(sd_gendisks, N_USED_SD_MAJORS);
 	init_mem_lth(sd_max_sectors, sd_template.dev_max << 4);
 
-	if (!rscsi_disks || !sd_sizes || !sd_blocksizes || !sd || !sd_gendisks)
+	if (!sd_dsk_arr || !sd_sizes || !sd || !sd_gendisks)
 		goto cleanup_mem;
 
-	zero_mem_lth(rscsi_disks, sd_template.dev_max);
 	zero_mem_lth(sd_sizes, maxparts);
 	zero_mem_lth(sd, maxparts);
 
-	for (i = 0; i < maxparts; i++) {
-		sd_blocksizes[i] = 1024;
+	for (k = 0; k < maxparts; k++) {
 		/*
 		 * Allow lowlevel device drivers to generate 512k large scsi
 		 * commands if they know what they're doing and they ask for it
 		 * explicitly via the SHpnt->max_sectors API.
 		 */
-		sd_max_sectors[i] = MAX_PHYS_SEGMENTS*8;
+		sd_max_sectors[k] = MAX_PHYS_SEGMENTS*8;
 	}
 
-	for (i = 0; i < N_USED_SD_MAJORS; i++) {
-		request_queue_t *q = blk_get_queue(mk_kdev(SD_MAJOR(i), 0));
-		int parts_per_major = (SCSI_DISKS_PER_MAJOR << 4);
-
-		blksize_size[SD_MAJOR(i)] =
-			sd_blocksizes + i * parts_per_major;
+	for (k = 0; k < N_USED_SD_MAJORS; k++) {
+		request_queue_t *q = blk_get_queue(mk_kdev(SD_MAJOR(k), 0));
 		blk_queue_hardsect_size(q, 512);
  	}
 
-	for (i = 0; i < N_USED_SD_MAJORS; i++) {
+	for (k = 0; k < N_USED_SD_MAJORS; k++) {
 		int N = SCSI_DISKS_PER_MAJOR;
 
-		sd_gendisks[i] = sd_gendisk;
+		sd_gendisks[k] = sd_gendisk;
 
-		init_mem_lth(sd_gendisks[i].de_arr, N);
-		init_mem_lth(sd_gendisks[i].flags, N);
+		init_mem_lth(sd_gendisks[k].de_arr, N);
+		init_mem_lth(sd_gendisks[k].flags, N);
 
-		if (!sd_gendisks[i].de_arr || !sd_gendisks[i].flags)
+		if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags)
 			goto cleanup_gendisks;
 
-		zero_mem_lth(sd_gendisks[i].de_arr, N);
-		zero_mem_lth(sd_gendisks[i].flags, N);
+		zero_mem_lth(sd_gendisks[k].de_arr, N);
+		zero_mem_lth(sd_gendisks[k].flags, N);
 
-		sd_gendisks[i].major = SD_MAJOR(i);
-		sd_gendisks[i].major_name = "sd";
-		sd_gendisks[i].minor_shift = 4;
-		sd_gendisks[i].part = sd + i * (N << 4);
-		sd_gendisks[i].sizes = sd_sizes + i * (N << 4);
-		sd_gendisks[i].nr_real = 0;
+		sd_gendisks[k].major = SD_MAJOR(k);
+		sd_gendisks[k].major_name = "sd";
+		sd_gendisks[k].minor_shift = 4;
+		sd_gendisks[k].part = sd + k * (N << 4);
+		sd_gendisks[k].sizes = sd_sizes + k * (N << 4);
+		sd_gendisks[k].nr_real = 0;
 	}
 
 	return 0;
@@ -1149,130 +1305,196 @@
 #undef zero_mem_lth
 
 cleanup_gendisks:
-	/* kfree can handle NULL, so no test is required here */
-	for (i = 0; i < N_USED_SD_MAJORS; i++) {
-		kfree(sd_gendisks[i].de_arr);
-		kfree(sd_gendisks[i].flags);
+	/* vfree can handle NULL, so no test is required here */
+	for (k = 0; k < N_USED_SD_MAJORS; k++) {
+		vfree(sd_gendisks[k].de_arr);
+		vfree(sd_gendisks[k].flags);
 	}
 cleanup_mem:
-	kfree(sd_gendisks);
-	kfree(sd);
-	kfree(sd_blocksizes);
-	kfree(sd_sizes);
-	kfree(rscsi_disks);
-	for (i = 0; i < N_USED_SD_MAJORS; i++) {
-		devfs_unregister_blkdev(SD_MAJOR(i), "sd");
+	if (sd_gendisks) vfree(sd_gendisks);
+	sd_gendisks = NULL;
+	if (sd) vfree(sd);
+	sd = NULL;
+	if (sd_sizes) vfree(sd_sizes);
+	sd_sizes = NULL;
+	if (sd_dsk_arr) {
+                for (k = 0; k < sd_template.dev_max; ++k) {
+			sdkp = sd_dsk_arr[k];
+			if (sdkp)
+				vfree(sdkp);
+		}
+		vfree(sd_dsk_arr);
+		sd_dsk_arr = NULL;
+	}
+	for (k = 0; k < N_USED_SD_MAJORS; k++) {
+		devfs_unregister_blkdev(SD_MAJOR(k), "sd");
 	}
 	sd_registered--;
 	return 1;
 }
 
-
+/**
+ *	sd_finish- called during driver initialization, after all
+ *	the sd_attach() calls are finished.
+ *
+ *	Note: this function is invoked from the scsi mid-level.
+ *	This function is not called after driver initialization has completed.
+ *	Specifically later device attachments invoke sd_attach() but not
+ *	this function.
+ **/
 static void sd_finish()
 {
-	int i;
+	int k;
+	Scsi_Disk * sdkp;
 
-	for (i = 0; i < N_USED_SD_MAJORS; i++) {
-		blk_dev[SD_MAJOR(i)].queue = sd_find_queue;
-		add_gendisk(&(sd_gendisks[i]));
-	}
-
-	for (i = 0; i < sd_template.dev_max; ++i)
-		if (!rscsi_disks[i].capacity && rscsi_disks[i].device) {
-			sd_init_onedisk(i);
-			if (!rscsi_disks[i].has_part_table) {
-				sd_sizes[i << 4] = rscsi_disks[i].capacity;
-				register_disk(&SD_GENDISK(i), MKDEV_SD(i),
+	SCSI_LOG_HLQUEUE(3, printk("sd_finish: \n"));
+	for (k = 0; k < N_USED_SD_MAJORS; k++) {
+		blk_dev[SD_MAJOR(k)].queue = sd_find_queue;
+		add_gendisk(&(sd_gendisks[k]));
+	}
+
+	for (k = 0; k < sd_template.dev_max; ++k) {
+		sdkp = sd_get_sdisk(k);
+		if (sdkp && (0 == sdkp->capacity) && sdkp->device) {
+			sd_init_onedisk(sdkp, k);
+			if (!sdkp->has_part_table) {
+				sd_sizes[k << 4] = sdkp->capacity;
+				register_disk(&SD_GENDISK(k), MKDEV_SD(k),
 						1<<4, &sd_fops,
-						rscsi_disks[i].capacity);
-				rscsi_disks[i].has_part_table = 1;
+						sdkp->capacity);
+				sdkp->has_part_table = 1;
 			}
 		}
-
+	}
 	return;
 }
 
-static int sd_detect(Scsi_Device * SDp)
+/**
+ *	sd_detect- called at the start of driver initialization, once 
+ *	for each scsi device (not just disks) present.
+ *
+ *	Returns 0 if not interested in this scsi device (e.g. scanner);
+ *	1 if this device is of interest (e.g. a disk).
+ *
+ *	Note: this function is invoked from the scsi mid-level.
+ *	This function is called before sd_init() so very little is available.
+ **/
+static int sd_detect(Scsi_Device * sdp)
 {
-	if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD)
+	SCSI_LOG_HLQUEUE(3, printk("sd_detect: type=%d\n", sdp->type));
+	if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD)
 		return 0;
 	sd_template.dev_noticed++;
 	return 1;
 }
 
-static int sd_attach(Scsi_Device * SDp)
+/**
+ *	sd_attach- called during driver initialization and whenever a
+ *	new scsi device is attached to the system. It is called once
+ *	for each scsi device (not just disks) present.
+ *	@sdp: pointer to mid level scsi device object
+ *
+ *	Returns 0 if successful (or not interested in this scsi device 
+ *	(e.g. scanner)); 1 when there is an error.
+ *
+ *	Note: this function is invoked from the scsi mid-level.
+ *	This function sets up the mapping between a given 
+ *	<host,channel,id,lun> (found in sdp) and new device name 
+ *	(e.g. /dev/sda). More precisely it is the block device major 
+ *	and minor number that is chosen here.
+ **/
+static int sd_attach(Scsi_Device * sdp)
 {
         unsigned int devnum;
-	Scsi_Disk *dpnt;
-	int i;
+	Scsi_Disk *sdkp;
+	int dsk_nr;
 	char nbuff[6];
+	unsigned long iflags;
 
-	if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD)
+	if ((NULL == sdp) ||
+	    ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)))
 		return 0;
 
+	SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", 
+			 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun));
 	if (sd_template.nr_dev >= sd_template.dev_max) {
-		SDp->attached--;
+		sdp->attached--;
+		printk(KERN_ERR "sd_init: no more room for device\n");
 		return 1;
 	}
-	for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++)
-		if (!dpnt->device)
+
+/* Assume sd_attach is not re-entrant (for time being) */
+/* Also think about sd_attach() and sd_detach() running coincidentally. */
+	write_lock_irqsave(&sd_dsk_arr_lock, iflags);
+	for (dsk_nr = 0; dsk_nr < sd_template.dev_max; dsk_nr++) {
+		sdkp = sd_dsk_arr[dsk_nr];
+		if (!sdkp->device) {
+			sdkp->device = sdp;
+			sdkp->has_part_table = 0;
 			break;
+		}
+	}
+	write_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
 
-	if (i >= sd_template.dev_max)
-		panic("scsi_devices corrupt (sd)");
+	if (dsk_nr >= sd_template.dev_max) {
+		/* panic("scsi_devices corrupt (sd)");  overkill */
+		printk(KERN_ERR "sd_init: sd_dsk_arr corrupted\n");
+		return 1;
+	}
 
-	rscsi_disks[i].device = SDp;
-	rscsi_disks[i].has_part_table = 0;
 	sd_template.nr_dev++;
-	SD_GENDISK(i).nr_real++;
-        devnum = i % SCSI_DISKS_PER_MAJOR;
-        SD_GENDISK(i).de_arr[devnum] = SDp->de;
-        if (SDp->removable)
-		SD_GENDISK(i).flags[devnum] |= GENHD_FL_REMOVABLE;
-	sd_devname(i, nbuff);
-	printk("Attached scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
-	       SDp->removable ? "removable " : "",
-	       nbuff, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+	SD_GENDISK(dsk_nr).nr_real++;
+        devnum = dsk_nr % SCSI_DISKS_PER_MAJOR;
+        SD_GENDISK(dsk_nr).de_arr[devnum] = sdp->de;
+        if (sdp->removable)
+		SD_GENDISK(dsk_nr).flags[devnum] |= GENHD_FL_REMOVABLE;
+	sd_dskname(dsk_nr, nbuff);
+	printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, "
+	       "id %d, lun %d\n", sdp->removable ? "removable " : "",
+	       nbuff, sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
 	return 0;
 }
 
-#define DEVICE_BUSY rscsi_disks[target].device->busy
-#define ALLOW_REVALIDATE rscsi_disks[target].device->allow_revalidate
-#define USAGE rscsi_disks[target].device->access_count
-#define CAPACITY rscsi_disks[target].capacity
-#define MAYBE_REINIT  sd_init_onedisk(target)
-
-/* This routine is called to flush all partitions and partition tables
- * for a changed scsi 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.
+/**
+ *	revalidate_scsidisk- called to flush all partitions and partition 
+ *	tables for a changed scsi disk. sd_init_onedisk() is then called
+ *	followed by re-reading the new partition table.
+ *      @dev: kernel device descriptor (kdev_t)
+ *      @maxusage: 0 when called from block level, 1 when called from
+ *      sd_ioctl().
+ *
+ *	Returns 0 if successful; negated errno value otherwise.
  */
 int revalidate_scsidisk(kdev_t dev, int maxusage)
 {
-	int target;
+	int dsk_nr = DEVICE_NR(dev);
 	int res;
+	Scsi_Disk * sdkp;
+	Scsi_Device * sdp;
 
-	target = DEVICE_NR(dev);
+	 SCSI_LOG_HLQUEUE(3, printk("revalidate_scsidisk: dsk_nr=%d\n", 
+			     DEVICE_NR(dev)));
+	sdkp = sd_get_sdisk(dsk_nr);
+	if ((NULL == sdkp) || (NULL == (sdp = sdkp->device)))
+		return -ENODEV;
 
-	if (DEVICE_BUSY || (ALLOW_REVALIDATE == 0 && USAGE > maxusage)) {
-		printk("Device busy for revalidation (usage=%d)\n", USAGE);
+	if (sdp->busy || ((sdp->allow_revalidate == 0) && 
+			  (sdp->access_count > maxusage))) {
+		printk(KERN_WARNING "Device busy for revalidation "
+		       "(access_count=%d)\n", sdp->access_count);
 		return -EBUSY;
 	}
-	DEVICE_BUSY = 1;
+	sdp->busy = 1;
 
 	res = wipe_partitions(dev);
 	if (res)
 		goto leave;
 
-#ifdef MAYBE_REINIT
-	MAYBE_REINIT;
-#endif
+	sd_init_onedisk(sdkp, dsk_nr);
 
-	grok_partitions(dev, CAPACITY);
+	grok_partitions(dev, sdkp->capacity);
 leave:
-	DEVICE_BUSY = 0;
+	sdp->busy = 0;
 	return res;
 }
 
@@ -1280,69 +1502,125 @@
 {
 	return revalidate_scsidisk(dev, 0);
 }
-static void sd_detach(Scsi_Device * SDp)
+
+/**
+ *	sd_detach- called whenever a scsi disk (previously recognized by
+ *	sd_attach) is detached from the system. It is called (potentially
+ *	multiple times) during sd module unload.
+ *	@sdp: pointer to mid level scsi device object
+ *
+ *	Note: this function is invoked from the scsi mid-level.
+ *	This function potentially frees up a device name (e.g. /dev/sdc)
+ *	that could be re-used by a subsequent sd_attach().
+ *	This function is not called when the built-in sd driver is "exit-ed".
+ **/
+static void sd_detach(Scsi_Device * sdp)
 {
-	Scsi_Disk *dpnt;
+	Scsi_Disk *sdkp = NULL;
 	kdev_t dev;
-	int i, j;
+	int dsk_nr, j;
 	int max_p;
 	int start;
+	unsigned long iflags;
 
-	for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++)
-		if (dpnt->device == SDp) {
-
-			max_p = 1 << sd_gendisk.minor_shift;
-			start = i << sd_gendisk.minor_shift;
-			dev = MKDEV_SD_PARTITION(start);
-			wipe_partitions(dev);
-			for (j = max_p - 1; j >= 0; j--)
-				sd_sizes[start + j] = 0;
-
-                        devfs_register_partitions (&SD_GENDISK (i),
-                                                   SD_MINOR_NUMBER (start), 1);
-			/* unregister_disk() */
-			dpnt->has_part_table = 0;
-			dpnt->device = NULL;
-			dpnt->capacity = 0;
-			SDp->attached--;
-			sd_template.dev_noticed--;
-			sd_template.nr_dev--;
-			SD_GENDISK(i).nr_real--;
-			return;
+	SCSI_LOG_HLQUEUE(3, printk("sd_detach: <%d,%d,%d,%d>\n", 
+			    sdp->host->host_no, sdp->channel, sdp->id, 
+			    sdp->lun));
+	write_lock_irqsave(&sd_dsk_arr_lock, iflags);
+	for (dsk_nr = 0; dsk_nr < sd_template.dev_max; dsk_nr++) {
+		sdkp = sd_dsk_arr[dsk_nr];
+		if (sdkp->device == sdp) {
+			sdkp->has_part_table = 0;
+			sdkp->device = NULL;
+			sdkp->capacity = 0;
+			/* sdkp->detaching = 1; */
+			break;
 		}
+	}
+	write_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
+	if (dsk_nr >= sd_template.dev_max)
+		return;
+
+	max_p = 1 << sd_gendisk.minor_shift;
+	start = dsk_nr << sd_gendisk.minor_shift;
+	dev = MKDEV_SD_PARTITION(start);
+	wipe_partitions(dev);
+	for (j = max_p - 1; j >= 0; j--)
+		sd_sizes[start + j] = 0;
+
+	devfs_register_partitions (&SD_GENDISK (dsk_nr),
+				   SD_MINOR_NUMBER (start), 1);
+	/* unregister_disk() */
+	sdp->attached--;
+	sd_template.dev_noticed--;
+	sd_template.nr_dev--;
+	SD_GENDISK(dsk_nr).nr_real--;
 }
 
+/**
+ *	init_sd- entry point for this driver (both when built in or when
+ *	a module).
+ *
+ *	Note: this function registers this driver with the scsi mid-level.
+ **/
 static int __init init_sd(void)
 {
+	SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
 	sd_template.module = THIS_MODULE;
 	return scsi_register_device(&sd_template);
 }
 
+/**
+ *	exit_sd- exit point for this driver (when it is	a module).
+ *
+ *	Note: this function unregisters this driver from the scsi mid-level.
+ **/
 static void __exit exit_sd(void)
 {
-	int i;
+	int k;
+	Scsi_Disk * sdkp;
 
+	SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
 	scsi_unregister_device(&sd_template);
-
-	for (i = 0; i < N_USED_SD_MAJORS; i++)
-		devfs_unregister_blkdev(SD_MAJOR(i), "sd");
+	for (k = 0; k < N_USED_SD_MAJORS; k++)
+		devfs_unregister_blkdev(SD_MAJOR(k), "sd");
 
 	sd_registered--;
-	if (rscsi_disks != NULL) {
-		kfree(rscsi_disks);
-		kfree(sd_sizes);
-		kfree(sd_blocksizes);
-		kfree((char *) sd);
-	}
-	for (i = 0; i < N_USED_SD_MAJORS; i++) {
-		del_gendisk(&(sd_gendisks[i]));
-		blk_clear(SD_MAJOR(i));
+	if (sd_dsk_arr != NULL) {
+		for (k = 0; k < sd_template.dev_max; ++k) {
+			sdkp = sd_dsk_arr[k];
+			if (sdkp)
+				vfree(sdkp);
+		}
+		vfree(sd_dsk_arr);
+	}
+	if (sd_sizes) vfree(sd_sizes);
+	if (sd) vfree((char *) sd);
+	for (k = 0; k < N_USED_SD_MAJORS; k++) {
+		blk_dev[SD_MAJOR(k)].queue = NULL;
+		del_gendisk(&(sd_gendisks[k]));
+		blk_clear(SD_MAJOR(k));
 	}
 	sd_template.dev_max = 0;
 	if (sd_gendisks != &sd_gendisk)
-		kfree(sd_gendisks);
+		vfree(sd_gendisks);
 }
 
+static Scsi_Disk * sd_get_sdisk(int index)
+{
+	Scsi_Disk * sdkp = NULL;
+	unsigned long iflags;
+
+	read_lock_irqsave(&sd_dsk_arr_lock, iflags);
+	if (sd_dsk_arr && (index >= 0) && (index < sd_template.dev_max))
+		sdkp = sd_dsk_arr[index];
+	read_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
+	return sdkp;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Youngdale");
+MODULE_DESCRIPTION("SCSI disk (sd) driver");
+
 module_init(init_sd);
 module_exit(exit_sd);
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Thu May  2 17:22:16 2002
+++ b/drivers/scsi/sr.c	Thu May  2 17:22:16 2002
@@ -89,8 +89,6 @@
 Scsi_CD *scsi_CDs;
 static int *sr_sizes;
 
-static int *sr_blocksizes;
-
 static int sr_open(struct cdrom_device_info *, int);
 void get_sectorsize(int);
 void get_capabilities(int);
@@ -724,18 +722,6 @@
 	if (!sr_sizes)
 		goto cleanup_cds;
 	memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
-
-	sr_blocksizes = kmalloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
-	if (!sr_blocksizes)
-		goto cleanup_sizes;
-
-	/*
-	 * These are good guesses for the time being.
-	 */
-	for (i = 0; i < sr_template.dev_max; i++)
-		sr_blocksizes[i] = 2048;
-
-	blksize_size[MAJOR_NR] = sr_blocksizes;
 	return 0;
 cleanup_sizes:
 	kfree(sr_sizes);
@@ -845,9 +831,6 @@
 
 		kfree(sr_sizes);
 		sr_sizes = NULL;
-
-		kfree(sr_blocksizes);
-		sr_blocksizes = NULL;
 	}
 	blk_clear(MAJOR_NR);
 
diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c
--- a/drivers/scsi/st.c	Thu May  2 17:22:17 2002
+++ b/drivers/scsi/st.c	Thu May  2 17:22:17 2002
@@ -12,13 +12,13 @@
    Copyright 1992 - 2002 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Wed Jan 23 20:22:42 2002 by makisara
+   Last modified: Tue Feb  5 21:25:55 2002 by makisara
    Some small formal changes - aeb, 950809
 
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
  */
 
-static char *verstr = "20020123";
+static char *verstr = "20020205";
 
 #include <linux/module.h>
 
@@ -2112,7 +2112,8 @@
 #define MODE_SELECT_PAGE_FORMAT 0x10
 
 /* Read a mode page into the tape buffer. The block descriptors are included
-   if incl_block_descs is true. */
+   if incl_block_descs is true. The page control is ored to the page number
+   parameter, if necessary. */
 static int read_mode_page(Scsi_Tape *STp, int page, int omit_block_descs)
 {
 	unsigned char cmd[MAX_COMMAND_SIZE];
diff -Nru a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c	Thu May  2 17:22:15 2002
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c	Thu May  2 17:22:15 2002
@@ -5947,7 +5947,7 @@
 	 */
 attach_failed:
 		sym_hcb_free(np);
-	return ENXIO;
+	return -ENXIO;
 }
 
 /*
diff -Nru a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
--- a/drivers/scsi/ultrastor.c	Thu May  2 17:22:15 2002
+++ b/drivers/scsi/ultrastor.c	Thu May  2 17:22:15 2002
@@ -371,14 +371,14 @@
 	return FALSE;
 
 #ifdef PORT_OVERRIDE
-    if(check_region(PORT_OVERRIDE, 0xc)) {
+    if(!request_region(PORT_OVERRIDE, 0xc, "ultrastor")) {
       printk("Ultrastor I/O space already in use\n");
       return FALSE;
     };
     config.port_address = PORT_OVERRIDE;
 #else
     for (i = 0; i < ARRAY_SIZE(ultrastor_ports_14f); i++) {
-      if(check_region(ultrastor_ports_14f[i], 0x0c)) continue;
+      if(!request_region(ultrastor_ports_14f[i], 0x0c, "ultrastor")) continue;
       config.port_address = ultrastor_ports_14f[i];
 #endif
 
@@ -396,8 +396,9 @@
 # endif
 #endif
 #ifdef PORT_OVERRIDE
-	    return FALSE;
+	    goto out_release_port;
 #else
+	    release_region(config.port_address, 0x0c);
 	    continue;
 #endif
 	}
@@ -412,8 +413,9 @@
 # endif
 #endif
 #ifdef PORT_OVERRIDE
-	    return FALSE;
+	    goto out_release_port;
 #else
+	    release_region(config.port_address, 0x0c);
 	    continue;
 #endif
 	}
@@ -425,6 +427,7 @@
 # if (ULTRASTOR_DEBUG & UD_DETECT)
 	printk("US14F: detect: no port address found!\n");
 # endif
+	/* all ports probed already released - we can just go straight out */
 	return FALSE;
     }
 #endif
@@ -441,7 +444,6 @@
     /* All above tests passed, must be the right thing.  Get some useful
        info. */
 
-    request_region(config.port_address, 0x0c,"ultrastor"); 
     /* Register the I/O space that we use */
 
     *(char *)&config_1 = inb(CONFIG(config.port_address + 0));
@@ -465,7 +467,7 @@
 #if (ULTRASTOR_DEBUG & UD_DETECT)
 	printk("US14F: detect: not detected.\n");
 #endif
-	return FALSE;
+	goto out_release_port;
     }
 
     /* Final consistency check, verify previous info. */
@@ -474,7 +476,7 @@
 #if (ULTRASTOR_DEBUG & UD_DETECT)
 	    printk("US14F: detect: consistency check failed\n");
 #endif
-	    return FALSE;
+           goto out_release_port;
 	}
 
     /* If we were TRULY paranoid, we could issue a host adapter inquiry
@@ -507,19 +509,22 @@
     if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", &config.mscp[0].SCint->host)) {
 	printk("Unable to allocate IRQ%u for UltraStor controller.\n",
 	       config.interrupt);
-	return FALSE;
+	goto out_release_port;
     }
     if (config.dma_channel && request_dma(config.dma_channel,"Ultrastor")) {
 	printk("Unable to allocate DMA channel %u for UltraStor controller.\n",
 	       config.dma_channel);
 	free_irq(config.interrupt, NULL);
-	return FALSE;
+	goto out_release_port;
     }
     tpnt->sg_tablesize = ULTRASTOR_14F_MAX_SG;
     printk("UltraStor driver version" VERSION ".  Using %d SG lists.\n",
 	   ULTRASTOR_14F_MAX_SG);
 
     return TRUE;
+out_release_port:
+    release_region(config.port_address, 0x0c);
+    return FALSE;
 }
 
 static int ultrastor_24f_detect(Scsi_Host_Template * tpnt)
diff -Nru a/drivers/usb/class/printer.c b/drivers/usb/class/printer.c
--- a/drivers/usb/class/printer.c	Thu May  2 17:22:16 2002
+++ b/drivers/usb/class/printer.c	Thu May  2 17:22:16 2002
@@ -794,6 +794,7 @@
 {
 	struct usblp *usblp = 0;
 	int protocol;
+	int retval;
 	char name[6];
 
 	/* Malloc and start initializing usblp structure so we can use it
@@ -808,7 +809,12 @@
 	init_waitqueue_head(&usblp->wait);
 	usblp->ifnum = ifnum;
 
-	if (usb_register_dev(&usblp_driver, 1, &usblp->minor)) {
+	retval = usb_register_dev(&usblp_driver, 1, &usblp->minor);
+	if (retval) {
+		if (retval != -ENODEV) {
+			err("Not able to get a minor for this device.");
+			goto abort;
+		}
 		/* Look for a free usblp_table entry on our own. */
 		while (usblp_table[usblp->minor]) {
 			usblp->minor++;
@@ -871,6 +877,9 @@
 	usblp_check_status(usblp, 0);
 #endif
 
+	/* add a table entry so the device works when advertised */
+	usblp_table[usblp->minor] = usblp;
+
 	/* If we have devfs, create with perms=660. */
 	sprintf(name, "lp%d", usblp->minor);
 	usblp->devfs = devfs_register(usb_devfs_handle, name,
@@ -886,7 +895,7 @@
 		usblp->current_protocol, usblp->dev->descriptor.idVendor,
 		usblp->dev->descriptor.idProduct);
 
-	return usblp_table[usblp->minor] = usblp;
+	return usblp;
 
 abort:
 	if (usblp) {
diff -Nru a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
--- a/drivers/usb/host/ohci-hub.c	Thu May  2 17:22:16 2002
+++ b/drivers/usb/host/ohci-hub.c	Thu May  2 17:22:16 2002
@@ -154,12 +154,10 @@
 	u16		wLength
 ) {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
-	int		ports;
+	int		ports = hcd->self.root_hub->maxchild;
 	u32		temp;
 	int		retval = 0;
 
-	// if (port request)
-		ports = roothub_a (ohci) & RH_A_NDP; 
 	switch (typeReq) {
 	case ClearHubFeature:
 		switch (wValue) {
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c	Thu May  2 17:22:17 2002
+++ b/drivers/usb/host/ohci-q.c	Thu May  2 17:22:17 2002
@@ -569,6 +569,9 @@
 	td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
 	td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
 
+	/* HC might read the TD right after we link it ... */
+	wmb ();
+
 	/* append to queue */
 	td->ed->hwTailP = td->hwNextTD;
 }
@@ -641,8 +644,10 @@
 				cnt++;
 			}
 			/* start bulk list */
-			if (!ohci->sleeping)
+			if (!ohci->sleeping) {
+				wmb ();
 				writel (OHCI_BLF, &ohci->regs->cmdstatus);
+			}
 			break;
 
 		case PIPE_INTERRUPT:
@@ -654,6 +659,7 @@
 			break;
 
 		case PIPE_CONTROL:
+			/* control requests don't use toggle state  */
 			info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
 			td_fill (ohci, info,
 #ifdef CONFIG_PCI
@@ -678,8 +684,10 @@
 				: TD_CC | TD_DP_OUT | TD_T_DATA1;
 			td_fill (ohci, info, data, 0, urb, cnt++);
 			/* start control list */
-			if (!ohci->sleeping)
+			if (!ohci->sleeping) {
+				wmb ();
 				writel (OHCI_CLF, &ohci->regs->cmdstatus);
+			}
 			break;
 
 		case PIPE_ISOCHRONOUS:
diff -Nru a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
--- a/drivers/usb/image/mdc800.c	Thu May  2 17:22:15 2002
+++ b/drivers/usb/image/mdc800.c	Thu May  2 17:22:15 2002
@@ -411,6 +411,7 @@
 	int i,j;
 	struct usb_interface_descriptor	*intf_desc;
 	int irq_interval=0;
+	int retval;
 
 	dbg ("(mdc800_usb_probe) called.");
 
@@ -475,7 +476,11 @@
 
 	down (&mdc800->io_lock);
 
-	usb_register_dev (&mdc800_usb_driver, 1, &mdc800->minor);
+	retval = usb_register_dev (&mdc800_usb_driver, 1, &mdc800->minor);
+	if (retval && (retval != -ENODEV)) {
+		err ("Not able to get a minor for this device.");
+		return 0;
+	}
 
 	mdc800->dev=dev;
 	mdc800->open=0;
diff -Nru a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c
--- a/drivers/usb/image/scanner.c	Thu May  2 17:22:16 2002
+++ b/drivers/usb/image/scanner.c	Thu May  2 17:22:16 2002
@@ -812,6 +812,7 @@
 	int ep_cnt;
 	int ix;
 	int scn_minor;
+	int retval;
 
 	char valid_device = 0;
 	char have_bulk_in, have_bulk_out, have_intr;
@@ -953,7 +954,13 @@
 	
 	down(&scn_mutex);
 
-	if (usb_register_dev(&scanner_driver, 1, &scn_minor)) {
+	retval = usb_register_dev(&scanner_driver, 1, &scn_minor);
+	if (retval) {
+		if (retval != -ENODEV) {
+			err ("Not able to get a minor for this device.");
+			up(&scn_mutex);
+			return NULL;
+		}
 		for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {
 			if (!p_scn_table[scn_minor])
 				break;
diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
--- a/drivers/usb/input/hiddev.c	Thu May  2 17:22:16 2002
+++ b/drivers/usb/input/hiddev.c	Thu May  2 17:22:16 2002
@@ -606,6 +606,7 @@
 {
 	struct hiddev *hiddev;
 	int minor, i;
+	int retval;
 	char devfs_name[16];
 
 	for (i = 0; i < hid->maxapplication; i++)
@@ -615,7 +616,12 @@
 	if (i == hid->maxapplication)
 		return -1;
 
-	if (usb_register_dev (&hiddev_driver, 1, &minor)) {
+	retval = usb_register_dev (&hiddev_driver, 1, &minor);
+	if (retval) {
+		if (retval != -ENODEV) {
+			err ("Not able to get a minor for this device.");
+			return -1;
+		}
 		for (minor = 0; minor < HIDDEV_MINORS && hiddev_table[minor]; minor++);
 		if (minor == HIDDEV_MINORS) {
 			printk(KERN_ERR "hiddev: no more free hiddev devices\n");
diff -Nru a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c
--- a/drivers/usb/media/dabusb.c	Thu May  2 17:22:17 2002
+++ b/drivers/usb/media/dabusb.c	Thu May  2 17:22:17 2002
@@ -727,6 +727,7 @@
 			   const struct usb_device_id *id)
 {
 	int devnum;
+	int retval;
 	pdabusb_t s;
 
 	dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
@@ -739,7 +740,10 @@
 	if (ifnum != _DABUSB_IF && usbdev->descriptor.idProduct == 0x9999)
 		return NULL;
 
-	if (usb_register_dev (&dabusb_driver, 1, &devnum)) {
+	retval = usb_register_dev (&dabusb_driver, 1, &devnum);
+	if (retval) {
+		if (retval != -ENODEV)
+			return NULL;
 		devnum = dabusb_find_struct ();
 		if (devnum == -1)
 			return NULL;
diff -Nru a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c
--- a/drivers/usb/media/ibmcam.c	Thu May  2 17:22:16 2002
+++ b/drivers/usb/media/ibmcam.c	Thu May  2 17:22:16 2002
@@ -3899,6 +3899,17 @@
 	return uvd;
 }
 
+
+static struct usb_device_id id_table[] = {
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) },	/* Model 1 */
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 2 */
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) },	/* Model 3 */
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 4 */
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 2 */
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 4 */
+	{ }  /* Terminating entry */
+};
+
 /*
  * ibmcam_init()
  *
@@ -3926,7 +3937,8 @@
 		sizeof(ibmcam_t),
 		"ibmcam",
 		&cbTbl,
-		THIS_MODULE);
+		THIS_MODULE,
+		id_table);
 }
 
 static void __exit ibmcam_cleanup(void)
@@ -3934,15 +3946,6 @@
 	usbvideo_Deregister(&cams);
 }
 
-static __devinitdata struct usb_device_id id_table[] = {
-	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) },	/* Model 1 */
-	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 2 */
-	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) },	/* Model 3 */
-	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 4 */
-	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 2 */
-	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 4 */
-	{ }  /* Terminating entry */
-};
 MODULE_DEVICE_TABLE(usb, id_table);
 
 module_init(ibmcam_init);
diff -Nru a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c
--- a/drivers/usb/media/konicawc.c	Thu May  2 17:22:15 2002
+++ b/drivers/usb/media/konicawc.c	Thu May  2 17:22:15 2002
@@ -767,7 +767,8 @@
 		sizeof(struct konicawc),
 		"konicawc",
 		&cbTbl,
-		THIS_MODULE);
+		THIS_MODULE,
+		id_table);
 }
 
 
diff -Nru a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c
--- a/drivers/usb/media/ultracam.c	Thu May  2 17:22:16 2002
+++ b/drivers/usb/media/ultracam.c	Thu May  2 17:22:16 2002
@@ -659,6 +659,12 @@
 	return uvd;
 }
 
+
+static struct usb_device_id id_table[] = {
+	{ USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
+	{ }  /* Terminating entry */
+};
+
 /*
  * ultracam_init()
  *
@@ -682,7 +688,8 @@
 		sizeof(ultracam_t),
 		"ultracam",
 		&cbTbl,
-		THIS_MODULE);
+		THIS_MODULE,
+		id_table);
 }
 
 static void __exit ultracam_cleanup(void)
@@ -690,16 +697,7 @@
 	usbvideo_Deregister(&cams);
 }
 
-#if defined(usb_device_id_ver)
-
-static __devinitdata struct usb_device_id id_table[] = {
-	{ USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
-	{ }  /* Terminating entry */
-};
 MODULE_DEVICE_TABLE(usb, id_table);
-
-
-#endif /* defined(usb_device_id_ver) */
 MODULE_LICENSE("GPL");
 
 module_init(ultracam_init);
diff -Nru a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c
--- a/drivers/usb/media/usbvideo.c	Thu May  2 17:22:17 2002
+++ b/drivers/usb/media/usbvideo.c	Thu May  2 17:22:17 2002
@@ -749,7 +749,8 @@
 	const int num_extra,
 	const char *driverName,
 	const usbvideo_cb_t *cbTbl,
-	struct module *md )
+	struct module *md,
+	const struct usb_device_id *id_table)
 {
 	static const char proc[] = "usbvideo_register";
 	usbvideo_t *cams;
@@ -839,6 +840,7 @@
 	cams->usbdrv.name = cams->drvName;
 	cams->usbdrv.probe = cams->cb.probe;
 	cams->usbdrv.disconnect = cams->cb.disconnect;
+	cams->usbdrv.id_table = id_table;
 
 #if USES_PROC_FS
 	if (cams->uses_procfs) {
@@ -1192,7 +1194,7 @@
 	if (!CAMERA_IS_OPERATIONAL(uvd))
 		return -EFAULT;
 
-	if (size > (((2 * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+	if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
 		return -EINVAL;
 
 	pos = (unsigned long) uvd->fbuf;
@@ -1471,12 +1473,14 @@
 		case VIDIOCGMBUF:
 		{
 			struct video_mbuf *vm = arg;
+			int i;
 
 			memset(vm, 0, sizeof(*vm));
-			vm->size = uvd->max_frame_size * 2;
-			vm->frames = 2;
-			vm->offsets[0] = 0;
-			vm->offsets[1] = uvd->max_frame_size;
+			vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES;
+			vm->frames = USBVIDEO_NUMFRAMES;
+			for(i = 0; i < USBVIDEO_NUMFRAMES; i++) 
+			  vm->offsets[i] = i * uvd->max_frame_size;
+
 			return 0;
 		}
 		case VIDIOCMCAPTURE:
@@ -1518,8 +1522,8 @@
 				}
 				return -EINVAL;
 			}
-			if ((vm->frame != 0) && (vm->frame != 1)) {
-				err("VIDIOCMCAPTURE: vm.frame=%d. !E [0,1]", vm->frame);
+			if ((vm->frame < 0) || (vm->frame >= USBVIDEO_NUMFRAMES)) {
+				err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1);
 				return -EINVAL;
 			}
 			if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) {
@@ -1618,7 +1622,7 @@
 	static const char proc[] = "usbvideo_v4l_read";
 	uvd_t *uvd = file->private_data;
 	int noblock = file->f_flags & O_NONBLOCK;
-	int frmx = -1;
+	int frmx = -1, i;
 	usbvideo_frame_t *frame;
 
 	if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL))
@@ -1630,14 +1634,13 @@
 	down(&uvd->lock);	
 
 	/* See if a frame is completed, then use it. */
-	if ((uvd->frame[0].frameState == FrameState_Done) ||
-	    (uvd->frame[0].frameState == FrameState_Done_Hold) ||
-	    (uvd->frame[0].frameState == FrameState_Error)) {
-		frmx = 0;
-	} else if ((uvd->frame[1].frameState >= FrameState_Done) ||
-		   (uvd->frame[1].frameState == FrameState_Done_Hold) ||
-		   (uvd->frame[1].frameState >= FrameState_Done)) {
-		frmx = 1;
+	for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
+		if ((uvd->frame[i].frameState == FrameState_Done) ||
+		    (uvd->frame[i].frameState == FrameState_Done_Hold) ||
+		    (uvd->frame[i].frameState == FrameState_Error)) {
+			frmx = i;
+			break;
+		}
 	}
 
 	/* FIXME: If we don't start a frame here then who ever does? */
@@ -1652,10 +1655,12 @@
 	 * We will need to wait until it becomes cooked, of course.
 	 */
 	if (frmx == -1) {
-		if (uvd->frame[0].frameState == FrameState_Grabbing)
-			frmx = 0;
-		else if (uvd->frame[1].frameState == FrameState_Grabbing)
-			frmx = 1;
+		for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
+			if (uvd->frame[i].frameState == FrameState_Grabbing) {
+				frmx = i;
+				break;
+			}
+		}
 	}
 
 	/*
@@ -1753,7 +1758,7 @@
 
 		/* Mark it as available to be used again. */
 		uvd->frame[frmx].frameState = FrameState_Unused;
-		if (usbvideo_NewFrame(uvd, frmx ? 0 : 1)) {
+		if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
 			err("%s: usbvideo_NewFrame failed.", proc);
 		}
 	}
@@ -1990,7 +1995,7 @@
 		uvd->settingsAdjusted = 1;
 	}
 
-	n = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES;
+	n = (framenum + 1) % USBVIDEO_NUMFRAMES;
 	if (uvd->frame[n].frameState == FrameState_Ready)
 		framenum = n;
 
@@ -2022,7 +2027,8 @@
 	 */
 	if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) {
 		/* This copies previous frame into this one to mask losses */
-		memmove(frame->data, uvd->frame[1-framenum].data, uvd->max_frame_size);
+		int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES;
+		memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size);
 	} else {
 		if (uvd->flags & FLAGS_CLEAN_FRAMES) {
 			/* This provides a "clean" frame but slows things down */
diff -Nru a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h
--- a/drivers/usb/media/usbvideo.h	Thu May  2 17:22:16 2002
+++ b/drivers/usb/media/usbvideo.h	Thu May  2 17:22:16 2002
@@ -327,7 +327,8 @@
 	const int num_extra,
 	const char *driverName,
 	const usbvideo_cb_t *cbTable,
-	struct module *md);
+	struct module *md,
+	const struct usb_device_id *id_table);
 uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams);
 int usbvideo_RegisterVideoDevice(uvd_t *uvd);
 void usbvideo_Deregister(usbvideo_t **uvt);
diff -Nru a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
--- a/drivers/usb/misc/auerswald.c	Thu May  2 17:22:16 2002
+++ b/drivers/usb/misc/auerswald.c	Thu May  2 17:22:16 2002
@@ -1948,7 +1948,13 @@
 	init_waitqueue_head (&cp->bufferwait);
 
 	down (&dev_table_mutex);
-	if (usb_register_dev (&auerswald_driver, 1, &dtindex)) {
+	ret = usb_register_dev (&auerswald_driver, 1, &dtindex);
+	if (ret) {
+		if (ret != -ENODEV) {
+			err ("Not able to get a minor for this device.");
+			up (&dev_table_mutex);
+			goto pfail;
+		}
 		/* find a free slot in the device table */
 		for (dtindex = 0; dtindex < AUER_MAX_DEVICES; ++dtindex) {
 			if (dev_table[dtindex] == NULL)
diff -Nru a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c
--- a/drivers/usb/misc/brlvger.c	Thu May  2 17:22:17 2002
+++ b/drivers/usb/misc/brlvger.c	Thu May  2 17:22:17 2002
@@ -290,6 +290,7 @@
 {
 	struct brlvger_priv *priv = NULL;
 	int i;
+	int retval;
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_interface_descriptor *actifsettings;
 	/* protects against reentrance: once we've found a free slot
@@ -315,7 +316,12 @@
 
 	down(&reserve_sem);
 
-	if (usb_register_dev(&brlvger_driver, 1, &i)) {
+	retval = usb_register_dev(&brlvger_driver, 1, &i);
+	if (retval) {
+		if (retval != -ENODEV) {
+			err("Not able to get a minor for this device.");
+			goto error;
+		}
 		for( i = 0; i < MAX_NR_BRLVGER_DEVS; i++ )
 			if( display_table[i] == NULL )
 				break;
diff -Nru a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
--- a/drivers/usb/net/pegasus.c	Thu May  2 17:22:17 2002
+++ b/drivers/usb/net/pegasus.c	Thu May  2 17:22:17 2002
@@ -62,6 +62,8 @@
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
+static const char driver_name [] = "pegasus";
+
 #define	PEGASUS_USE_INTR
 #define	PEGASUS_WRITE_EEPROM
 #define	BMSR_MEDIA	(BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
@@ -811,7 +813,6 @@
 {
 	pegasus_t *pegasus;
 	int cmd;
-	char tmp[128];
 
 	pegasus = net->priv;
 	if (get_user(cmd, (int *) uaddr))
@@ -819,12 +820,11 @@
 	switch (cmd) {
 	case ETHTOOL_GDRVINFO:{
 			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-			strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
+			strncpy(info.driver, driver_name, sizeof info.driver);
 			strncpy(info.version, DRIVER_VERSION,
 				ETHTOOL_BUSINFO_LEN);
-			sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum,
-				pegasus->usb->devnum);
-			strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
+			usb_make_path(pegasus->usb, info.bus_info,
+				sizeof info.bus_info);
 			if (copy_to_user(uaddr, &info, sizeof(info)))
 				return -EFAULT;
 			return 0;
@@ -833,8 +833,7 @@
 			struct ethtool_cmd ecmd;
 			short lpa, bmcr;
 
-			if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
-				return -EFAULT;
+			memset(&ecmd, 0, sizeof ecmd);
 			ecmd.supported = (SUPPORTED_10baseT_Half |
 					  SUPPORTED_10baseT_Full |
 					  SUPPORTED_100baseT_Half |
@@ -1104,7 +1103,7 @@
 }
 
 static struct usb_driver pegasus_driver = {
-	name:		"pegasus",
+	name:		driver_name,
 	probe:		pegasus_probe,
 	disconnect:	pegasus_disconnect,
 	id_table:	pegasus_ids,
diff -Nru a/drivers/usb/serial/Config.help b/drivers/usb/serial/Config.help
--- a/drivers/usb/serial/Config.help	Thu May  2 17:22:16 2002
+++ b/drivers/usb/serial/Config.help	Thu May  2 17:22:16 2002
@@ -60,9 +60,9 @@
   module, say M here and read <file:Documentation/modules.txt>.
 
 CONFIG_USB_SERIAL_IPAQ
-  Say Y here if you want to connect to your Compaq iPAQ or HP Jornada
-  548/568 running Windows CE 3.0 or PocketPC 2002 using a USB
-  cradle/cable. For information on using the driver,
+  Say Y here if you want to connect to your Compaq iPAQ, HP Jornada
+  548/568 or Casio EM500 running Windows CE 3.0 or PocketPC 2002
+  using a USB cradle/cable. For information on using the driver,
   read <file:Documentation/usb/usb-serial.txt>.
 
   This code is also available as a module ( = code which can be
diff -Nru a/drivers/usb/serial/Config.in b/drivers/usb/serial/Config.in
--- a/drivers/usb/serial/Config.in	Thu May  2 17:22:15 2002
+++ b/drivers/usb/serial/Config.in	Thu May  2 17:22:15 2002
@@ -16,7 +16,7 @@
 dep_tristate '  USB Empeg empeg-car Mark I/II Driver' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL
 dep_tristate '  USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
-dep_tristate '  USB Compaq iPAQ / HP Jornada Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
+dep_tristate '  USB Compaq iPAQ / HP Jornada / Casio EM500 Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
 dep_tristate '  USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Inside Out Edgeport Serial Driver' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL
 dep_tristate '  USB Keyspan PDA Single Port Serial Driver' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL
diff -Nru a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
--- a/drivers/usb/serial/io_tables.h	Thu May  2 17:22:16 2002
+++ b/drivers/usb/serial/io_tables.h	Thu May  2 17:22:16 2002
@@ -25,6 +25,11 @@
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_421) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_21) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2_DIN) },
 	{ }
 };
 
@@ -37,6 +42,11 @@
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4T) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8_DUAL_CPU) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4_DIN) },
 	{ }
 };
 
@@ -44,6 +54,9 @@
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8I) },
 	{ }
 };
 
@@ -66,6 +79,19 @@
 	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_COMPATIBLE) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_8I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_421) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_21) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2_DIN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4T) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8_DUAL_CPU) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4_DIN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8I) },
 	{ }							/* Terminating entry */
 };
 
diff -Nru a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
--- a/drivers/usb/serial/io_usbvend.h	Thu May  2 17:22:16 2002
+++ b/drivers/usb/serial/io_usbvend.h	Thu May  2 17:22:16 2002
@@ -92,6 +92,20 @@
 #define ION_DEVICE_ID_EDGEPORT_8I		0x014	// Edgeport/8 RS422 (single-CPU)
 #define ION_DEVICE_ID_MT4X56USB			0x1403	// OEM device
 
+// BlackBox OEM devices
+#define ION_DEVICE_ID_BB_EDGEPORT_4		0x001	// Edgeport/4 RS232
+#define ION_DEVICE_ID_BB_EDGEPORT_4T		0x004	// Edgeport/4 RS232 for Telxon (aka "Fleetport")
+#define ION_DEVICE_ID_BB_EDGEPORT_2		0x005	// Edgeport/2 RS232
+#define ION_DEVICE_ID_BB_EDGEPORT_4I		0x006	// Edgeport/4 RS422
+#define ION_DEVICE_ID_BB_EDGEPORT_2I		0x007	// Edgeport/2 RS422/RS485
+#define	ION_DEVICE_ID_BB_EDGEPORT_421		0x00C	// Edgeport/421 Hub+RS232+Parallel
+#define	ION_DEVICE_ID_BB_EDGEPORT_21		0x00D	// Edgeport/21  RS232+Parallel
+#define ION_DEVICE_ID_BB_EDGEPORT_8_DUAL_CPU	0x00E	// Half of an Edgeport/8 (the kind with 2 EP/4s on 1 PCB)
+#define ION_DEVICE_ID_BB_EDGEPORT_8		0x00F	// Edgeport/8 (single-CPU)
+#define ION_DEVICE_ID_BB_EDGEPORT_2_DIN		0x010	// Edgeport/2 RS232 with Apple DIN connector
+#define ION_DEVICE_ID_BB_EDGEPORT_4_DIN		0x011	// Edgeport/4 RS232 with Apple DIN connector
+#define ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU	0x012	// Half of an Edgeport/16 (the kind with 2 EP/8s)
+#define ION_DEVICE_ID_BB_EDGEPORT_8I		0x014	// Edgeport/8 RS422 (single-CPU)
 // These IDs are used by the Edgeport.exe program for uninstalling.
 // 
 #define EDGEPORT_DEVICE_IDS	{0x001, 0x003, 0x004, 0x005, 0x006, 0x007, 0x00B, \
diff -Nru a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
--- a/drivers/usb/serial/ipaq.c	Thu May  2 17:22:16 2002
+++ b/drivers/usb/serial/ipaq.c	Thu May  2 17:22:16 2002
@@ -9,6 +9,10 @@
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
  *
+ * (30/4/2002) ganesh
+ * 	Added support for the Casio EM500. Completely untested. Thanks
+ * 	to info from Nathan <wfilardo@fuse.net>
+ *
  * (19/3/2002) ganesh
  *	Don't submit urbs while holding spinlocks. Not strictly necessary
  *	in 2.5.x.
@@ -58,7 +62,7 @@
  */
 #define DRIVER_VERSION "v0.2"
 #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
-#define DRIVER_DESC "USB Compaq iPAQ, HP Jornada driver"
+#define DRIVER_DESC "USB Compaq iPAQ, HP Jornada, Casio EM500 driver"
 
 /* Function prototypes for an ipaq */
 static int  ipaq_open (struct usb_serial_port *port, struct file *filp);
@@ -81,6 +85,7 @@
 	{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) },
+	{ USB_DEVICE(CASIO_VENDOR_ID, CASIO_EM500_ID) },
 	{ }					/* Terminating entry */
 };
 
diff -Nru a/drivers/usb/serial/ipaq.h b/drivers/usb/serial/ipaq.h
--- a/drivers/usb/serial/ipaq.h	Thu May  2 17:22:15 2002
+++ b/drivers/usb/serial/ipaq.h	Thu May  2 17:22:15 2002
@@ -23,6 +23,9 @@
 #define HP_JORNADA_548_ID	0x1016
 #define HP_JORNADA_568_ID	0x1116
 
+#define CASIO_VENDOR_ID		0x07cf
+#define CASIO_EM500_ID		0x2002
+
 /*
  * Since we can't queue our bulk write urbs (don't know why - it just
  * doesn't work), we can send down only one write urb at a time. The simplistic
diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c	Thu May  2 17:22:17 2002
+++ b/drivers/usb/serial/pl2303.c	Thu May  2 17:22:17 2002
@@ -142,6 +142,7 @@
 
 struct pl2303_private { 
 	u8 line_control;
+	u8 termios_initialized;
 };
 
 
@@ -214,13 +215,19 @@
 	int baud;
 	int i;
 
-	dbg (__FUNCTION__ " -  port %d", port->number);
+	dbg (__FUNCTION__ " -  port %d, initialized = %d", port->number, 
+	     ((struct pl2303_private *) port->private)->termios_initialized);
 
 	if ((!port->tty) || (!port->tty->termios)) {
 		dbg(__FUNCTION__" - no tty structures");
 		return;
 	}
 
+	if (!(((struct pl2303_private *) port->private)->termios_initialized)) {
+		*(port->tty->termios) = tty_std_termios;
+		port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+		((struct pl2303_private *) port->private)->termios_initialized = 1;
+	}
 	cflag = port->tty->termios->c_cflag;
 	/* check that they really want us to change something */
 	if (old_termios) {
@@ -390,9 +397,6 @@
 
 	/* Setup termios */
 	if (port->tty) {
-		*(port->tty->termios) = tty_std_termios;
-		port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-
 		pl2303_set_termios (port, &tmp_termios);
 	}
 
diff -Nru a/drivers/usb/storage/Config.help b/drivers/usb/storage/Config.help
--- a/drivers/usb/storage/Config.help	Thu May  2 17:22:16 2002
+++ b/drivers/usb/storage/Config.help	Thu May  2 17:22:16 2002
@@ -28,11 +28,15 @@
   Support for the Freecom USB to IDE/ATAPI adaptor.
   Freecom has a web page at <http://www.freecom.de/>.
 
+CONFIG_USB_STORAGE_DATAFAB
+  Support for certain Datafab CompactFlash readers.
+  Datafab has a web page at <http://www.datafabusa.com/>.
+
 CONFIG_USB_STORAGE_DPCM
-  Say Y here to support the Microtech ZiO! CompactFlash/SmartMedia
-  reader, details at <http://www.microtechint.com/zio/index.html>.
-  This driver treats the flash card as a removable storage device.
+  Say Y here to support the Microtech ZiO! CompactFlash reader.
+  There is a web page at <http://www.microtechint.com/zio/index.html>.
 
 CONFIG_USB_STORAGE_SDDR09
   Say Y here to include additional code to support the Sandisk SDDR-09
   SmartMedia reader in the USB Mass Storage driver.
+  Also works for the Microtech Zio! SmartMedia reader.
diff -Nru a/drivers/usb/storage/Config.in b/drivers/usb/storage/Config.in
--- a/drivers/usb/storage/Config.in	Thu May  2 17:22:16 2002
+++ b/drivers/usb/storage/Config.in	Thu May  2 17:22:16 2002
@@ -6,7 +6,7 @@
 fi
 dep_tristate '  USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
    dep_mbool '    USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE
-   dep_mbool '    Datafab MDCFE-B Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+   dep_mbool '    Datafab Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
    dep_mbool '    Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM  $CONFIG_USB_STORAGE
    dep_mbool '    ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE
    dep_mbool '    Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE
diff -Nru a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c
--- a/drivers/usb/storage/debug.c	Thu May  2 17:22:16 2002
+++ b/drivers/usb/storage/debug.c	Thu May  2 17:22:16 2002
@@ -327,6 +327,7 @@
 	case 0x3502: what="enclosure services unavailable"; break;
 	case 0x3503: what="enclosure services transfer failure"; break;
 	case 0x3504: what="enclosure services transfer refused"; break;
+	case 0x3A00: what="medium not present"; break;
 	case 0x3B0F: what="end of medium reached"; break;
 	case 0x3F02: what="changed operating definition"; break;
 	case 0x4100: what="data path failure (should use 40 NN)"; break;
diff -Nru a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
--- a/drivers/usb/storage/initializers.h	Thu May  2 17:22:17 2002
+++ b/drivers/usb/storage/initializers.h	Thu May  2 17:22:17 2002
@@ -37,8 +37,13 @@
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/config.h>
 #include "usb.h"
 
 /* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
  * mode */
 int usb_stor_euscsi_init(struct us_data *us);
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+int sddr09_init(struct us_data *us);
+#endif
diff -Nru a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
--- a/drivers/usb/storage/jumpshot.c	Thu May  2 17:22:15 2002
+++ b/drivers/usb/storage/jumpshot.c	Thu May  2 17:22:15 2002
@@ -192,7 +192,7 @@
 		return US_BULK_TRANSFER_SHORT;
 	}
 
-	US_DEBUGP("jumpshot_raw_bulk:  Transfered %d of %d bytes\n", act_len, len);
+	US_DEBUGP("jumpshot_raw_bulk:  Transferred %d of %d bytes\n", act_len, len);
 	return US_BULK_TRANSFER_GOOD;
 }
 
diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
--- a/drivers/usb/storage/sddr09.c	Thu May  2 17:22:17 2002
+++ b/drivers/usb/storage/sddr09.c	Thu May  2 17:22:17 2002
@@ -1,18 +1,12 @@
 /* Driver for SanDisk SDDR-09 SmartMedia reader
  *
- * $Id: sddr09.c,v 1.22 2001/12/08 23:32:48 mdharm Exp $
- *
- * SDDR09 driver v0.1:
- *
- * First release
- *
- * Current development and maintenance by:
  *   (c) 2000, 2001 Robert Baruch (autophile@starband.net)
+ *   (c) 2002 Andries Brouwer (aeb@cwi.nl)
  *
  * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip.
  * This chip is a programmable USB controller. In the SDDR-09, it has
- * been programmed to obey a certain limited set of SCSI commands. This
- * driver translates the "real" SCSI commands to the SDDR-09 SCSI
+ * been programmed to obey a certain limited set of SCSI commands.
+ * This driver translates the "real" SCSI commands to the SDDR-09 SCSI
  * commands.
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -44,6 +38,180 @@
 #define LSB_of(s) ((s)&0xFF)
 #define MSB_of(s) ((s)>>8)
 
+/* #define US_DEBUGP printk */
+
+/*
+ * First some stuff that does not belong here:
+ * data on SmartMedia and other cards, completely
+ * unrelated to this driver.
+ * Similar stuff occurs in <linux/mtd/nand_ids.h>.
+ */
+
+struct nand_flash_dev {
+	int model_id;
+	int chipshift;		/* 1<<cs bytes total capacity */
+	char pageshift;		/* 1<<ps bytes in a page */
+	char blockshift;	/* 1<<bs pages in an erase block */
+	char zoneshift;		/* 1<<zs blocks in a zone */
+				/* # of logical blocks is 125/128 of this */
+	char pageadrlen;	/* length of an address in bytes - 1 */
+};
+
+/*
+ * NAND Flash Manufacturer ID Codes
+ */
+#define NAND_MFR_AMD		0x01
+#define NAND_MFR_TOSHIBA	0x98
+#define NAND_MFR_SAMSUNG	0xec
+
+static inline char *nand_flash_manufacturer(int manuf_id) {
+	switch(manuf_id) {
+	case NAND_MFR_AMD:
+		return "AMD";
+	case NAND_MFR_TOSHIBA:
+		return "Toshiba";
+	case NAND_MFR_SAMSUNG:
+		return "Samsung";
+	default:
+		return "unknown";
+	}
+}
+
+/*
+ * It looks like it is unnecessary to attach manufacturer to the
+ * remaining data: SSFDC prescribes manufacturer-independent id codes.
+ */
+
+static struct nand_flash_dev nand_flash_ids[] = {
+	/* NAND flash - these I verified */
+	{ 0x6e, 20, 8, 4, 8, 2},	/* 1 MB */
+	{ 0xe8, 20, 8, 4, 8, 2},	/* 1 MB */
+	{ 0xec, 20, 8, 4, 8, 2},	/* 1 MB */
+	{ 0x64, 21, 8, 4, 9, 2}, 	/* 2 MB */
+	{ 0xea, 21, 8, 4, 9, 2},	/* 2 MB */
+	{ 0x6b, 22, 9, 4, 9, 2},	/* 4 MB */
+	{ 0xe3, 22, 9, 4, 9, 2},	/* 4 MB */
+	{ 0xe5, 22, 9, 4, 9, 2},	/* 4 MB */
+	{ 0xe6, 23, 9, 4, 10, 2},	/* 8 MB */
+	{ 0x73, 24, 9, 5, 10, 2},	/* 16 MB */
+	{ 0x75, 25, 9, 5, 10, 2},	/* 32 MB */
+	{ 0x76, 26, 9, 5, 10, 3},	/* 64 MB */
+	{ 0x79, 27, 9, 5, 10, 3},	/* 128 MB */
+	/* There do also exist 96 MB (from Datafab) and 256 MB cards */
+
+	/* MASK ROM - from unknown source */
+	{ 0x5d, 21, 9, 4, 8, 2},	/* 2 MB */
+	{ 0xd5, 22, 9, 4, 9, 2},	/* 4 MB */
+	{ 0xd6, 23, 9, 4, 10, 2},	/* 8 MB */
+	{ 0,}
+};
+
+#define SIZE(a)	(sizeof(a)/sizeof((a)[0]))
+
+static struct nand_flash_dev *
+nand_find_id(unsigned char id) {
+	int i;
+
+	for (i = 0; i < SIZE(nand_flash_ids); i++)
+		if (nand_flash_ids[i].model_id == id)
+			return &(nand_flash_ids[i]);
+	return NULL;
+}
+
+/*
+ * ECC computation.
+ */
+static unsigned char parity[256];
+static unsigned char ecc2[256];
+
+static void nand_init_ecc(void) {
+	int i, j, a;
+
+	parity[0] = 0;
+	for (i = 1; i < 256; i++)
+		parity[i] = (parity[i&(i-1)] ^ 1);
+
+	for (i = 0; i < 256; i++) {
+		a = 0;
+		for (j = 0; j < 8; j++) {
+			if (i & (1<<j)) {
+				if ((j & 1) == 0)
+					a ^= 0x04;
+				if ((j & 2) == 0)
+					a ^= 0x10;
+				if ((j & 4) == 0)
+					a ^= 0x40;
+			}
+		}
+		ecc2[i] = ~(a ^ (a<<1) ^ (parity[i] ? 0xa8 : 0));
+	}
+}
+
+/* compute 3-byte ecc on 256 bytes */
+static void nand_compute_ecc(unsigned char *data, unsigned char *ecc) {
+	int i, j, a;
+	unsigned char par, bit, bits[8];
+
+	par = 0;
+	for (j = 0; j < 8; j++)
+		bits[j] = 0;
+
+	/* collect 16 checksum bits */
+	for (i = 0; i < 256; i++) {
+		par ^= data[i];
+		bit = parity[data[i]];
+		for (j = 0; j < 8; j++)
+			if ((i & (1<<j)) == 0)
+				bits[j] ^= bit;
+	}
+
+	/* put 4+4+4 = 12 bits in the ecc */
+	a = (bits[3] << 6) + (bits[2] << 4) + (bits[1] << 2) + bits[0];
+	ecc[0] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
+
+	a = (bits[7] << 6) + (bits[6] << 4) + (bits[5] << 2) + bits[4];
+	ecc[1] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
+
+	ecc[2] = ecc2[par];
+}
+
+static int nand_compare_ecc(unsigned char *data, unsigned char *ecc) {
+	return (data[0] == ecc[0] && data[1] == ecc[1] && data[2] == ecc[2]);
+}
+
+static void nand_store_ecc(unsigned char *data, unsigned char *ecc) {
+	memcpy(data, ecc, 3);
+}
+
+/*
+ * The actual driver starts here.
+ */
+
+/*
+ * On my 16MB card, control blocks have size 64 (16 real control bytes,
+ * and 48 junk bytes). In reality of course the card uses 16 control bytes,
+ * so the reader makes up the remaining 48. Don't know whether these numbers
+ * depend on the card. For now a constant.
+ */
+#define CONTROL_SHIFT 6
+
+/*
+ * On my Combo CF/SM reader, the SM reader has LUN 1.
+ * (and things fail with LUN 0).
+ * It seems LUN is irrelevant for others.
+ */
+#define LUN	1
+#define	LUNBITS	(LUN << 5)
+
+/*
+ * LBA and PBA are unsigned ints. Special values.
+ */
+#define UNDEF    0xffffffff
+#define SPARE    0xfffffffe
+#define UNUSABLE 0xfffffffd
+
+static int erase_bad_lba_entries = 0;
+
 /*
  * Send a control message and wait for the response.
  *
@@ -63,27 +231,18 @@
  *
  */
 
-static int sddr09_send_control(struct us_data *us,
-		int pipe,
-		unsigned char request,
-		unsigned char requesttype,
-		unsigned short value,
-		unsigned short index,
-		unsigned char *xfer_data,
-		unsigned int xfer_len) {
+static int
+sddr09_send_control(struct us_data *us,
+		    int pipe,
+		    unsigned char request,
+		    unsigned char requesttype,
+		    unsigned int value,
+		    unsigned int index,
+		    unsigned char *xfer_data,
+		    unsigned int xfer_len) {
 
 	int result;
 
-	// If data is going to be sent or received with the URB,
-	// then allocate a buffer for it. If data is to be sent,
-	// copy the data into the buffer.
-/*
-	if (xfer_len > 0) {
-		buffer = kmalloc(xfer_len, GFP_NOIO);
-		if (!(command[0] & USB_DIR_IN))
-			memcpy(buffer, xfer_data, xfer_len);
-	}
-*/
 	// Send the URB to the device and wait for a response.
 
 	/* Why are request and request type reversed in this call? */
@@ -93,16 +252,6 @@
 			xfer_data, xfer_len);
 
 
-	// If data was sent or received with the URB, free the buffer we
-	// allocated earlier, but not before reading the data out of the
-	// buffer if we wanted to receive data.
-/*
-	if (xfer_len > 0) {
-		if (command[0] & USB_DIR_IN)
-			memcpy(xfer_data, buffer, xfer_len);
-		kfree(buffer);
-	}
-*/
 	// Check the return code for the command.
 
 	if (result < 0) {
@@ -118,17 +267,44 @@
 			return USB_STOR_TRANSPORT_FAILED;
 		}
 
-		/* Uh oh... serious problem here */
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
 	return USB_STOR_TRANSPORT_GOOD;
 }
 
-static int sddr09_raw_bulk(struct us_data *us, 
-		int direction,
-		unsigned char *data,
-		unsigned int len) {
+/* send vendor interface command (0x41) */
+/* called for requests 0, 1, 8 */
+static int
+sddr09_send_command(struct us_data *us,
+		    unsigned char request,
+		    unsigned char direction,
+		    unsigned char *xfer_data,
+		    unsigned int xfer_len) {
+	int pipe;
+	unsigned char requesttype = (0x41 | direction);
+
+	// Get the receive or send control pipe number
+
+	if (direction == USB_DIR_IN)
+		pipe = usb_rcvctrlpipe(us->pusb_dev,0);
+	else
+		pipe = usb_sndctrlpipe(us->pusb_dev,0);
+
+	return sddr09_send_control(us, pipe, request, requesttype,
+				   0, 0, xfer_data, xfer_len);
+}
+
+static int
+sddr09_send_scsi_command(struct us_data *us,
+			 unsigned char *command,
+			 unsigned int command_len) {
+	return sddr09_send_command(us, 0, USB_DIR_OUT, command, command_len);
+}
+
+static int
+sddr09_raw_bulk(struct us_data *us, int direction,
+		unsigned char *data, unsigned int len) {
 
 	int result;
 	int act_len;
@@ -141,61 +317,46 @@
 
 	result = usb_stor_bulk_msg(us, data, pipe, len, &act_len);
 
-        /* if we stall, we need to clear it before we go on */
-        if (result == -EPIPE) {
-       	        US_DEBUGP("EPIPE: clearing endpoint halt for"
-			" pipe 0x%x, stalled at %d bytes\n",
-			pipe, act_len);
-               	usb_clear_halt(us->pusb_dev, pipe);
-        }
+	/* if we stall, we need to clear it before we go on */
+	if (result == -EPIPE) {
+		US_DEBUGP("EPIPE: clearing endpoint halt for"
+			  " pipe 0x%x, stalled at %d bytes\n",
+			  pipe, act_len);
+		usb_clear_halt(us->pusb_dev, pipe);
+	}
 
 	if (result) {
-
-                /* NAK - that means we've retried a few times already */
-       	        if (result == -ETIMEDOUT) {
-                        US_DEBUGP("usbat_raw_bulk():"
-				" device NAKed\n");
-                        return US_BULK_TRANSFER_FAILED;
-                }
-
-                /* -ENOENT -- we canceled this transfer */
-                if (result == -ENOENT) {
-                        US_DEBUGP("usbat_raw_bulk():"
-				" transfer aborted\n");
-                        return US_BULK_TRANSFER_ABORTED;
-                }
-
-		if (result == -EPIPE) {
-			US_DEBUGP("usbat_raw_bulk():"
-				" output pipe stalled\n");
-			return USB_STOR_TRANSPORT_FAILED;
+		/* -ENOENT -- we canceled this transfer */
+		if (result == -ENOENT) {
+			US_DEBUGP("usbat_raw_bulk(): transfer aborted\n");
+			return US_BULK_TRANSFER_ABORTED;
 		}
 
-                /* the catch-all case */
-                US_DEBUGP("us_transfer_partial(): unknown error\n");
-                return US_BULK_TRANSFER_FAILED;
-        }
+		/* NAK - that means we've retried a few times already */
+       		if (result == -ETIMEDOUT)
+			US_DEBUGP("usbat_raw_bulk(): device NAKed\n");
+		else if (result == -EOVERFLOW)
+			US_DEBUGP("us_transfer_partial(): babble/overflow\n");
+		else if (result != -EPIPE)
+			US_DEBUGP("us_transfer_partial(): unknown error %d\n",
+				  result);
+
+		return US_BULK_TRANSFER_FAILED;
+	}
 
 	if (act_len != len) {
-		US_DEBUGP("Warning: Transferred only %d bytes\n",
-			act_len);
+		US_DEBUGP("Warning: Transferred only %d of %d bytes\n",
+			  act_len, len);
 		return US_BULK_TRANSFER_SHORT;
 	}
 
-	US_DEBUGP("Transferred %d of %d bytes\n", act_len, len);
-
 	return US_BULK_TRANSFER_GOOD;
 }
 
-/*
- * Note: direction must be set if command_len == 0.
- */
-
-static int sddr09_bulk_transport(struct us_data *us,
-			  int direction,
-			  unsigned char *data,
-			  unsigned int len,
-			  int use_sg) {
+static int
+sddr09_bulk_transport(struct us_data *us, int direction,
+		      unsigned char *data, unsigned int len,
+		      int use_sg) {
 
 	int result = USB_STOR_TRANSPORT_GOOD;
 	int transferred = 0;
@@ -203,94 +364,473 @@
 	struct scatterlist *sg;
 	char string[64];
 
-	if (len==0)
-		return USB_STOR_TRANSPORT_GOOD;
-
+#define DEBUG_PRCT 12
 
-	/* transfer the data */
+	if (len == 0)
+		return USB_STOR_TRANSPORT_GOOD;
 
-	if (direction == SCSI_DATA_WRITE) {
+	if (direction == SCSI_DATA_WRITE && !use_sg) {
 
-		/* Debug-print the first 48 bytes of the write transfer */
+		/* Debug-print the first N bytes of the write transfer */
 
-		if (!use_sg) {
-			strcpy(string, "wr: ");
-			for (i=0; i<len && i<48; i++) {
-				sprintf(string+strlen(string), "%02X ",
-				  data[i]);
-				if ((i%16)==15) {
-					US_DEBUGP("%s\n", string);
-					strcpy(string, "wr: ");
-				}
-			}
-			if ((i%16)!=0)
+		strcpy(string, "wr: ");
+		for (i=0; i<len && i<DEBUG_PRCT; i++) {
+			sprintf(string+strlen(string), "%02X ",
+				data[i]);
+			if ((i%16) == 15) {
 				US_DEBUGP("%s\n", string);
+				strcpy(string, "wr: ");
+			}
 		}
+		if ((i%16)!=0)
+			US_DEBUGP("%s\n", string);
 	}
 
-
 	US_DEBUGP("SCM data %s transfer %d sg buffers %d\n",
-		  ( direction==SCSI_DATA_READ ? "in" : "out"),
+		  (direction == SCSI_DATA_READ) ? "in" : "out",
 		  len, use_sg);
 
 	if (!use_sg)
 		result = sddr09_raw_bulk(us, direction, data, len);
 	else {
 		sg = (struct scatterlist *)data;
+
 		for (i=0; i<use_sg && transferred<len; i++) {
-			result = sddr09_raw_bulk(us, direction,
-				page_address(sg[i].page) + sg[i].offset, 
-				len-transferred > sg[i].length ?
-					sg[i].length : len-transferred);
-			if (result!=US_BULK_TRANSFER_GOOD)
+			unsigned char *buf;
+			unsigned int length;
+
+			buf = page_address(sg[i].page) + sg[i].offset;
+			length = len-transferred;
+			if (length > sg[i].length)
+				length = sg[i].length;
+
+			result = sddr09_raw_bulk(us, direction, buf, length);
+			if (result != US_BULK_TRANSFER_GOOD)
 				break;
 			transferred += sg[i].length;
 		}
 	}
 
-	if (direction == SCSI_DATA_READ) {
+	if (direction == SCSI_DATA_READ && !use_sg) {
 
-		/* Debug-print the first 48 bytes of the read transfer */
+		/* Debug-print the first N bytes of the read transfer */
 
-		if (!use_sg) {
-			strcpy(string, "rd: ");
-			for (i=0; i<len && i<48; i++) {
-				sprintf(string+strlen(string), "%02X ",
-				  data[i]);
-				if ((i%16)==15) {
-					US_DEBUGP("%s\n", string);
-					strcpy(string, "rd: ");
-				}
-			}
-			if ((i%16)!=0)
+		strcpy(string, "rd: ");
+		for (i=0; i<len && i<DEBUG_PRCT; i++) {
+			sprintf(string+strlen(string), "%02X ",
+				data[i]);
+			if ((i%16) == 15) {
 				US_DEBUGP("%s\n", string);
+				strcpy(string, "rd: ");
+			}
 		}
+		if ((i%16)!=0)
+			US_DEBUGP("%s\n", string);
 	}
 
 	return result;
 }
 
-int sddr09_read_data(struct us_data *us,
-		unsigned long address,
-		unsigned short sectors,
-		unsigned char *content,
-		int use_sg) {
+#if 0
+/*
+ * Test Unit Ready Command: 12 bytes.
+ * byte 0: opcode: 00
+ */
+static int
+sddr09_test_unit_ready(struct us_data *us) {
+	unsigned char command[6] = {
+		0, LUNBITS, 0, 0, 0, 0
+	};
+	int result;
+
+	result = sddr09_send_scsi_command(us, command, sizeof(command));
 
+	US_DEBUGP("sddr09_test_unit_ready returns %d\n", result);
+
+	return result;
+}
+#endif
+
+/*
+ * Request Sense Command: 12 bytes.
+ * byte 0: opcode: 03
+ * byte 4: data length
+ */
+static int
+sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) {
+	unsigned char command[12] = {
+		0x03, LUNBITS, 0, 0, buflen, 0, 0, 0, 0, 0, 0, 0
+	};
 	int result;
+
+	result = sddr09_send_scsi_command(us, command, sizeof(command));
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("request sense failed\n");
+		return result;
+	}
+
+	result = sddr09_raw_bulk(us, SCSI_DATA_READ, sensebuf, buflen);
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		US_DEBUGP("request sense bulk in failed\n");
+	else
+		US_DEBUGP("request sense worked\n");
+
+	return result;
+}
+
+/*
+ * Read Command: 12 bytes.
+ * byte 0: opcode: E8
+ * byte 1: last two bits: 00: read data, 01: read blockwise control,
+ *			10: read both, 11: read pagewise control.
+ *	 It turns out we need values 20, 21, 22, 23 here (LUN 1).
+ * bytes 2-5: address (interpretation depends on byte 1, see below)
+ * bytes 10-11: count (idem)
+ *
+ * A page has 512 data bytes and 64 control bytes (16 control and 48 junk).
+ * A read data command gets data in 512-byte pages.
+ * A read control command gets control in 64-byte chunks.
+ * A read both command gets data+control in 576-byte chunks.
+ *
+ * Blocks are groups of 32 pages, and read blockwise control jumps to the
+ * next block, while read pagewise control jumps to the next page after
+ * reading a group of 64 control bytes.
+ * [Here 512 = 1<<pageshift, 32 = 1<<blockshift, 64 is constant?]
+ *
+ * (1 MB and 2 MB cards are a bit different, but I have only a 16 MB card.)
+ */
+
+static int
+sddr09_readX(struct us_data *us, int x, unsigned long fromaddress,
+	     int nr_of_pages, int bulklen, unsigned char *buf,
+	     int use_sg) {
+
+	unsigned char command[12] = {
+		0xe8, LUNBITS | x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	int result;
+
+	command[2] = MSB_of(fromaddress>>16);
+	command[3] = LSB_of(fromaddress>>16); 
+	command[4] = MSB_of(fromaddress & 0xFFFF);
+	command[5] = LSB_of(fromaddress & 0xFFFF); 
+
+	command[10] = MSB_of(nr_of_pages);
+	command[11] = LSB_of(nr_of_pages);
+
+	result = sddr09_send_scsi_command(us, command, sizeof(command));
+
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("Result for send_control in sddr09_read2%d %d\n",
+			  x, result);
+		return result;
+	}
+
+	result = sddr09_bulk_transport(us, SCSI_DATA_READ,
+				       buf, bulklen, use_sg);
+
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		US_DEBUGP("Result for bulk_transport in sddr09_read2%d %d\n",
+			  x, result);
+
+	return result;
+}
+
+/*
+ * Read Data
+ *
+ * fromaddress counts data shorts:
+ * increasing it by 256 shifts the bytestream by 512 bytes;
+ * the last 8 bits are ignored.
+ *
+ * nr_of_pages counts pages of size (1 << pageshift).
+ */
+static int
+sddr09_read20(struct us_data *us, unsigned long fromaddress,
+	      int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) {
+	int bulklen = nr_of_pages << pageshift;
+
+	/* The last 8 bits of fromaddress are ignored. */
+	return sddr09_readX(us, 0, fromaddress, nr_of_pages, bulklen,
+			    buf, use_sg);
+}
+
+/*
+ * Read Blockwise Control
+ *
+ * fromaddress gives the starting position (as in read data;
+ * the last 8 bits are ignored); increasing it by 32*256 shifts
+ * the output stream by 64 bytes.
+ *
+ * count counts control groups of size (1 << controlshift).
+ * For me, controlshift = 6. Is this constant?
+ *
+ * After getting one control group, jump to the next block
+ * (fromaddress += 8192).
+ */
+static int
+sddr09_read21(struct us_data *us, unsigned long fromaddress,
+	      int count, int controlshift, unsigned char *buf, int use_sg) {
+
+	int bulklen = (count << controlshift);
+	return sddr09_readX(us, 1, fromaddress, count, bulklen,
+			    buf, use_sg);
+}
+
+/*
+ * Read both Data and Control
+ *
+ * fromaddress counts data shorts, ignoring control:
+ * increasing it by 256 shifts the bytestream by 576 = 512+64 bytes;
+ * the last 8 bits are ignored.
+ *
+ * nr_of_pages counts pages of size (1 << pageshift) + (1 << controlshift).
+ */
+static int
+sddr09_read22(struct us_data *us, unsigned long fromaddress,
+	      int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) {
+
+	int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT);
+	US_DEBUGP("sddr09_read22: reading %d pages, %d bytes\n",
+		  nr_of_pages, bulklen);
+	return sddr09_readX(us, 2, fromaddress, nr_of_pages, bulklen,
+			    buf, use_sg);
+}
+
+#if 0
+/*
+ * Read Pagewise Control
+ *
+ * fromaddress gives the starting position (as in read data;
+ * the last 8 bits are ignored); increasing it by 256 shifts
+ * the output stream by 64 bytes.
+ *
+ * count counts control groups of size (1 << controlshift).
+ * For me, controlshift = 6. Is this constant?
+ *
+ * After getting one control group, jump to the next page
+ * (fromaddress += 256).
+ */
+static int
+sddr09_read23(struct us_data *us, unsigned long fromaddress,
+	      int count, int controlshift, unsigned char *buf, int use_sg) {
+
+	int bulklen = (count << controlshift);
+	return sddr09_readX(us, 3, fromaddress, count, bulklen,
+			    buf, use_sg);
+}
+#endif
+
+/*
+ * Erase Command: 12 bytes.
+ * byte 0: opcode: EA
+ * bytes 6-9: erase address (big-endian, counting shorts, sector aligned).
+ * 
+ * Always precisely one block is erased; bytes 2-5 and 10-11 are ignored.
+ * The byte address being erased is 2*Eaddress.
+ */
+static int
+sddr09_erase(struct us_data *us, unsigned long Eaddress) {
+	unsigned char command[12] = {
+		0xea, LUNBITS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	int result;
+
+	command[6] = MSB_of(Eaddress>>16);
+	command[7] = LSB_of(Eaddress>>16);
+	command[8] = MSB_of(Eaddress & 0xFFFF);
+	command[9] = LSB_of(Eaddress & 0xFFFF);
+
+	result = sddr09_send_scsi_command(us, command, sizeof(command));
+
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		US_DEBUGP("Result for send_control in sddr09_erase %d\n",
+			  result);
+
+	return result;
+}
+
+/*
+ * Write Command: 12 bytes.
+ * byte 0: opcode: E9
+ * bytes 2-5: write address (big-endian, counting shorts, sector aligned).
+ * bytes 6-9: erase address (big-endian, counting shorts, sector aligned).
+ * bytes 10-11: sector count (big-endian, in 512-byte sectors).
+ *
+ * If write address equals erase address, the erase is done first,
+ * otherwise the write is done first. When erase address equals zero
+ * no erase is done?
+ */
+static int
+sddr09_writeX(struct us_data *us,
+	      unsigned long Waddress, unsigned long Eaddress,
+	      int nr_of_pages, int bulklen, unsigned char *buf, int use_sg) {
+
 	unsigned char command[12] = {
-		0xe8, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+		0xe9, LUNBITS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 	};
-	struct sddr09_card_info *info = (struct sddr09_card_info *)us->extra;
-	unsigned int lba;
-	unsigned int pba;
-	unsigned short page;
-	unsigned short pages;
+	int result;
+
+	command[2] = MSB_of(Waddress>>16);
+	command[3] = LSB_of(Waddress>>16);
+	command[4] = MSB_of(Waddress & 0xFFFF);
+	command[5] = LSB_of(Waddress & 0xFFFF);
+
+	command[6] = MSB_of(Eaddress>>16);
+	command[7] = LSB_of(Eaddress>>16);
+	command[8] = MSB_of(Eaddress & 0xFFFF);
+	command[9] = LSB_of(Eaddress & 0xFFFF);
+
+	command[10] = MSB_of(nr_of_pages);
+	command[11] = LSB_of(nr_of_pages);
+
+	result = sddr09_send_scsi_command(us, command, sizeof(command));
+
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("Result for send_control in sddr09_writeX %d\n",
+			  result);
+		return result;
+	}
+
+	result = sddr09_bulk_transport(us, SCSI_DATA_WRITE,
+				       buf, bulklen, use_sg);
+
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		US_DEBUGP("Result for bulk_transport in sddr09_writeX %d\n",
+			  result);
+
+	return result;
+}
+
+/* erase address, write same address */
+static int
+sddr09_write_inplace(struct us_data *us, unsigned long address,
+		     int nr_of_pages, int pageshift, unsigned char *buf,
+		     int use_sg) {
+	int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT);
+	return sddr09_writeX(us, address, address, nr_of_pages, bulklen,
+			     buf, use_sg);
+}
+
+#if 0
+/*
+ * Read Scatter Gather Command: 3+4n bytes.
+ * byte 0: opcode E7
+ * byte 2: n
+ * bytes 4i-1,4i,4i+1: page address
+ * byte 4i+2: page count
+ * (i=1..n)
+ *
+ * This reads several pages from the card to a single memory buffer.
+ * The last two bits of byte 1 have the same meaning as for E8.
+ */
+static int
+sddr09_read_sg_test_only(struct us_data *us) {
+	unsigned char command[15] = {
+		0xe7, LUNBITS, 0
+	};
+	int result, bulklen, nsg, ct;
+	unsigned char *buf;
+	unsigned long address;
+
+	nsg = bulklen = 0;
+
+	address = 040000; ct = 1;
+	nsg++;
+	bulklen += (ct << 9);
+	command[4*nsg+2] = ct;
+	command[4*nsg+1] = ((address >> 9) & 0xFF);
+	command[4*nsg+0] = ((address >> 17) & 0xFF);
+	command[4*nsg-1] = ((address >> 25) & 0xFF);
+
+	address = 0340000; ct = 1;
+	nsg++;
+	bulklen += (ct << 9);
+	command[4*nsg+2] = ct;
+	command[4*nsg+1] = ((address >> 9) & 0xFF);
+	command[4*nsg+0] = ((address >> 17) & 0xFF);
+	command[4*nsg-1] = ((address >> 25) & 0xFF);
+
+	address = 01000000; ct = 2;
+	nsg++;
+	bulklen += (ct << 9);
+	command[4*nsg+2] = ct;
+	command[4*nsg+1] = ((address >> 9) & 0xFF);
+	command[4*nsg+0] = ((address >> 17) & 0xFF);
+	command[4*nsg-1] = ((address >> 25) & 0xFF);
+
+	command[2] = nsg;
+
+	result = sddr09_send_scsi_command(us, command, 4*nsg+3);
+
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("Result for send_control in sddr09_read_sg %d\n",
+			  result);
+		return result;
+	}
+
+	buf = (unsigned char *) kmalloc(bulklen, GFP_NOIO);
+	if (!buf)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	result = sddr09_bulk_transport(us, SCSI_DATA_READ,
+				       buf, bulklen, 0);
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		US_DEBUGP("Result for bulk_transport in sddr09_read_sg %d\n",
+			  result);
+
+	kfree(buf);
+
+	return result;
+}
+#endif
+
+/*
+ * Read Status Command: 12 bytes.
+ * byte 0: opcode: EC
+ *
+ * Returns 64 bytes, all zero except for the first.
+ * bit 0: 1: Error
+ * bit 5: 1: Suspended
+ * bit 6: 1: Ready
+ * bit 7: 1: Not write-protected
+ */
+
+static int
+sddr09_read_status(struct us_data *us, unsigned char *status) {
+
+	unsigned char command[12] = {
+		0xec, LUNBITS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	unsigned char data[64];
+	int result;
+
+	US_DEBUGP("Reading status...\n");
+
+	result = sddr09_send_scsi_command(us, command, sizeof(command));
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		return result;
+
+	result = sddr09_bulk_transport(us, SCSI_DATA_READ,
+				       data, sizeof(data), 0);
+	*status = data[0];
+	return result;
+}
+
+static int
+sddr09_read_data(struct us_data *us,
+		 unsigned long address,
+		 unsigned int sectors,
+		 unsigned char *content,
+		 int use_sg) {
+
+	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+	unsigned int lba, maxlba, pba;
+	unsigned int page, pages;
 	unsigned char *buffer = NULL;
 	unsigned char *ptr;
 	struct scatterlist *sg = NULL;
-	int i;
-	int len;
-	int transferred;
+	int result, i, len;
 
 	// If we're using scatter-gather, we have to create a new
 	// buffer to read all of the data in first, since a
@@ -311,68 +851,57 @@
 		ptr = content;
 
 	// Figure out the initial LBA and page
-
-	pba = address >> (info->pageshift + info->blockshift);
-	lba = info->pba_to_lba[pba];
-	page = (address >> info->pageshift) & info->blockmask;
+	lba = address >> info->blockshift;
+	page = (address & info->blockmask);
+	maxlba = info->capacity >> (info->pageshift + info->blockshift);
 
 	// This could be made much more efficient by checking for
 	// contiguous LBA's. Another exercise left to the student.
 
-	while (sectors>0) {
-
-		pba = info->lba_to_pba[lba];
+	result = USB_STOR_TRANSPORT_GOOD;
 
-		// Read as many sectors as possible in this block
+	while (sectors > 0) {
 
+		/* Find number of pages we can read in this block */
 		pages = info->blocksize - page;
 		if (pages > sectors)
 			pages = sectors;
 
-		US_DEBUGP("Read %02X pages, from PBA %04X"
-			" (LBA %04X) page %02X\n",
-			pages, pba, lba, page);
-
-		address = ( (pba << info->blockshift) + page ) << 
-			info->pageshift;
-
-		// Unlike in the documentation, the address is in
-		// words of 2 bytes.
-
-		command[2] = MSB_of(address>>17);
-		command[3] = LSB_of(address>>17); 
-		command[4] = MSB_of((address>>1)&0xFFFF);
-		command[5] = LSB_of((address>>1)&0xFFFF); 
-
-		command[10] = MSB_of(pages);
-		command[11] = LSB_of(pages);
-
-		result = sddr09_send_control(us,
-			usb_sndctrlpipe(us->pusb_dev,0),
-			0,
-			0x41,
-			0,
-			0,
-			command,
-			12);
-
-		US_DEBUGP("Result for send_control in read_data %d\n",
-			result);
-
-		if (result != USB_STOR_TRANSPORT_GOOD) {
-			if (use_sg)
-				kfree(buffer);
-			return result;
+		/* Not overflowing capacity? */
+		if (lba >= maxlba) {
+			US_DEBUGP("Error: Requested lba %u exceeds "
+				  "maximum %u\n", lba, maxlba);
+			result = USB_STOR_TRANSPORT_ERROR;
+			break;
 		}
 
-		result = sddr09_bulk_transport(us,
-			SCSI_DATA_READ, ptr,
-			pages<<info->pageshift, 0);
+		/* Find where this lba lives on disk */
+		pba = info->lba_to_pba[lba];
+
+		if (pba == UNDEF) {	/* this lba was never written */
+
+			US_DEBUGP("Read %d zero pages (LBA %d) page %d\n",
+				  pages, lba, page);
+
+			/* This is not really an error. It just means
+			   that the block has never been written.
+			   Instead of returning USB_STOR_TRANSPORT_ERROR
+			   it is better to return all zero data. */
+
+			memset(ptr, 0, pages << info->pageshift);
 
-		if (result != USB_STOR_TRANSPORT_GOOD) {
-			if (use_sg)
-				kfree(buffer);
-			return result;
+		} else {
+			US_DEBUGP("Read %d pages, from PBA %d"
+				  " (LBA %d) page %d\n",
+				  pages, pba, lba, page);
+
+			address = ((pba << info->blockshift) + page) << 
+				info->pageshift;
+
+			result = sddr09_read20(us, address>>1,
+					       pages, info->pageshift, ptr, 0);
+			if (result != USB_STOR_TRANSPORT_GOOD)
+				break;
 		}
 
 		page = 0;
@@ -381,234 +910,395 @@
 		ptr += (pages << info->pageshift);
 	}
 
-	if (use_sg) {
-		transferred = 0;
+	if (use_sg && result == USB_STOR_TRANSPORT_GOOD) {
+		int transferred = 0;
+
 		for (i=0; i<use_sg && transferred<len; i++) {
-			memcpy(page_address(sg[i].page) + sg[i].offset, buffer+transferred,
-				len-transferred > sg[i].length ?
-					sg[i].length : len-transferred);
+			unsigned char *buf;
+			unsigned int length;
+
+			buf = page_address(sg[i].page) + sg[i].offset;
+
+			length = len-transferred;
+			if (length > sg[i].length)
+				length = sg[i].length;
+
+			memcpy(buf, buffer+transferred, length);
 			transferred += sg[i].length;
 		}
-		kfree(buffer);
 	}
 
-	return USB_STOR_TRANSPORT_GOOD;
-}
+	if (use_sg)
+		kfree(buffer);
 
-int sddr09_read_control(struct us_data *us,
-		unsigned long address,
-		unsigned short blocks,
-		unsigned char *content,
-		int use_sg) {
+	return result;
+}
 
-	// Unlike in the documentation, the last two bytes are the
-	// number of blocks, not sectors.
+/* we never free blocks, so lastpba can only increase */
+static unsigned int
+sddr09_find_unused_pba(struct sddr09_card_info *info) {
+	static unsigned int lastpba = 1;
+	int numblocks = info->capacity >> (info->blockshift + info->pageshift);
+	int i;
 
-	int result;
-	unsigned char command[12] = {
-		0xe8, 0x21, MSB_of(address>>16),
-		LSB_of(address>>16), MSB_of(address&0xFFFF),
-		LSB_of(address&0xFFFF), 0, 0, 0, 0,
-		MSB_of(blocks), LSB_of(blocks)
-	};
+	for (i = lastpba+1; i < numblocks; i++) {
+		if (info->pba_to_lba[i] == UNDEF) {
+			lastpba = i;
+			return i;
+		}
+	}
+	return 0;
+}
 
-	US_DEBUGP("Read control address %08lX blocks %04X\n",
-		address, blocks);
+static int
+sddr09_write_lba(struct us_data *us, unsigned int lba,
+		 unsigned int page, unsigned int pages,
+		 unsigned char *ptr) {
+
+	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+	unsigned long address;
+	unsigned int pba, lbap;
+	unsigned int pagelen, blocklen;
+	unsigned char *blockbuffer, *bptr, *cptr, *xptr;
+	unsigned char ecc[3];
+	int i, result;
+
+	lbap = ((lba & 0x3ff) << 1) | 0x1000;
+	if (parity[MSB_of(lbap) ^ LSB_of(lbap)])
+		lbap ^= 1;
+	pba = info->lba_to_pba[lba];
+
+	if (pba == UNDEF) {
+		pba = sddr09_find_unused_pba(info);
+		if (!pba) {
+			printk("sddr09_write_lba: Out of unused blocks\n");
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+		info->pba_to_lba[pba] = lba;
+		info->lba_to_pba[lba] = pba;
+	}
 
-	result = sddr09_send_control(us,
-		usb_sndctrlpipe(us->pusb_dev,0),
-		0,
-		0x41,
-		0,
-		0,
-		command,
-		12);
+	if (pba == 1) {
+		/* Maybe it is impossible to write to PBA 1.
+		   Fake success, but don't do anything. */
+		printk("sddr09: avoid writing to pba 1\n");
+		return USB_STOR_TRANSPORT_GOOD;
+	}
 
-	US_DEBUGP("Result for send_control in read_control %d\n",
-		result);
+	pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
+	blocklen = (pagelen << info->blockshift);
+	blockbuffer = kmalloc(blocklen, GFP_NOIO);
+	if (!blockbuffer) {
+		printk("sddr09_write_lba: Out of memory\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
 
+	/* read old contents */
+	address = (pba << (info->pageshift + info->blockshift));
+	result = sddr09_read22(us, address>>1, info->blocksize,
+			       info->pageshift, blockbuffer, 0);
 	if (result != USB_STOR_TRANSPORT_GOOD)
-		return result;
+		goto err;
 
-	result = sddr09_bulk_transport(us,
-		SCSI_DATA_READ, content,
-		blocks<<6, use_sg); // 0x40 bytes per block
+	/* check old contents */
+	for (i = 0; i < info->blockshift; i++) {
+		bptr = blockbuffer + i*pagelen;
+		cptr = bptr + info->pagesize;
+		nand_compute_ecc(bptr, ecc);
+		if (!nand_compare_ecc(cptr+13, ecc)) {
+			US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n",
+				  i, pba);
+			nand_store_ecc(cptr+13, ecc);
+		}
+		nand_compute_ecc(bptr+(info->pagesize / 2), ecc);
+		if (!nand_compare_ecc(cptr+8, ecc)) {
+			US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n",
+				  i, pba);
+			nand_store_ecc(cptr+8, ecc);
+		}
+	}
 
-	US_DEBUGP("Result for bulk read in read_control %d\n",
-		result);
+	/* copy in new stuff and compute ECC */
+	xptr = ptr;
+	for (i = page; i < page+pages; i++) {
+		bptr = blockbuffer + i*pagelen;
+		cptr = bptr + info->pagesize;
+		memcpy(bptr, xptr, info->pagesize);
+		xptr += info->pagesize;
+		nand_compute_ecc(bptr, ecc);
+		nand_store_ecc(cptr+13, ecc);
+		nand_compute_ecc(bptr+(info->pagesize / 2), ecc);
+		nand_store_ecc(cptr+8, ecc);
+		cptr[6] = cptr[11] = MSB_of(lbap);
+		cptr[7] = cptr[12] = LSB_of(lbap);
+	}
+
+	US_DEBUGP("Rewrite PBA %d (LBA %d)\n", pba, lba);
+
+	result = sddr09_write_inplace(us, address>>1, info->blocksize,
+				      info->pageshift, blockbuffer, 0);
+
+	US_DEBUGP("sddr09_write_inplace returns %d\n", result);
+
+#if 0
+	{
+		unsigned char status = 0;
+		int result2 = sddr09_read_status(us, &status);
+		if (result2 != USB_STOR_TRANSPORT_GOOD)
+			US_DEBUGP("sddr09_write_inplace: cannot read status\n");
+		else if (status != 0xc0)
+			US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n",
+				  status);
+	}
+#endif
+
+#if 0
+	{
+		int result2 = sddr09_test_unit_ready(us);
+	}
+#endif
+ err:
+	kfree(blockbuffer);
+
+	/* TODO: instead of doing kmalloc/kfree for each block,
+	   add a bufferpointer to the info structure */
 
 	return result;
 }
 
-int sddr09_read_deviceID(struct us_data *us,
-		unsigned char *manufacturerID,
-		unsigned char *deviceID) {
+static int
+sddr09_write_data(struct us_data *us,
+		  unsigned long address,
+		  unsigned int sectors,
+		  unsigned char *content,
+		  int use_sg) {
 
-	int result;
-	unsigned char command[12] = {
-		0xed, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-	};
-	unsigned char content[64];
+	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+	unsigned int lba, page, pages;
+	unsigned char *buffer = NULL;
+	unsigned char *ptr;
+	struct scatterlist *sg = NULL;
+	int result, i, len;
 
-	result = sddr09_send_control(us,
-		usb_sndctrlpipe(us->pusb_dev,0),
-		0,
-		0x41,
-		0,
-		0,
-		command,
-		12);
+	// If we're using scatter-gather, we have to create a new
+	// buffer to write all of the data in first, since a
+	// scatter-gather buffer could in theory start in the middle
+	// of a page, which would be bad. A developer who wants a
+	// challenge might want to write a limited-buffer
+	// version of this code.
 
-	US_DEBUGP("Result of send_control for device ID is %d\n",
-		result);
+	len = sectors*info->pagesize;
 
-	if (result != USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (use_sg) {
+		int transferred = 0;
 
-	result = sddr09_bulk_transport(us,
-		SCSI_DATA_READ, content,
-		64, 0);
+		sg = (struct scatterlist *)content;
+		buffer = kmalloc(len, GFP_NOIO);
+		if (buffer == NULL)
+			return USB_STOR_TRANSPORT_ERROR;
 
-	*manufacturerID = content[0];
-	*deviceID = content[1];
+		for (i=0; i<use_sg && transferred<len; i++) {
+			unsigned char *buf;
+			unsigned int length;
+
+			buf = page_address(sg[i].page) + sg[i].offset;
+
+			length = len-transferred;
+			if (length > sg[i].length)
+				length = sg[i].length;
+
+			memcpy(buffer+transferred, buf, length);
+			transferred += sg[i].length;
+		}
+		ptr = buffer;
+	} else
+		ptr = content;
+
+	// Figure out the initial LBA and page
+	lba = address >> info->blockshift;
+	page = (address & info->blockmask);
+
+	// This could be made much more efficient by checking for
+	// contiguous LBA's. Another exercise left to the student.
+
+	result = USB_STOR_TRANSPORT_GOOD;
+
+	while (sectors > 0) {
+
+		// Write as many sectors as possible in this block
+
+		pages = info->blocksize - page;
+		if (pages > sectors)
+			pages = sectors;
+
+		result = sddr09_write_lba(us, lba, page, pages, ptr);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			break;
+
+		page = 0;
+		lba++;
+		sectors -= pages;
+		ptr += (pages << info->pageshift);
+	}
+
+	if (use_sg)
+		kfree(buffer);
 
 	return result;
 }
 
-int sddr09_read_status(struct us_data *us,
-		unsigned char *status) {
+static int
+sddr09_read_control(struct us_data *us,
+		unsigned long address,
+		unsigned int blocks,
+		unsigned char *content,
+		int use_sg) {
 
-	int result;
+	US_DEBUGP("Read control address %08lX blocks %04X\n",
+		address, blocks);
+
+	return sddr09_read21(us, address, blocks, CONTROL_SHIFT, content, use_sg);
+}
+
+/*
+ * Read Device ID Command: 12 bytes.
+ * byte 0: opcode: ED
+ *
+ * Returns 2 bytes: Manufacturer ID and Device ID.
+ * On more recent cards 3 bytes: the third byte is an option code A5
+ * signifying that the secret command to read an 128-bit ID is available.
+ * On still more recent cards 4 bytes: the fourth byte C0 means that
+ * a second read ID cmd is available.
+ */
+static int
+sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) {
 	unsigned char command[12] = {
-		0xec, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+		0xed, LUNBITS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 	};
+	unsigned char content[64];
+	int result, i;
 
-	result = sddr09_send_control(us,
-		usb_sndctrlpipe(us->pusb_dev,0),
-		0,
-		0x41,
-		0,
-		0,
-		command,
-		12);
-
+	result = sddr09_send_scsi_command(us, command, sizeof(command));
 	if (result != USB_STOR_TRANSPORT_GOOD)
 		return result;
 
-	result = sddr09_bulk_transport(us,
-		SCSI_DATA_READ, status,
-		1, 0);
+	result = sddr09_bulk_transport(us, SCSI_DATA_READ, content, 64, 0);
+
+	for (i = 0; i < 4; i++)
+		deviceID[i] = content[i];
 
 	return result;
 }
 
-int sddr09_reset(struct us_data *us) {
-
+static int
+sddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) {
 	int result;
+	unsigned char status;
+
+	result = sddr09_read_status(us, &status);
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("sddr09_get_wp: read_status fails\n");
+		return result;
+	}
+	US_DEBUGP("sddr09_get_wp: status %02X", status);
+	if ((status & 0x80) == 0) {
+		info->flags |= SDDR09_WP;	/* write protected */
+		US_DEBUGP(" WP");
+	}
+	if (status & 0x40)
+		US_DEBUGP(" Ready");
+	if (status & LUNBITS)
+		US_DEBUGP(" Suspended");
+	if (status & 0x1)
+		US_DEBUGP(" Error");
+	US_DEBUGP("\n");
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+#if 0
+/*
+ * Reset Command: 12 bytes.
+ * byte 0: opcode: EB
+ */
+static int
+sddr09_reset(struct us_data *us) {
+
 	unsigned char command[12] = {
-		0xeb, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+		0xeb, LUNBITS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 	};
 
-	result = sddr09_send_control(us,
-		usb_sndctrlpipe(us->pusb_dev,0),
-		0,
-		0x41,
-		0,
-		0,
-		command,
-		12);
-
-	return result;
+	return sddr09_send_scsi_command(us, command, sizeof(command));
 }
+#endif
 
-unsigned long sddr09_get_capacity(struct us_data *us,
-		unsigned int *pagesize, unsigned int *blocksize) {
-
-	unsigned char manufacturerID;
-	unsigned char deviceID;
+static struct nand_flash_dev *
+sddr09_get_cardinfo(struct us_data *us, unsigned char flags) {
+	struct nand_flash_dev *cardinfo;
+	unsigned char deviceID[4];
+	char blurbtxt[256];
 	int result;
 
 	US_DEBUGP("Reading capacity...\n");
 
-	result = sddr09_read_deviceID(us,
-		&manufacturerID,
-		&deviceID);
-
-	US_DEBUGP("Result of read_deviceID is %d\n",
-		result);
+	result = sddr09_read_deviceID(us, deviceID);
 
-	if (result != USB_STOR_TRANSPORT_GOOD)
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("Result of read_deviceID is %d\n", result);
+		printk("sddr09: could not read card info\n");
 		return 0;
+	}
 
-	US_DEBUGP("Device ID = %02X\n", deviceID);
-	US_DEBUGP("Manuf  ID = %02X\n", manufacturerID);
-
-	*pagesize = 512;
-	*blocksize = 16;
-
-	switch (deviceID) {
+	sprintf(blurbtxt, "sddr09: Found Flash card, ID = %02X %02X %02X %02X",
+		deviceID[0], deviceID[1], deviceID[2], deviceID[3]);
 
-	case 0x6e: // 1MB
-	case 0xe8:
-	case 0xec:
-		*pagesize = 256;
-		return 0x00100000;
-
-	case 0xea: // 2MB
-	case 0x5d: // 5d is a ROM card with pagesize 512.
-	case 0x64:
-		if (deviceID!=0x5D)
-			*pagesize = 256;
-		return 0x00200000;
-
-	case 0xe3: // 4MB
-	case 0xe5:
-	case 0x6b:
-	case 0xd5:
-		return 0x00400000;
-
-	case 0xe6: // 8MB
-	case 0xd6:
-		return 0x00800000;
-
-	case 0x73: // 16MB
-		*blocksize = 32;
-		return 0x01000000;
-
-	case 0x75: // 32MB
-		*blocksize = 32;
-		return 0x02000000;
-
-	case 0x76: // 64MB
-		*blocksize = 32;
-		return 0x04000000;
-
-	case 0x79: // 128MB
-		*blocksize = 32;
-		return 0x08000000;
+	/* Byte 0 is the manufacturer */
+	sprintf(blurbtxt + strlen(blurbtxt),
+		": Manuf. %s",
+		nand_flash_manufacturer(deviceID[0]));
+
+	/* Byte 1 is the device type */
+	cardinfo = nand_find_id(deviceID[1]);
+	if (cardinfo) {
+		/* MB or MiB? It is neither. A 16 MB card has
+		   17301504 raw bytes, of which 16384000 are
+		   usable for user data. */
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", %d MB", 1<<(cardinfo->chipshift - 20));
+	} else {
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", type unrecognized");
+	}
+
+	/* Byte 2 is code to signal availability of 128-bit ID */
+	if (deviceID[2] == 0xa5) {
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", 128-bit ID");
+	}
+
+	/* Byte 3 announces the availability of another read ID command */
+	if (deviceID[3] == 0xc0) {
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", extra cmd");
+	}
+
+	if (flags & SDDR09_WP)
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", WP");
 
-	default: // unknown
-		return 0;
+	printk("%s\n", blurbtxt);
 
-	}
+	return cardinfo;
 }
 
-int sddr09_read_map(struct us_data *us) {
+static int
+sddr09_read_map(struct us_data *us) {
 
 	struct scatterlist *sg;
-	struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra);
-	int numblocks;
-	int i;
+	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+	int numblocks, alloc_len, alloc_blocks;
+	int i, j, result;
 	unsigned char *ptr;
-	unsigned short lba;
-	unsigned char parity;
-	unsigned char fast_parity[16] = {
-		0, 1, 1, 0, 1, 0, 0, 1,
-		1, 0, 0, 1, 0, 1, 1, 0
-	};
-	int result;
-	int alloc_len;
-	int alloc_blocks;
+	unsigned int lba, lbact;
 
 	if (!info->capacity)
 		return -1;
@@ -621,7 +1311,7 @@
 	// capacity>>(b+p-6)
 
 	alloc_len = info->capacity >> 
-		(info->blockshift + info->pageshift - 6);
+		(info->blockshift + info->pageshift - CONTROL_SHIFT);
 
 	// Allocate a number of scatterlist structures according to
 	// the number of 128k blocks in the alloc_len. Adding 128k-1
@@ -630,7 +1320,7 @@
 
 	alloc_blocks = (alloc_len + (1<<17) - 1) >> 17;
 	sg = kmalloc(alloc_blocks*sizeof(struct scatterlist),
-		GFP_NOIO);
+		     GFP_NOIO);
 	if (sg == NULL)
 		return 0;
 
@@ -660,29 +1350,23 @@
 
 	numblocks = info->capacity >> (info->blockshift + info->pageshift);
 
-	if ( (result = sddr09_read_control(us, 0, numblocks,
-			(unsigned char *)sg, alloc_blocks)) !=
-			USB_STOR_TRANSPORT_GOOD) {
+	result = sddr09_read_control(us, 0, numblocks,
+				     (unsigned char *)sg, alloc_blocks);
+	if (result != USB_STOR_TRANSPORT_GOOD) {
 		for (i=0; i<alloc_blocks; i++)
 			kfree(page_address(sg[i].page) + sg[i].offset);
 		kfree(sg);
 		return -1;
 	}
 
-
-
-	if (info->lba_to_pba)
-		kfree(info->lba_to_pba);
-	if (info->pba_to_lba)
-		kfree(info->pba_to_lba);
+	kfree(info->lba_to_pba);
+	kfree(info->pba_to_lba);
 	info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
 	info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
 
 	if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
-		if (info->lba_to_pba != NULL)
-			kfree(info->lba_to_pba);
-		if (info->pba_to_lba != NULL)
-			kfree(info->pba_to_lba);
+		kfree(info->lba_to_pba);
+		kfree(info->pba_to_lba);
 		info->lba_to_pba = NULL;
 		info->pba_to_lba = NULL;
 		for (i=0; i<alloc_blocks; i++)
@@ -691,64 +1375,137 @@
 		return 0;
 	}
 
-	memset(info->lba_to_pba, 0, numblocks*sizeof(int));
-	memset(info->pba_to_lba, 0, numblocks*sizeof(int));
+	for (i = 0; i < numblocks; i++)
+		info->lba_to_pba[i] = info->pba_to_lba[i] = UNDEF;
 
+	ptr = page_address(sg[0].page)+sg[0].offset;
+
+	/*
+	 * Define lba-pba translation table
+	 */
 	// Each block is 64 bytes of control data, so block i is located in
 	// scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11)
 
+#if 0
+	/* No translation */
+	for (i=0; i<numblocks; i++) {
+		lba = i;
+		info->pba_to_lba[i] = lba;
+		info->lba_to_pba[lba] = i;
+	}
+	printk("sddr09: no translation today\n");
+#else
 	for (i=0; i<numblocks; i++) {
-		ptr = page_address(sg[i>>11].page)+sg[i>>11].offset+((i&0x7ff)<<6);
-		if (ptr[0]!=0xFF || ptr[1]!=0xFF || ptr[2]!=0xFF ||
-		    ptr[3]!=0xFF || ptr[4]!=0xFF || ptr[5]!=0xFF) {
-			US_DEBUGP("PBA %04X has no logical mapping: reserved area = "
-			  "%02X%02X%02X%02X data status %02X block status %02X\n",
-			  i, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
+		ptr = page_address(sg[i>>11].page) +
+			sg[i>>11].offset + ((i&0x7ff)<<6);
+
+		if (i == 0 || i == 1) {
+			info->pba_to_lba[i] = UNUSABLE;
 			continue;
 		}
-		if ((ptr[6]>>4)!=0x01) {
-			US_DEBUGP("PBA %04X has invalid address field %02X%02X/%02X%02X\n",
-			  i, ptr[6], ptr[7], ptr[11], ptr[12]);
+
+		/* special PBAs have control field 0^16 */
+		for (j = 0; j < 16; j++)
+			if (ptr[j] != 0)
+				goto nonz;
+		info->pba_to_lba[i] = UNUSABLE;
+		printk("sddr09: PBA %04X has no logical mapping\n", i);
+		continue;
+
+	nonz:
+		/* unwritten PBAs have control field FF^16 */
+		for (j = 0; j < 16; j++)
+			if (ptr[j] != 0xff)
+				goto nonff;
+		continue;
+
+	nonff:
+		/* normal PBAs start with six FFs */
+		if (j < 6) {
+			printk("sddr09: PBA %04X has no logical mapping: "
+			       "reserved area = %02X%02X%02X%02X "
+			       "data status %02X block status %02X\n",
+			       i, ptr[0], ptr[1], ptr[2], ptr[3],
+			       ptr[4], ptr[5]);
+			info->pba_to_lba[i] = UNUSABLE;
 			continue;
 		}
 
-		/* ensure even parity */
-
-		lba = short_pack(ptr[7], ptr[6]);
-		parity = 1; // the parity of 0x1000
-		parity ^= fast_parity[lba & 0x000F];
-		parity ^= fast_parity[(lba>>4) & 0x000F];
-		parity ^= fast_parity[(lba>>8) & 0x000F];
-
-		if (parity) { /* bad parity bit */
-			US_DEBUGP("Bad parity in LBA for block %04X\n", i);
+		if ((ptr[6] >> 4) != 0x01) {
+			printk("sddr09: PBA %04X has invalid address field "
+			       "%02X%02X/%02X%02X\n",
+			       i, ptr[6], ptr[7], ptr[11], ptr[12]);
+			info->pba_to_lba[i] = UNUSABLE;
 			continue;
 		}
 
-		lba = (lba&0x07FF)>>1;
-
-			/* Every 1024 physical blocks ("zone"), the LBA numbers
-			 * go back to zero, but are within a higher
-			 * block of LBA's. Also, there is a maximum of
-			 * 1000 LBA's per zone. In other words, in PBA
-			 * 1024-2047 you will find LBA 0-999 which are
-			 * really LBA 1000-1999. Yes, this wastes 24
-			 * physical blocks per zone. Go figure.
-			 */
+		/* check even parity */
+		if (parity[ptr[6] ^ ptr[7]]) {
+			printk("sddr09: Bad parity in LBA for block %04X"
+			       " (%02X %02X)\n", i, ptr[6], ptr[7]);
+			info->pba_to_lba[i] = UNUSABLE;
+			continue;
+		}
 
-		lba += 1000*(i/0x400);
+		lba = short_pack(ptr[7], ptr[6]);
+		lba = (lba & 0x07FF) >> 1;
 
-		if (lba>=numblocks) {
-			US_DEBUGP("Bad LBA %04X for block %04X\n", lba, i);
+		/*
+		 * Every 1024 physical blocks ("zone"), the LBA numbers
+		 * go back to zero, but are within a higher block of LBA's.
+		 * Also, there is a maximum of 1000 LBA's per zone.
+		 * In other words, in PBA 1024-2047 you will find LBA 0-999
+		 * which are really LBA 1000-1999. This allows for 24 bad
+		 * or special physical blocks per zone.
+		 */
+
+		if (lba >= 1000) {
+			unsigned long address;
+
+			printk("sddr09: Bad LBA %04X for block %04X\n",
+			       lba, i);
+			info->pba_to_lba[i] = UNDEF /* UNUSABLE */;
+			if (erase_bad_lba_entries) {
+				/* some cameras cannot erase a card if it has
+				   bad entries, so we supply this function */
+				address = (i << (info->pageshift + info->blockshift));
+				sddr09_erase(us, address>>1);
+			}
 			continue;
 		}
 
-		if (lba<0x10 || (lba>=0x3E0 && lba<0x3EF))
+		lba += 1000*(i/0x400);
+
+		if (lba<0x10 || (lba >= 0x3E0 && lba < 0x3EF))
 			US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i);
 
 		info->pba_to_lba[i] = lba;
 		info->lba_to_pba[lba] = i;
 	}
+#endif
+
+	/*
+	 * Approximate capacity. This is not entirely correct yet,
+	 * since a zone with less than 1000 usable pages leads to
+	 * missing LBAs. Especially if it is the last zone, some
+	 * LBAs can be past capacity.
+	 */
+	lbact = 0;
+	for (i = 0; i < numblocks; i += 1024) {
+		int ct = 0;
+
+		for (j = 0; j < 1024 && i+j < numblocks; j++) {
+			if (info->pba_to_lba[i+j] != UNUSABLE) {
+				if (ct >= 1000)
+					info->pba_to_lba[i+j] = SPARE;
+				else
+					ct++;
+			}
+		}
+		lbact += ct;
+	}
+	info->lbact = lbact;
+	US_DEBUGP("Found %d LBA's\n", lbact);
 
 	for (i=0; i<alloc_blocks; i++)
 		kfree(page_address(sg[i].page)+sg[i].offset);
@@ -756,67 +1513,74 @@
 	return 0;
 }
 
-/*
-static int init_sddr09(struct us_data *us) {
-
-	int result;
-	unsigned char data[14];
-	unsigned char command[8] = {
-		0xc1, 0x01, 0, 0, 0, 0, 0, 0
-	};
-	unsigned char command2[8] = {
-		0x41, 0, 0, 0, 0, 0, 0, 0
-	};
-	unsigned char tur[12] = {
-		0x03, 0x20, 0, 0, 0x0e, 0, 0, 0, 0, 0, 0, 0
-	};
-
-	// What the hey is all this for? Doesn't seem to
-	// affect the device, so we won't do device inits.
-
-	if ( (result = sddr09_send_control(us, command, data, 2)) !=
-			USB_STOR_TRANSPORT_GOOD)
-		return result;
+static void
+sddr09_card_info_destructor(void *extra) {
+	struct sddr09_card_info *info = (struct sddr09_card_info *)extra;
 
-	US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]);
+	if (!info)
+		return;
 
-	command[1] = 0x08;
+	kfree(info->lba_to_pba);
+	kfree(info->pba_to_lba);
+}
 
-	if ( (result = sddr09_send_control(us, command, data, 2)) !=
-			USB_STOR_TRANSPORT_GOOD)
-		return result;
+static void
+sddr09_init_card_info(struct us_data *us) {
+	if (!us->extra) {
+		us->extra = kmalloc(sizeof(struct sddr09_card_info), GFP_NOIO);
+		if (us->extra) {
+			memset(us->extra, 0, sizeof(struct sddr09_card_info));
+			us->extra_destructor = sddr09_card_info_destructor;
+		}
+	}
+}
 
-	US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]);
+/*
+ * This is needed at a very early stage. If this is not listed in the
+ * unusual devices list but called from here then LUN 0 of the combo reader
+ * is not recognized. But I do not know what precisely these calls do.
+ */
+int
+sddr09_init(struct us_data *us) {
+	int result;
+	unsigned char data[18];
 
-	if ( (result = sddr09_send_control(us, command2, tur, 12)) !=
-			USB_STOR_TRANSPORT_GOOD) {
-		US_DEBUGP("SDDR09: request sense failed\n");
+	result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2);
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("sddr09_init: send_command fails\n");
 		return result;
 	}
 
-	if ( (result = sddr09_raw_bulk(
-		us, SCSI_DATA_READ, data, 14)) !=
-			USB_STOR_TRANSPORT_GOOD) {
-		US_DEBUGP("SDDR09: request sense bulk in failed\n");
+	US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]);
+	// get 07 02
+
+	result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2);
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("sddr09_init: 2nd send_command fails\n");
 		return result;
 	}
 
-	US_DEBUGP("SDDR09: request sense worked\n");
+	US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]);
+	// get 07 00
 
-	return result;
-}
-*/
+	result = sddr09_request_sense(us, data, sizeof(data));
+	if (result == USB_STOR_TRANSPORT_GOOD && data[2] != 0) {
+		int j;
+		for (j=0; j<sizeof(data); j++)
+			printk(" %02X", data[j]);
+		printk("\n");
+		// get 70 00 00 00 00 00 00 * 00 00 00 00 00 00
+		// 70: current command
+		// sense key 0, sense code 0, extd sense code 0
+		// additional transfer length * = sizeof(data) - 7
+		// Or: 70 00 06 00 00 00 00 0b 00 00 00 00 28 00 00 00 00 00
+		// sense key 06, sense code 28: unit attention,
+		// not ready to ready transition
+	}
 
-void sddr09_card_info_destructor(void *extra) {
-	struct sddr09_card_info *info = (struct sddr09_card_info *)extra;
+	// test unit ready
 
-	if (!extra)
-		return;
-
-	if (info->lba_to_pba)
-		kfree(info->lba_to_pba);
-	if (info->pba_to_lba)
-		kfree(info->pba_to_lba);
+	return USB_STOR_TRANSPORT_GOOD;		/* not result */
 }
 
 /*
@@ -824,36 +1588,53 @@
  */
 int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
-	int result;
-	int i;
+	static unsigned char sensekey = 0, sensecode = 0;
+	static unsigned char havefakesense = 0;
+	int result, i;
+	unsigned char *ptr;
+	unsigned long capacity;
+	unsigned int page, pages;
 	char string[64];
+
+	struct sddr09_card_info *info;
+
 	unsigned char inquiry_response[36] = {
 		0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
 	};
-	unsigned char mode_page_01[16] = { // write-protected for now
-		0x03, 0x00, 0x80, 0x00,
+
+	unsigned char mode_page_01[16] = {
+		0x0F, 0x00, 0, 0x00,
 		0x01, 0x0A,
 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 	};
-	unsigned char *ptr;
-	unsigned long capacity;
-	unsigned int lba;
-	unsigned int pba;
-	unsigned int page;
-	unsigned short pages;
-	struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra);
 
-	if (!us->extra) {
-		us->extra = kmalloc(
-			sizeof(struct sddr09_card_info), GFP_NOIO);
-		if (!us->extra)
+	info = (struct sddr09_card_info *)us->extra;
+	if (!info) {
+		nand_init_ecc();
+		sddr09_init_card_info(us);
+		info = (struct sddr09_card_info *)us->extra;
+		if (!info)
 			return USB_STOR_TRANSPORT_ERROR;
-		memset(us->extra, 0, sizeof(struct sddr09_card_info));
-		us->extra_destructor = sddr09_card_info_destructor;
 	}
 
 	ptr = (unsigned char *)srb->request_buffer;
 
+	if (srb->cmnd[0] == REQUEST_SENSE && havefakesense) {
+		/* for a faked command, we have to follow with a faked sense */
+		memset(ptr, 0, srb->request_bufflen);
+		if (srb->request_bufflen > 7) {
+			ptr[0] = 0x70;
+			ptr[2] = sensekey;
+			ptr[7] = srb->request_bufflen - 7;
+		}
+		if (srb->request_bufflen > 12)
+			ptr[12] = sensecode;
+		sensekey = sensecode = havefakesense = 0;
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	havefakesense = 1;
+
 	/* Dummy up a response for INQUIRY since SDDR09 doesn't
 	   respond to INQUIRY commands */
 
@@ -864,70 +1645,73 @@
 	}
 
 	if (srb->cmnd[0] == READ_CAPACITY) {
+		struct nand_flash_dev *cardinfo;
 
-		capacity = sddr09_get_capacity(us, &info->pagesize,
-			&info->blocksize);
+		sddr09_get_wp(us, info);	/* read WP bit */
 
-		if (!capacity)
+		cardinfo = sddr09_get_cardinfo(us, info->flags);
+		if (!cardinfo) {
+			/* probably no media */
+			sensekey = 0x02;	/* not ready */
+			sensecode = 0x3a;	/* medium not present */
 			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		info->capacity = (1 << cardinfo->chipshift);
+		info->pageshift = cardinfo->pageshift;
+		info->pagesize = (1 << info->pageshift);
+		info->blockshift = cardinfo->blockshift;
+		info->blocksize = (1 << info->blockshift);
+		info->blockmask = info->blocksize - 1;
 
-		info->capacity = capacity;
-		for (info->pageshift=1; 
-			(info->pagesize>>info->pageshift);
-			info->pageshift++);
-		info->pageshift--;
-		for (info->blockshift=1; 
-			(info->blocksize>>info->blockshift);
-			info->blockshift++);
-		info->blockshift--;
-		info->blockmask = (1<<info->blockshift)-1;
+		// map initialization, must follow get_cardinfo()
+		sddr09_read_map(us);
 
-		// Last page in the card
+		// Report capacity
 
-		capacity /= info->pagesize;
-		capacity--;
+		capacity = (info->lbact << info->blockshift) - 1;
 
 		ptr[0] = MSB_of(capacity>>16);
 		ptr[1] = LSB_of(capacity>>16);
 		ptr[2] = MSB_of(capacity&0xFFFF);
 		ptr[3] = LSB_of(capacity&0xFFFF);
 
-		// The page size
+		// Report page size
 
 		ptr[4] = MSB_of(info->pagesize>>16);
 		ptr[5] = LSB_of(info->pagesize>>16);
 		ptr[6] = MSB_of(info->pagesize&0xFFFF);
 		ptr[7] = LSB_of(info->pagesize&0xFFFF);
 
-		sddr09_read_map(us);
-
 		return USB_STOR_TRANSPORT_GOOD;
 	}
 
 	if (srb->cmnd[0] == MODE_SENSE) {
 
-			// Read-write error recovery page: there needs to
-			// be a check for write-protect here
+		// Read-write error recovery page: there needs to
+		// be a check for write-protect here
 
 		if ( (srb->cmnd[2] & 0x3F) == 0x01 ) {
 
 			US_DEBUGP(
-			  "SDDR09: Dummy up request for mode page 1\n");
+				"SDDR09: Dummy up request for mode page 1\n");
 
-			if (ptr==NULL || 
-			  srb->request_bufflen<sizeof(mode_page_01))
+			if (ptr == NULL || 
+			    srb->request_bufflen<sizeof(mode_page_01))
 				return USB_STOR_TRANSPORT_ERROR;
 
+			mode_page_01[0] = sizeof(mode_page_01) - 1;
+			mode_page_01[2] = (info->flags & SDDR09_WP) ? 0x80 : 0;
 			memcpy(ptr, mode_page_01, sizeof(mode_page_01));
 			return USB_STOR_TRANSPORT_GOOD;
 
 		} else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) {
 
-			US_DEBUGP(
-			  "SDDR09: Dummy up request for all mode pages\n");
+			US_DEBUGP("SDDR09: Dummy up request for "
+				  "all mode pages\n");
 
-			if (ptr==NULL || 
-			  srb->request_bufflen<sizeof(mode_page_01))
+			if (ptr == NULL || 
+			    srb->request_bufflen<sizeof(mode_page_01))
 				return USB_STOR_TRANSPORT_ERROR;
 
 			memcpy(ptr, mode_page_01, sizeof(mode_page_01));
@@ -935,22 +1719,22 @@
 
 		}
 
-		// FIXME: sense buffer?
-
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
 	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
 
 		US_DEBUGP(
-		  "SDDR09: %s medium removal. Not that I can do"
-		  " anything about it...\n",
-		  (srb->cmnd[4]&0x03) ? "Prevent" : "Allow");
+			"SDDR09: %s medium removal. Not that I can do"
+			" anything about it...\n",
+			(srb->cmnd[4]&0x03) ? "Prevent" : "Allow");
 
 		return USB_STOR_TRANSPORT_GOOD;
 
 	}
 
+	havefakesense = 0;
+
 	if (srb->cmnd[0] == READ_10) {
 
 		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
@@ -958,80 +1742,51 @@
 		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
 		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
 
-		// convert page to block and page-within-block
-
-		lba = page >> info->blockshift;
-		page = page & info->blockmask;
-
-		// locate physical block corresponding to logical block
-
-		if (lba >=
-			(info->capacity >> 
-				(info->pageshift + info->blockshift) ) ) {
-
-			US_DEBUGP("Error: Requested LBA %04X exceeds maximum "
-			  "block %04lX\n", lba,
-			  (info->capacity >> (info->pageshift + info->blockshift))-1);
-
-			// FIXME: sense buffer?
-
-			return USB_STOR_TRANSPORT_ERROR;
-		}
-
-		pba = info->lba_to_pba[lba];
-
-		// if pba is 0, either it's really 0, in which case
-		// the pba-to-lba map for pba 0 will be the lba,
-		// or that lba doesn't exist.
+		US_DEBUGP("READ_10: read page %d pagect %d\n",
+			  page, pages);
 
-		if (pba==0 && info->pba_to_lba[0] != lba) {
+		return sddr09_read_data(us, page, pages, ptr, srb->use_sg);
+	}
 
-			// FIXME: sense buffer?
+	if (srb->cmnd[0] == WRITE_10) {
 
-			US_DEBUGP("Error: Requested LBA %04X has no physical block "
-			  "mapping.\n", lba);
+		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+		page <<= 16;
+		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
 
-			return USB_STOR_TRANSPORT_ERROR;
-		}
+		US_DEBUGP("WRITE_10: write page %d pagect %d\n",
+			  page, pages);
 
-		US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X"
-			" pages %d\n",
-			pba, lba, page, pages);
-
-		return sddr09_read_data(us,
-			( (pba << info->blockshift) + page) << info->pageshift,
-			pages, ptr, srb->use_sg);
+		return sddr09_write_data(us, page, pages, ptr, srb->use_sg);
 	}
 
 	// Pass TEST_UNIT_READY and REQUEST_SENSE through
 
 	if (srb->cmnd[0] != TEST_UNIT_READY &&
-	    srb->cmnd[0] != REQUEST_SENSE)
-		return USB_STOR_TRANSPORT_ERROR; // FIXME: sense buffer?
+	    srb->cmnd[0] != REQUEST_SENSE) {
+		havefakesense = 1;
+		return USB_STOR_TRANSPORT_ERROR;
+	}
 
 	for (; srb->cmd_len<12; srb->cmd_len++)
 		srb->cmnd[srb->cmd_len] = 0;
 
-	srb->cmnd[1] = 0x20;
+	srb->cmnd[1] = LUNBITS;
 
 	string[0] = 0;
 	for (i=0; i<12; i++)
-	  sprintf(string+strlen(string), "%02X ", srb->cmnd[i]);
+		sprintf(string+strlen(string), "%02X ", srb->cmnd[i]);
 
 	US_DEBUGP("SDDR09: Send control for command %s\n",
-		string);
+		  string);
 
-	if ( (result = sddr09_send_control(us,
-			usb_sndctrlpipe(us->pusb_dev,0),
-			0,
-			0x41,
-			0,
-			0,
-			srb->cmnd,
-			12)) != USB_STOR_TRANSPORT_GOOD)
+	result = sddr09_send_scsi_command(us, srb->cmnd, 12);
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("sddr09_transport: sddr09_send_scsi_command "
+			  "returns %d\n", result);
 		return result;
-
-	US_DEBUGP("SDDR09: Control for command OK\n");
+	}
 
 	if (srb->request_bufflen == 0)
 		return USB_STOR_TRANSPORT_GOOD;
@@ -1040,17 +1795,17 @@
 	    srb->sc_data_direction == SCSI_DATA_READ) {
 
 		US_DEBUGP("SDDR09: %s %d bytes\n",
-			srb->sc_data_direction==SCSI_DATA_WRITE ?
+			  (srb->sc_data_direction == SCSI_DATA_WRITE) ?
 			  "sending" : "receiving",
-			srb->request_bufflen);
+			  srb->request_bufflen);
 
 		result = sddr09_bulk_transport(us,
-			srb->sc_data_direction,
-			srb->request_buffer, 
-			srb->request_bufflen, srb->use_sg);
+					       srb->sc_data_direction,
+					       srb->request_buffer, 
+					       srb->request_bufflen,
+					       srb->use_sg);
 
 		return result;
-
 	} 
 
 	return USB_STOR_TRANSPORT_GOOD;
diff -Nru a/drivers/usb/storage/sddr09.h b/drivers/usb/storage/sddr09.h
--- a/drivers/usb/storage/sddr09.h	Thu May  2 17:22:16 2002
+++ b/drivers/usb/storage/sddr09.h	Thu May  2 17:22:16 2002
@@ -5,6 +5,7 @@
  *
  * Current development and maintenance by:
  *   (c) 2000 Robert Baruch (autophile@dol.net)
+ *   (c) 2002 Andries Brouwer (aeb@cwi.nl)
  *
  * See sddr09.c for more explanation
  *
@@ -39,6 +40,9 @@
 	int		blockmask;	/* 2^blockshift - 1 */
 	int		*lba_to_pba;	/* logical to physical map */
 	int		*pba_to_lba;	/* physical to logical map */
+	int		lbact;		/* number of available pages */
+	int		flags;
+#define	SDDR09_WP	1		/* write protected */
 };
 
 #endif
diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
--- a/drivers/usb/storage/unusual_devs.h	Thu May  2 17:22:17 2002
+++ b/drivers/usb/storage/unusual_devs.h	Thu May  2 17:22:17 2002
@@ -130,14 +130,14 @@
 		"ImageMate SDDR09",
 		US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
 		US_FL_SINGLE_LUN | US_FL_START_STOP ),
-#endif
 
 /* This entry is from Andries.Brouwer@cwi.nl */
 UNUSUAL_DEV(  0x04e6, 0x0005, 0x0100, 0x0208,
 		"SCM Microsystems",
 		"eUSB SmartMedia / CompactFlash Adapter",
-		US_SC_SCSI, US_PR_DPCM_USB, NULL, 
+		US_SC_SCSI, US_PR_DPCM_USB, sddr09_init, 
 		US_FL_START_STOP), 
+#endif
 
 UNUSUAL_DEV(  0x04e6, 0x0006, 0x0100, 0x0205, 
 		"Shuttle",
diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
--- a/drivers/usb/usb-skeleton.c	Thu May  2 17:22:17 2002
+++ b/drivers/usb/usb-skeleton.c	Thu May  2 17:22:17 2002
@@ -525,6 +525,7 @@
 	int minor;
 	int buffer_size;
 	int i;
+	int retval;
 	char name[10];
 
 	
@@ -535,14 +536,20 @@
 	}
 
 	down (&minor_table_mutex);
-	if (usb_register_dev (&skel_driver, 1, &minor)) {
+	retval = usb_register_dev (&skel_driver, 1, &minor);
+	if (retval) {
+		if (retval != -ENODEV) {
+			/* something prevented us from registering this driver */
+			err ("Not able to get a minor for this device.");
+			goto exit;
+		}
 		/* we could not get a dynamic minor, so lets find one of our own */
 		for (minor = 0; minor < MAX_DEVICES; ++minor) {
 			if (minor_table[minor] == NULL)
 				break;
 		}
 		if (minor >= MAX_DEVICES) {
-			info ("Too many devices plugged in, can not handle this device.");
+			err ("Too many devices plugged in, can not handle this device.");
 			goto exit;
 		}
 	}
diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile
--- a/drivers/video/Makefile	Thu May  2 17:22:16 2002
+++ b/drivers/video/Makefile	Thu May  2 17:22:16 2002
@@ -10,7 +10,7 @@
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
 export-objs    := fbmem.o fbcmap.o fbcon.o fbmon.o modedb.o \
-		  fbcon-afb.o fbcon-ilbm.o \
+		  fbcon-afb.o fbcon-ilbm.o fbgen.o \
 		  fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \
 		  fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
 		  fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
@@ -35,7 +35,7 @@
 obj-$(CONFIG_FONT_ACORN_8x8)      += font_acorn_8x8.o
 
 # Add fbmon.o back into obj-$(CONFIG_FB) in 2.5.x
-obj-$(CONFIG_FB)                  += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o
+obj-$(CONFIG_FB)                  += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o fbgen.o
 # Only include macmodes.o if we have FB support and are PPC
 ifeq ($(CONFIG_FB),y)
 obj-$(CONFIG_PPC)                 += macmodes.o
@@ -43,7 +43,7 @@
 
 obj-$(CONFIG_FB_ACORN)            += acornfb.o
 obj-$(CONFIG_FB_AMIGA)            += amifb.o
-obj-$(CONFIG_FB_PM2)              += pm2fb.o fbgen.o
+obj-$(CONFIG_FB_PM2)              += pm2fb.o
 obj-$(CONFIG_FB_APOLLO)           += dnfb.o
 obj-$(CONFIG_FB_Q40)              += q40fb.o
 obj-$(CONFIG_FB_ATARI)            += atafb.o
@@ -66,9 +66,9 @@
 obj-$(CONFIG_FB_OF)               += offb.o
 obj-$(CONFIG_FB_IMSTT)            += imsttfb.o
 obj-$(CONFIG_FB_RETINAZ3)         += retz3fb.o
-obj-$(CONFIG_FB_CLGEN)            += clgenfb.o fbgen.o
+obj-$(CONFIG_FB_CLGEN)            += clgenfb.o
 obj-$(CONFIG_FB_S3TRIO)           += S3triofb.o
-obj-$(CONFIG_FB_TGA)              += tgafb.o fbgen.o
+obj-$(CONFIG_FB_TGA)              += tgafb.o
 obj-$(CONFIG_FB_VESA)             += vesafb.o 
 obj-$(CONFIG_FB_VGA16)            += vga16fb.o fbcon-vga-planes.o
 obj-$(CONFIG_FB_VIRGE)            += virgefb.o
@@ -82,7 +82,7 @@
 obj-$(CONFIG_FB_CGFOURTEEN)       += cgfourteenfb.o sbusfb.o
 obj-$(CONFIG_FB_P9100)            += p9100fb.o sbusfb.o
 obj-$(CONFIG_FB_LEO)              += leofb.o sbusfb.o
-obj-$(CONFIG_FB_STI)	          += stifb.o sticore.o fbgen.o
+obj-$(CONFIG_FB_STI)	          += stifb.o sticore.o
 obj-$(CONFIG_FB_PMAG_BA)          += pmag-ba-fb.o
 obj-$(CONFIG_FB_PMAGB_B)          += pmagb-b-fb.o
 obj-$(CONFIG_FB_MAXINE)           += maxinefb.o
@@ -114,8 +114,8 @@
 obj-$(CONFIG_FB_HGA)              += hgafb.o  
 obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o  
-obj-$(CONFIG_FB_HIT)              += hitfb.o fbgen.o
-obj-$(CONFIG_FB_E1355)            += epson1355fb.o fbgen.o
+obj-$(CONFIG_FB_HIT)              += hitfb.o
+obj-$(CONFIG_FB_E1355)            += epson1355fb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
 
diff -Nru a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
--- a/drivers/video/aty/atyfb_base.c	Thu May  2 17:22:16 2002
+++ b/drivers/video/aty/atyfb_base.c	Thu May  2 17:22:16 2002
@@ -247,7 +247,7 @@
 static int default_mclk __initdata = 0;
 
 #ifndef MODULE
-static const char *mode_option __initdata = NULL;
+static char *mode_option __initdata = NULL;
 #endif
 
 #ifdef CONFIG_PPC
@@ -267,33 +267,33 @@
 static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
 #endif
 
-static const char m64n_gx[] __initdata = "mach64GX (ATI888GX00)";
-static const char m64n_cx[] __initdata = "mach64CX (ATI888CX00)";
-static const char m64n_ct[] __initdata = "mach64CT (ATI264CT)";
-static const char m64n_et[] __initdata = "mach64ET (ATI264ET)";
-static const char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)";
-static const char m64n_vta4[] __initdata = "mach64VTA4 (ATI264VT)";
-static const char m64n_vtb[] __initdata = "mach64VTB (ATI264VTB)";
-static const char m64n_vt4[] __initdata = "mach64VT4 (ATI264VT4)";
-static const char m64n_gt[] __initdata = "3D RAGE (GT)";
-static const char m64n_gtb[] __initdata = "3D RAGE II+ (GTB)";
-static const char m64n_iic_p[] __initdata = "3D RAGE IIC (PCI)";
-static const char m64n_iic_a[] __initdata = "3D RAGE IIC (AGP)";
-static const char m64n_lt[] __initdata = "3D RAGE LT";
-static const char m64n_ltg[] __initdata = "3D RAGE LT-G";
-static const char m64n_gtc_ba[] __initdata = "3D RAGE PRO (BGA, AGP)";
-static const char m64n_gtc_ba1[] __initdata = "3D RAGE PRO (BGA, AGP, 1x only)";
-static const char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)";
-static const char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)";
-static const char m64n_gtc_ppl[] __initdata = "3D RAGE PRO (PQFP, PCI, limited 3D)";
-static const char m64n_xl[] __initdata = "3D RAGE (XL)";
-static const char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)";
-static const char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)";
-static const char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)";
-static const char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)";
+static char m64n_gx[] __initdata = "mach64GX (ATI888GX00)";
+static char m64n_cx[] __initdata = "mach64CX (ATI888CX00)";
+static char m64n_ct[] __initdata = "mach64CT (ATI264CT)";
+static char m64n_et[] __initdata = "mach64ET (ATI264ET)";
+static char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)";
+static char m64n_vta4[] __initdata = "mach64VTA4 (ATI264VT)";
+static char m64n_vtb[] __initdata = "mach64VTB (ATI264VTB)";
+static char m64n_vt4[] __initdata = "mach64VT4 (ATI264VT4)";
+static char m64n_gt[] __initdata = "3D RAGE (GT)";
+static char m64n_gtb[] __initdata = "3D RAGE II+ (GTB)";
+static char m64n_iic_p[] __initdata = "3D RAGE IIC (PCI)";
+static char m64n_iic_a[] __initdata = "3D RAGE IIC (AGP)";
+static char m64n_lt[] __initdata = "3D RAGE LT";
+static char m64n_ltg[] __initdata = "3D RAGE LT-G";
+static char m64n_gtc_ba[] __initdata = "3D RAGE PRO (BGA, AGP)";
+static char m64n_gtc_ba1[] __initdata = "3D RAGE PRO (BGA, AGP, 1x only)";
+static char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)";
+static char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)";
+static char m64n_gtc_ppl[] __initdata = "3D RAGE PRO (PQFP, PCI, limited 3D)";
+static char m64n_xl[] __initdata = "3D RAGE (XL)";
+static char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)";
+static char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)";
+static char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)";
+static char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)";
 
 
-static const struct {
+static struct {
     u16 pci_id, chip_type;
     u8 rev_mask, rev_val;
     const char *name;
@@ -353,24 +353,24 @@
 #endif /* CONFIG_FB_ATY_CT */
 };
 
-static const char ram_dram[] __initdata = "DRAM";
-static const char ram_vram[] __initdata = "VRAM";
-static const char ram_edo[] __initdata = "EDO";
-static const char ram_sdram[] __initdata = "SDRAM";
-static const char ram_sgram[] __initdata = "SGRAM";
-static const char ram_wram[] __initdata = "WRAM";
-static const char ram_off[] __initdata = "OFF";
-static const char ram_resv[] __initdata = "RESV";
+static char ram_dram[] __initdata = "DRAM";
+static char ram_vram[] __initdata = "VRAM";
+static char ram_edo[] __initdata = "EDO";
+static char ram_sdram[] __initdata = "SDRAM";
+static char ram_sgram[] __initdata = "SGRAM";
+static char ram_wram[] __initdata = "WRAM";
+static char ram_off[] __initdata = "OFF";
+static char ram_resv[] __initdata = "RESV";
 
 #ifdef CONFIG_FB_ATY_GX
-static const char *aty_gx_ram[8] __initdata = {
+static char *aty_gx_ram[8] __initdata = {
     ram_dram, ram_vram, ram_vram, ram_dram,
     ram_dram, ram_vram, ram_vram, ram_resv
 };
 #endif /* CONFIG_FB_ATY_GX */
 
 #ifdef CONFIG_FB_ATY_CT
-static const char *aty_ct_ram[8] __initdata = {
+static char *aty_ct_ram[8] __initdata = {
     ram_off, ram_dram, ram_edo, ram_edo,
     ram_sdram, ram_sgram, ram_wram, ram_resv
 };
@@ -2625,7 +2625,7 @@
 
 #ifdef CONFIG_FB_ATY_CT
     /* Erase HW Cursor */
-    if (info->cursor)
+    if (info->cursor && (fb->currcon >= 0))
 	atyfb_cursor(&fb_display[fb->currcon], CM_ERASE,
 		     info->cursor->pos.x, info->cursor->pos.y);
 #endif /* CONFIG_FB_ATY_CT */
diff -Nru a/drivers/video/fbcon-accel.h b/drivers/video/fbcon-accel.h
--- a/drivers/video/fbcon-accel.h	Thu May  2 17:22:16 2002
+++ b/drivers/video/fbcon-accel.h	Thu May  2 17:22:16 2002
@@ -1,5 +1,5 @@
 /*
- *  FBcon low-level driver for 32 bpp packed pixel (cfb32)
+ *  FBcon low-level driver that is a wrapper for the accel engine. 
  */
 
 #ifndef _VIDEO_FBCON_ACCEL_H
diff -Nru a/drivers/video/fbcon-cfb16.c b/drivers/video/fbcon-cfb16.c
--- a/drivers/video/fbcon-cfb16.c	Thu May  2 17:22:17 2002
+++ b/drivers/video/fbcon-cfb16.c	Thu May  2 17:22:17 2002
@@ -47,8 +47,8 @@
     u8 *src, *dst;
 
     if (sx == 0 && dx == 0 && width * fontwidth(p) * 2 == bytes) {
-	fb_memmove(p->screen_base + dy * linesize,
-		  p->screen_base + sy * linesize,
+	fb_memmove(p->fb_info->screen_base + dy * linesize,
+		  p->fb_info->screen_base + sy * linesize,
 		  height * linesize);
 	return;
     }
@@ -62,16 +62,16 @@
 	width *= fontwidth(p)*2;
     }
     if (dy < sy || (dy == sy && dx < sx)) {
-	src = p->screen_base + sy * linesize + sx;
-	dst = p->screen_base + dy * linesize + dx;
+	src = p->fb_info->screen_base + sy * linesize + sx;
+	dst = p->fb_info->screen_base + dy * linesize + dx;
 	for (rows = height * fontheight(p); rows--;) {
 	    fb_memmove(dst, src, width);
 	    src += bytes;
 	    dst += bytes;
 	}
     } else {
-	src = p->screen_base + (sy+height) * linesize + sx - bytes;
-	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+	src = p->fb_info->screen_base + (sy+height) * linesize + sx - bytes;
+	dst = p->fb_info->screen_base + (dy+height) * linesize + dx - bytes;
 	for (rows = height * fontheight(p); rows--;) {
 	    fb_memmove(dst, src, width);
 	    src -= bytes;
@@ -108,7 +108,7 @@
     int bytes = p->next_line, lines = height * fontheight(p);
     u32 bgx;
 
-    dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 2;
+    dest = p->fb_info->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 2;
 
     bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
 
@@ -126,7 +126,7 @@
     int bytes = p->next_line, rows;
     u32 eorx, fgx, bgx;
 
-    dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
+    dest = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
 
     fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
     bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
@@ -177,7 +177,7 @@
     int rows, bytes = p->next_line;
     u32 eorx, fgx, bgx;
 
-    dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
+    dest0 = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
     c = scr_readw(s);
     fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
     bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
@@ -233,7 +233,7 @@
     u8 *dest;
     int bytes = p->next_line, rows;
 
-    dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p)*2;
+    dest = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p)*2;
     for (rows = fontheight(p); rows--; dest += bytes) {
 	switch (fontwidth(p)) {
 	case 16:
@@ -268,10 +268,10 @@
     bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
 
     if (!bottom_only && (right_width = p->var.xres-right_start))
-	rectfill(p->screen_base+right_start*2, right_width,
+	rectfill(p->fb_info->screen_base+right_start*2, right_width,
 		 p->var.yres_virtual, bgx, bytes);
     if ((bottom_width = p->var.yres-bottom_start))
-	rectfill(p->screen_base+(p->var.yoffset+bottom_start)*bytes,
+	rectfill(p->fb_info->screen_base+(p->var.yoffset+bottom_start)*bytes,
 		 right_start, bottom_width, bgx, bytes);
 }
 
diff -Nru a/drivers/video/fbcon-cfb2.c b/drivers/video/fbcon-cfb2.c
--- a/drivers/video/fbcon-cfb2.c	Thu May  2 17:22:16 2002
+++ b/drivers/video/fbcon-cfb2.c	Thu May  2 17:22:16 2002
@@ -61,14 +61,14 @@
 	u8 *src,*dst;
 
 	if (sx == 0 && dx == 0 && width * 2 == bytes) {
-		fb_memmove(p->screen_base + dy * linesize,
-			  p->screen_base + sy * linesize,
+		fb_memmove(p->fb_info->screen_base + dy * linesize,
+			  p->fb_info->screen_base + sy * linesize,
 			  height * linesize);
 	}
 	else {
 		if (dy < sy || (dy == sy && dx < sx)) {
-			src = p->screen_base + sy * linesize + sx * 2;
-			dst = p->screen_base + dy * linesize + dx * 2;
+			src = p->fb_info->screen_base + sy * linesize + sx * 2;
+			dst = p->fb_info->screen_base + dy * linesize + dx * 2;
 			for (rows = height * fontheight(p) ; rows-- ;) {
 				fb_memmove(dst, src, width * 2);
 				src += bytes;
@@ -76,10 +76,8 @@
 			}
 		}
 		else {
-			src = p->screen_base + (sy+height) * linesize + sx * 2
-				- bytes;
-			dst = p->screen_base + (dy+height) * linesize + dx * 2
-				- bytes;
+			src = p->fb_info->screen_base + (sy+height) * linesize + sx * 2 - bytes;
+			dst = p->fb_info->screen_base + (dy+height) * linesize + dx * 2 - bytes;
 			for (rows = height * fontheight(p) ; rows-- ;) {
 				fb_memmove(dst, src, width * 2);
 				src -= bytes;
@@ -96,7 +94,7 @@
 	int bytes=p->next_line,lines=height * fontheight(p), rows, i;
 	u32 bgx;
 
-	dest = p->screen_base + sy * fontheight(p) * bytes + sx * 2;
+	dest = p->fb_info->screen_base + sy * fontheight(p) * bytes + sx * 2;
 
 	bgx=attr_bgcol_ec(p,conp);
 	bgx |= (bgx << 2);	/* expand the colour to 16 bits */
@@ -128,7 +126,7 @@
 	int bytes=p->next_line,rows;
 	u32 eorx,fgx,bgx;
 
-	dest = p->screen_base + yy * fontheight(p) * bytes + xx * 2;
+	dest = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * 2;
 	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
 
 	fgx=3;/*attr_fgcol(p,c);*/
@@ -153,7 +151,7 @@
 	int rows,bytes=p->next_line;
 	u32 eorx, fgx, bgx;
 
-	dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * 2;
+	dest0 = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * 2;
 	c = scr_readw(s);
 	fgx = 3/*attr_fgcol(p, c)*/;
 	bgx = attr_bgcol(p, c);
@@ -179,7 +177,7 @@
 	u8 *dest;
 	int bytes=p->next_line, rows;
 
-	dest = p->screen_base + yy * fontheight(p) * bytes + xx * 2;
+	dest = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * 2;
 	for (rows = fontheight(p) ; rows-- ; dest += bytes) {
 		fb_writew(fb_readw(dest) ^ 0xffff, dest);
 	}
diff -Nru a/drivers/video/fbcon-cfb24.c b/drivers/video/fbcon-cfb24.c
--- a/drivers/video/fbcon-cfb24.c	Thu May  2 17:22:16 2002
+++ b/drivers/video/fbcon-cfb24.c	Thu May  2 17:22:16 2002
@@ -36,8 +36,8 @@
     u8 *src, *dst;
 
     if (sx == 0 && dx == 0 && width * fontwidth(p) * 3 == bytes) {
-	fb_memmove(p->screen_base + dy * linesize,
-		  p->screen_base + sy * linesize,
+	fb_memmove(p->fb_info->screen_base + dy * linesize,
+		  p->fb_info->screen_base + sy * linesize,
 		  height * linesize);
 	return;
     }
@@ -52,16 +52,16 @@
     }
     sx *= 3; dx *= 3; width *= 3;
     if (dy < sy || (dy == sy && dx < sx)) {
-	src = p->screen_base + sy * linesize + sx;
-	dst = p->screen_base + dy * linesize + dx;
+	src = p->fb_info->screen_base + sy * linesize + sx;
+	dst = p->fb_info->screen_base + dy * linesize + dx;
 	for (rows = height * fontheight(p); rows--;) {
 	    fb_memmove(dst, src, width);
 	    src += bytes;
 	    dst += bytes;
 	}
     } else {
-	src = p->screen_base + (sy+height) * linesize + sx - bytes;
-	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+	src = p->fb_info->screen_base + (sy+height) * linesize + sx - bytes;
+	dst = p->fb_info->screen_base + (dy+height) * linesize + dx - bytes;
 	for (rows = height * fontheight(p); rows--;) {
 	    fb_memmove(dst, src, width);
 	    src -= bytes;
@@ -122,7 +122,7 @@
     int bytes = p->next_line, lines = height * fontheight(p);
     u32 bgx;
 
-    dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 3;
+    dest = p->fb_info->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 3;
 
     bgx = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
 
@@ -140,7 +140,7 @@
     int bytes = p->next_line, rows;
     u32 eorx, fgx, bgx, d1, d2, d3, d4;
 
-    dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3;
+    dest = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3;
     if (fontwidth(p) <= 8)
 	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
     else
@@ -190,7 +190,7 @@
     int rows, bytes = p->next_line;
     u32 eorx, fgx, bgx, d1, d2, d3, d4;
 
-    dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3;
+    dest0 = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3;
     c = scr_readw(s);
     fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)];
     bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
@@ -241,7 +241,7 @@
     u8 *dest;
     int bytes = p->next_line, rows;
 
-    dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3;
+    dest = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3;
     for (rows = fontheight(p); rows--; dest += bytes) {
 	switch (fontwidth(p)) {
 	case 16:
@@ -280,10 +280,10 @@
     bgx = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
 
     if (!bottom_only && (right_width = p->var.xres-right_start))
-	rectfill(p->screen_base+right_start*3, right_width,
+	rectfill(p->fb_info->screen_base+right_start*3, right_width,
 		 p->var.yres_virtual, bgx, bytes);
     if ((bottom_width = p->var.yres-bottom_start))
-	rectfill(p->screen_base+(p->var.yoffset+bottom_start)*bytes,
+	rectfill(p->fb_info->screen_base+(p->var.yoffset+bottom_start)*bytes,
 		 right_start, bottom_width, bgx, bytes);
 }
 
diff -Nru a/drivers/video/fbcon-cfb32.c b/drivers/video/fbcon-cfb32.c
--- a/drivers/video/fbcon-cfb32.c	Thu May  2 17:22:16 2002
+++ b/drivers/video/fbcon-cfb32.c	Thu May  2 17:22:16 2002
@@ -36,8 +36,8 @@
     u8 *src, *dst;
 
     if (sx == 0 && dx == 0 && width * fontwidth(p) * 4 == bytes) {
-	fb_memmove(p->screen_base + dy * linesize,
-		  p->screen_base + sy * linesize,
+	fb_memmove(p->fb_info->screen_base + dy * linesize,
+		  p->fb_info->screen_base + sy * linesize,
 		  height * linesize);
 	return;
     }
@@ -51,16 +51,16 @@
 	width *= fontwidth(p)*4;
     }
     if (dy < sy || (dy == sy && dx < sx)) {
-	src = p->screen_base + sy * linesize + sx;
-	dst = p->screen_base + dy * linesize + dx;
+	src = p->fb_info->screen_base + sy * linesize + sx;
+	dst = p->fb_info->screen_base + dy * linesize + dx;
 	for (rows = height * fontheight(p); rows--;) {
 	    fb_memmove(dst, src, width);
 	    src += bytes;
 	    dst += bytes;
 	}
     } else {
-	src = p->screen_base + (sy+height) * linesize + sx - bytes;
-	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+	src = p->fb_info->screen_base + (sy+height) * linesize + sx - bytes;
+	dst = p->fb_info->screen_base + (dy+height) * linesize + dx - bytes;
 	for (rows = height * fontheight(p); rows--;) {
 	    fb_memmove(dst, src, width);
 	    src -= bytes;
@@ -99,7 +99,7 @@
     int bytes = p->next_line, lines = height * fontheight(p);
     u32 bgx;
 
-    dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 4;
+    dest = p->fb_info->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 4;
 
     bgx = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
 
@@ -117,7 +117,7 @@
     int bytes = p->next_line, rows;
     u32 eorx, fgx, bgx, *pt;
 
-    dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
+    dest = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
     if (fontwidth(p) <= 8)
 	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
     else
@@ -163,7 +163,7 @@
     int rows, bytes = p->next_line;
     u32 eorx, fgx, bgx, *pt;
 
-    dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
+    dest0 = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
     c = scr_readw(s);
     fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)];
     bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
@@ -210,7 +210,7 @@
     u8 *dest;
     int bytes = p->next_line, rows;
 
-    dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
+    dest = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
     for (rows = fontheight(p); rows--; dest += bytes) {
 	switch (fontwidth(p)) {
 	case 16:
@@ -254,10 +254,10 @@
     bgx = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
 
     if (!bottom_only && (right_width = p->var.xres-right_start))
-	rectfill(p->screen_base+right_start*4, right_width,
+	rectfill(p->fb_info->screen_base+right_start*4, right_width,
 		 p->var.yres_virtual, bgx, bytes);
     if ((bottom_width = p->var.yres-bottom_start))
-	rectfill(p->screen_base+(p->var.yoffset+bottom_start)*bytes,
+	rectfill(p->fb_info->screen_base+(p->var.yoffset+bottom_start)*bytes,
 		 right_start, bottom_width, bgx, bytes);
 }
 
diff -Nru a/drivers/video/fbcon-cfb4.c b/drivers/video/fbcon-cfb4.c
--- a/drivers/video/fbcon-cfb4.c	Thu May  2 17:22:16 2002
+++ b/drivers/video/fbcon-cfb4.c	Thu May  2 17:22:16 2002
@@ -61,14 +61,14 @@
 	u8 *src,*dst;
 
 	if (sx == 0 && dx == 0 && width * 4 == bytes) {
-		fb_memmove(p->screen_base + dy * linesize,
-			  p->screen_base + sy * linesize,
+		fb_memmove(p->fb_info->screen_base + dy * linesize,
+			  p->fb_info->screen_base + sy * linesize,
 			  height * linesize);
 	}
 	else {
 		if (dy < sy || (dy == sy && dx < sx)) {
-			src = p->screen_base + sy * linesize + sx * 4;
-			dst = p->screen_base + dy * linesize + dx * 4;
+			src = p->fb_info->screen_base + sy * linesize + sx * 4;
+			dst = p->fb_info->screen_base + dy * linesize + dx * 4;
 			for (rows = height * fontheight(p) ; rows-- ;) {
 				fb_memmove(dst, src, width * 4);
 				src += bytes;
@@ -76,10 +76,8 @@
 			}
 		}
 		else {
-			src = p->screen_base + (sy+height) * linesize + sx * 4
-				- bytes;
-			dst = p->screen_base + (dy+height) * linesize + dx * 4
-				- bytes;
+			src = p->fb_info->screen_base + (sy+height) * linesize + sx * 4 - bytes;
+			dst = p->fb_info->screen_base + (dy+height) * linesize + dx * 4 - bytes;
 			for (rows = height * fontheight(p) ; rows-- ;) {
 				fb_memmove(dst, src, width * 4);
 				src -= bytes;
@@ -96,9 +94,9 @@
 	int bytes=p->next_line,lines=height * fontheight(p), rows, i;
 	u32 bgx;
 
-/*	if(p->screen_base!=0xFDD00020)
+/*	if(p->fb_info->screen_base!=0xFDD00020)
 		mac_boom(1);*/
-	dest = p->screen_base + sy * fontheight(p) * bytes + sx * 4;
+	dest = p->fb_info->screen_base + sy * fontheight(p) * bytes + sx * 4;
 
 	bgx=attr_bgcol_ec(p,conp);
 	bgx |= (bgx << 4);	/* expand the colour to 32bits */
@@ -130,7 +128,7 @@
 	int bytes=p->next_line,rows;
 	u32 eorx,fgx,bgx;
 
-	dest = p->screen_base + yy * fontheight(p) * bytes + xx * 4;
+	dest = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * 4;
 	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
 
 	fgx=attr_fgcol(p,c);
@@ -155,7 +153,7 @@
 	int rows,bytes=p->next_line;
 	u32 eorx, fgx, bgx;
 
-	dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * 4;
+	dest0 = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * 4;
 	c = scr_readw(s);
 	fgx = attr_fgcol(p, c);
 	bgx = attr_bgcol(p, c);
@@ -183,7 +181,7 @@
 	u8 *dest;
 	int bytes=p->next_line, rows;
 
-	dest = p->screen_base + yy * fontheight(p) * bytes + xx * 4;
+	dest = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * 4;
 	for (rows = fontheight(p) ; rows-- ; dest += bytes) {
 		fb_writel(fb_readl(dest+0) ^ 0xffffffff, dest+0);
 	}
diff -Nru a/drivers/video/fbcon-cfb8.c b/drivers/video/fbcon-cfb8.c
--- a/drivers/video/fbcon-cfb8.c	Thu May  2 17:22:17 2002
+++ b/drivers/video/fbcon-cfb8.c	Thu May  2 17:22:17 2002
@@ -52,8 +52,8 @@
     u8 *src,*dst;
 
     if (sx == 0 && dx == 0 && width * fontwidth(p) == bytes) {
-	fb_memmove(p->screen_base + dy * linesize,
-		  p->screen_base + sy * linesize,
+	fb_memmove(p->fb_info->screen_base + dy * linesize,
+		  p->fb_info->screen_base + sy * linesize,
 		  height * linesize);
 	return;
     }
@@ -63,16 +63,16 @@
     	sx *= fontwidth(p); dx *= fontwidth(p); width *= fontwidth(p);
     }
     if (dy < sy || (dy == sy && dx < sx)) {
-	src = p->screen_base + sy * linesize + sx;
-	dst = p->screen_base + dy * linesize + dx;
+	src = p->fb_info->screen_base + sy * linesize + sx;
+	dst = p->fb_info->screen_base + dy * linesize + dx;
 	for (rows = height * fontheight(p) ; rows-- ;) {
 	    fb_memmove(dst, src, width);
 	    src += bytes;
 	    dst += bytes;
 	}
     } else {
-	src = p->screen_base + (sy+height) * linesize + sx - bytes;
-	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+	src = p->fb_info->screen_base + (sy+height) * linesize + sx - bytes;
+	dst = p->fb_info->screen_base + (dy+height) * linesize + dx - bytes;
 	for (rows = height * fontheight(p) ; rows-- ;) {
 	    fb_memmove(dst, src, width);
 	    src -= bytes;
@@ -97,7 +97,7 @@
     int bytes=p->next_line,lines=height * fontheight(p);
     u8 bgx;
 
-    dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p);
+    dest = p->fb_info->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p);
 
     bgx=attr_bgcol_ec(p,conp);
 
@@ -115,7 +115,7 @@
     int bytes=p->next_line,rows;
     u32 eorx,fgx,bgx;
 
-    dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
+    dest = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
     if (fontwidth(p) <= 8)
 	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
     else
@@ -162,7 +162,7 @@
     int rows,bytes=p->next_line;
     u32 eorx, fgx, bgx;
 
-    dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
+    dest0 = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
     c = scr_readw(s);
     fgx = attr_fgcol(p, c);
     bgx = attr_bgcol(p, c);
@@ -219,7 +219,7 @@
     u8 *dest;
     int bytes=p->next_line, rows;
 
-    dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
+    dest = p->fb_info->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
     for (rows = fontheight(p) ; rows-- ; dest += bytes) {
     	switch (fontwidth(p)) {
     	case 16: fb_writel(fb_readl(dest+12) ^ 0x0f0f0f0f, dest+12); /* fall thru */
@@ -244,10 +244,9 @@
     bgx=attr_bgcol_ec(p,conp);
 
     if (!bottom_only && (right_width = p->var.xres-right_start))
-	rectfill(p->screen_base+right_start, right_width, p->var.yres_virtual,
-		 bgx, bytes);
+	rectfill(p->fb_info->screen_base+right_start, right_width, p->var.yres_virtual, bgx, bytes);
     if ((bottom_width = p->var.yres-bottom_start))
-	rectfill(p->screen_base+(p->var.yoffset+bottom_start)*bytes,
+	rectfill(p->fb_info->screen_base+(p->var.yoffset+bottom_start)*bytes,
 		 right_start, bottom_width, bgx, bytes);
 }
 
diff -Nru a/drivers/video/fbcon-hga.c b/drivers/video/fbcon-hga.c
--- a/drivers/video/fbcon-hga.c	Thu May  2 17:22:16 2002
+++ b/drivers/video/fbcon-hga.c	Thu May  2 17:22:16 2002
@@ -38,7 +38,7 @@
 
 static inline u8* rowaddr(struct display *p, u_int row)
 {
-	return p->screen_base + HGA_ROWADDR(row);
+	return p->fb_info->screen_base + HGA_ROWADDR(row);
 }
 	
 void fbcon_hga_setup(struct display *p)
@@ -57,8 +57,8 @@
 	
 #if 0
 	if (sx == 0 && dx == 0 && width == p->next_line) {
-		src = p->screen_base+sy*fontheight(p)*width;
-		dest = p->screen_base+dy*fontheight(p)*width;
+		src = p->fb_info->screen_base+sy*fontheight(p)*width;
+		dest = p->fb_info->screen_base+dy*fontheight(p)*width;
 		fb_memmove(dest, src, height*fontheight(p)*width);
 	} else 
 #endif
diff -Nru a/drivers/video/fbcon-ilbm.c b/drivers/video/fbcon-ilbm.c
--- a/drivers/video/fbcon-ilbm.c	Thu May  2 17:22:16 2002
+++ b/drivers/video/fbcon-ilbm.c	Thu May  2 17:22:16 2002
@@ -45,24 +45,24 @@
 		      int height, int width)
 {
     if (sx == 0 && dx == 0 && width == p->next_plane)
-	fb_memmove(p->screen_base+dy*fontheight(p)*p->next_line,
-		  p->screen_base+sy*fontheight(p)*p->next_line,
+	fb_memmove(p->fb_info->screen_base+dy*fontheight(p)*p->next_line,
+		  p->fb_info->screen_base+sy*fontheight(p)*p->next_line,
 		  height*fontheight(p)*p->next_line);
     else {
 	u8 *src, *dest;
 	u_int i;
 
 	if (dy <= sy) {
-	    src = p->screen_base+sy*fontheight(p)*p->next_line+sx;
-	    dest = p->screen_base+dy*fontheight(p)*p->next_line+dx;
+	    src = p->fb_info->screen_base+sy*fontheight(p)*p->next_line+sx;
+	    dest = p->fb_info->screen_base+dy*fontheight(p)*p->next_line+dx;
 	    for (i = p->var.bits_per_pixel*height*fontheight(p); i--;) {
 		fb_memmove(dest, src, width);
 		src += p->next_plane;
 		dest += p->next_plane;
 	    }
 	} else {
-	    src = p->screen_base+(sy+height)*fontheight(p)*p->next_line+sx;
-	    dest = p->screen_base+(dy+height)*fontheight(p)*p->next_line+dx;
+	    src = p->fb_info->screen_base+(sy+height)*fontheight(p)*p->next_line+sx;
+	    dest = p->fb_info->screen_base+(dy+height)*fontheight(p)*p->next_line+dx;
 	    for (i = p->var.bits_per_pixel*height*fontheight(p); i--;) {
 		src -= p->next_plane;
 		dest -= p->next_plane;
@@ -79,7 +79,7 @@
     u_int i, rows;
     int bg, bg0;
 
-    dest = p->screen_base+sy*fontheight(p)*p->next_line+sx;
+    dest = p->fb_info->screen_base+sy*fontheight(p)*p->next_line+sx;
 
     bg0 = attr_bgcol_ec(p,conp);
     for (rows = height*fontheight(p); rows--;) {
@@ -102,7 +102,7 @@
     u8 d;
     int fg0, bg0, fg, bg;
 
-    dest = p->screen_base+yy*fontheight(p)*p->next_line+xx;
+    dest = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
     cdat = p->fontdata+(c&p->charmask)*fontheight(p);
     fg0 = attr_fgcol(p,c);
     bg0 = attr_bgcol(p,c);
@@ -153,7 +153,7 @@
     u32 d;
     int fg0, bg0, fg, bg;
 
-    dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
+    dest0 = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
     c1 = scr_readw(s);
     fg0 = attr_fgcol(p, c1);
     bg0 = attr_bgcol(p, c1);
@@ -235,7 +235,7 @@
     u_int rows, i;
     int mask;
 
-    dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
+    dest0 = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
     mask = p->fgcol ^ p->bgcol;
 
     /*
diff -Nru a/drivers/video/fbcon-iplan2p2.c b/drivers/video/fbcon-iplan2p2.c
--- a/drivers/video/fbcon-iplan2p2.c	Thu May  2 17:22:17 2002
+++ b/drivers/video/fbcon-iplan2p2.c	Thu May  2 17:22:17 2002
@@ -172,8 +172,8 @@
 	/*  Special (but often used) case: Moving whole lines can be
 	 *  done with memmove()
 	 */
-	fb_memmove(p->screen_base + dy * p->next_line * fontheight(p),
-		  p->screen_base + sy * p->next_line * fontheight(p),
+	fb_memmove(p->fb_info->screen_base + dy * p->next_line * fontheight(p),
+		  p->fb_info->screen_base + sy * p->next_line * fontheight(p),
 		  p->next_line * height * fontheight(p));
     } else {
 	int rows, cols;
@@ -194,8 +194,8 @@
 	if ((sx & 1) == (dx & 1)) {
 	    /* odd->odd or even->even */
 	    if (upwards) {
-		src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
-		dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
+		src = p->fb_info->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
+		dst = p->fb_info->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
 		if (sx & 1) {
 		    memmove_2p_col(dst, src, colsize, bytes);
 		    src += 3;
@@ -217,13 +217,13 @@
 		}
 	    } else {
 		if (!((sx+width-1) & 1)) {
-		    src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*4;
-		    dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*4;
+		    src = p->fb_info->screen_base + sy * linesize + ((sx+width-1)>>1)*4;
+		    dst = p->fb_info->screen_base + dy * linesize + ((dx+width-1)>>1)*4;
 		    memmove_2p_col(dst, src, colsize, bytes);
 		    --width;
 		}
-		src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
-		dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
+		src = p->fb_info->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
+		dst = p->fb_info->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
 		if (width > 1) {
 		    src += colsize * bytes + (sx & 1)*3;
 		    dst += colsize * bytes + (sx & 1)*3;
@@ -239,8 +239,8 @@
 	} else {
 	    /* odd->even or even->odd */
 	    if (upwards) {
-		src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
-		dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
+		src = p->fb_info->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
+		dst = p->fb_info->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
 		for (cols = width; cols > 0; --cols) {
 		    memmove_2p_col(dst, src, colsize, bytes);
 		    INC_2P(src);
@@ -249,8 +249,8 @@
 	    } else {
 		sx += width-1;
 		dx += width-1;
-		src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
-		dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
+		src = p->fb_info->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
+		dst = p->fb_info->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
 		for(cols = width; cols > 0; --cols) {
 		    memmove_2p_col(dst, src, colsize, bytes);
 		    DEC_2P(src);
@@ -286,13 +286,13 @@
 	else
 	    offset = sy * bytes * fontheight(p);
 	size = lines * bytes;
-	memset_even_2p(p->screen_base+offset, size, cval);
+	memset_even_2p(p->fb_info->screen_base+offset, size, cval);
     } else {
 	if (fontheightlog(p))
 	    offset = ((sy * bytes) << fontheightlog(p)) + (sx>>1)*4 + (sx & 1);
 	else
 	    offset = sy * bytes * fontheight(p) + (sx>>1)*4 + (sx & 1);
-	start = p->screen_base + offset;
+	start = p->fb_info->screen_base + offset;
 	pcval = expand2w(COLOR_2P(attr_bgcol_ec(p,conp)));
 
 	/*  Clears are split if the region starts at an odd column or
@@ -328,11 +328,11 @@
     u16 eorx, fgx, bgx, fdx;
 
     if (fontheightlog(p)) {
-	dest = (p->screen_base + ((yy * bytes) << fontheightlog(p)) +
+	dest = (p->fb_info->screen_base + ((yy * bytes) << fontheightlog(p)) +
 		(xx>>1)*4 + (xx & 1));
 	cdat = p->fontdata + ((c & p->charmask) << fontheightlog(p));
     } else {
-	dest = (p->screen_base + yy * bytes * fontheight(p) +
+	dest = (p->fb_info->screen_base + yy * bytes * fontheight(p) +
 		(xx>>1)*4 + (xx & 1));
 	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
     }
@@ -359,10 +359,10 @@
 
     bytes = p->next_line;
     if (fontheightlog(p))
-	dest0 = (p->screen_base + ((yy * bytes) << fontheightlog(p)) +
+	dest0 = (p->fb_info->screen_base + ((yy * bytes) << fontheightlog(p)) +
 		 (xx>>1)*4 + (xx & 1));
     else
-	dest0 = (p->screen_base + yy * bytes * fontheight(p) +
+	dest0 = (p->fb_info->screen_base + yy * bytes * fontheight(p) +
 		 (xx>>1)*4 + (xx & 1));
     c = scr_readw(s);
     fgx = expand2w(COLOR_2P(attr_fgcol(p, c)));
@@ -391,10 +391,9 @@
     int bytes;
 
     if (fontheightlog(p))
-	dest = (p->screen_base + ((yy * p->next_line) << fontheightlog(p)) +
-		(xx>>1)*4 + (xx & 1));
+	dest = (p->fb_info->screen_base + ((yy * p->next_line) << fontheightlog(p)) + (xx>>1)*4 + (xx & 1));
     else
-	dest = (p->screen_base + yy * p->next_line * fontheight(p) +
+	dest = (p->fb_info->screen_base + yy * p->next_line * fontheight(p) +
 		(xx>>1)*4 + (xx & 1));
     j = fontheight(p);
     bytes = p->next_line;
@@ -429,7 +428,7 @@
     }
     if (lines) {
 	cval = expand2l(COLOR_2P(attr_bgcol_ec(p,conp)));
-	memset_even_2p(p->screen_base+offset, lines * bytes, cval);
+	memset_even_2p(p->fb_info->screen_base+offset, lines * bytes, cval);
     }
 }
 
diff -Nru a/drivers/video/fbcon-iplan2p4.c b/drivers/video/fbcon-iplan2p4.c
--- a/drivers/video/fbcon-iplan2p4.c	Thu May  2 17:22:16 2002
+++ b/drivers/video/fbcon-iplan2p4.c	Thu May  2 17:22:16 2002
@@ -180,8 +180,8 @@
 	/*  Special (but often used) case: Moving whole lines can be
 	 *done with memmove()
 	 */
-	fb_memmove(p->screen_base + dy * p->next_line * fontheight(p),
-		  p->screen_base + sy * p->next_line * fontheight(p),
+	fb_memmove(p->fb_info->screen_base + dy * p->next_line * fontheight(p),
+		  p->fb_info->screen_base + sy * p->next_line * fontheight(p),
 		  p->next_line * height * fontheight(p));
     } else {
 	int rows, cols;
@@ -203,8 +203,8 @@
 	    /* odd->odd or even->even */
 
 	    if (upwards) {
-		src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
-		dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
+		src = p->fb_info->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
+		dst = p->fb_info->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
 		if (sx & 1) {
 		    memmove_4p_col(dst, src, colsize, bytes);
 		    src += 7;
@@ -226,13 +226,13 @@
 		}
 	    } else {
 		if (!((sx+width-1) & 1)) {
-		    src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*8;
-		    dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*8;
+		    src = p->fb_info->screen_base + sy * linesize + ((sx+width-1)>>1)*8;
+		    dst = p->fb_info->screen_base + dy * linesize + ((dx+width-1)>>1)*8;
 		    memmove_4p_col(dst, src, colsize, bytes);
 		    --width;
 		}
-		src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
-		dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
+		src = p->fb_info->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
+		dst = p->fb_info->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
 		if (width > 1) {
 		    src += colsize * bytes + (sx & 1)*7;
 		    dst += colsize * bytes + (sx & 1)*7;
@@ -250,8 +250,8 @@
 	/* odd->even or even->odd */
 
 	    if (upwards) {
-		src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
-		dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
+		src = p->fb_info->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
+		dst = p->fb_info->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
 		for(cols = width; cols > 0; --cols) {
 		    memmove_4p_col(dst, src, colsize, bytes);
 		    INC_4P(src);
@@ -260,8 +260,8 @@
 	    } else {
 		sx += width-1;
 		dx += width-1;
-		src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
-		dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
+		src = p->fb_info->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
+		dst = p->fb_info->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
 		for(cols = width; cols > 0; --cols) {
 		    memmove_4p_col(dst, src, colsize, bytes);
 		    DEC_4P(src);
@@ -296,13 +296,13 @@
 	else
 	    offset = sy * bytes * fontheight(p);
 	size = lines * bytes;
-	memset_even_4p(p->screen_base+offset, size, cval1, cval2);
+	memset_even_4p(p->fb_info->screen_base+offset, size, cval1, cval2);
     } else {
 	if (fontheightlog(p))
 	    offset = ((sy * bytes) << fontheightlog(p)) + (sx>>1)*8 + (sx & 1);
 	else
 	    offset = sy * bytes * fontheight(p) + (sx>>1)*8 + (sx & 1);
-	start = p->screen_base + offset;
+	start = p->fb_info->screen_base + offset;
 	pcval = expand4l(attr_bgcol_ec(p,conp));
 
 	/*  Clears are split if the region starts at an odd column or
@@ -338,11 +338,11 @@
     u32 eorx, fgx, bgx, fdx;
 
     if (fontheightlog(p)) {
-	dest = (p->screen_base + ((yy * bytes) << fontheightlog(p)) +
+	dest = (p->fb_info->screen_base + ((yy * bytes) << fontheightlog(p)) +
 		(xx>>1)*8 + (xx & 1));
 	cdat = p->fontdata + ((c & p->charmask) << fontheightlog(p));
     } else {
-	dest = (p->screen_base + yy * bytes * fontheight(p) +
+	dest = (p->fb_info->screen_base + yy * bytes * fontheight(p) +
 		(xx>>1)*8 + (xx & 1));
 	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
     }
@@ -369,10 +369,10 @@
 
     bytes = p->next_line;
     if (fontheightlog(p))
-	dest0 = (p->screen_base + ((yy * bytes) << fontheightlog(p)) +
+	dest0 = (p->fb_info->screen_base + ((yy * bytes) << fontheightlog(p)) +
 		 (xx>>1)*8 + (xx & 1));
     else
-	dest0 = (p->screen_base + yy * bytes * fontheight(p) +
+	dest0 = (p->fb_info->screen_base + yy * bytes * fontheight(p) +
 		 (xx>>1)*8 + (xx & 1));
     c = scr_readw(s);
     fgx = expand4l(attr_fgcol(p, c));
@@ -408,10 +408,10 @@
     int bytes;
 
     if (fontheightlog(p))
-	dest = (p->screen_base + ((yy * p->next_line) << fontheightlog(p)) +
+	dest = (p->fb_info->screen_base + ((yy * p->next_line) << fontheightlog(p)) +
 		(xx>>1)*8 + (xx & 1));
     else
-	dest = (p->screen_base + yy * p->next_line * fontheight(p) +
+	dest = (p->fb_info->screen_base + yy * p->next_line * fontheight(p) +
 		(xx>>1)*8 + (xx & 1));
     j = fontheight(p);
     bytes = p->next_line;
@@ -449,7 +449,7 @@
     }
     if (lines) {
 	expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2);
-	memset_even_4p(p->screen_base+offset, lines * bytes, cval1, cval2);
+	memset_even_4p(p->fb_info->screen_base+offset, lines * bytes, cval1, cval2);
     }
 }
 
diff -Nru a/drivers/video/fbcon-iplan2p8.c b/drivers/video/fbcon-iplan2p8.c
--- a/drivers/video/fbcon-iplan2p8.c	Thu May  2 17:22:16 2002
+++ b/drivers/video/fbcon-iplan2p8.c	Thu May  2 17:22:16 2002
@@ -212,8 +212,8 @@
 	/*  Special (but often used) case: Moving whole lines can be
 	 *  done with memmove()
 	 */
-	fast_memmove(p->screen_base + dy * p->next_line * fontheight(p),
-		     p->screen_base + sy * p->next_line * fontheight(p),
+	fast_memmove(p->fb_info->screen_base + dy * p->next_line * fontheight(p),
+		     p->fb_info->screen_base + sy * p->next_line * fontheight(p),
 		     p->next_line * height * fontheight(p));
      } else {
 	int rows, cols;
@@ -235,8 +235,8 @@
 	    /* odd->odd or even->even */
 
 	    if (upwards) {
-		src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
-		dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
+		src = p->fb_info->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
+		dst = p->fb_info->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
 		if (sx & 1) {
 		    memmove_8p_col(dst, src, colsize, bytes);
 		    src += 15;
@@ -259,13 +259,13 @@
 		}
 	    } else {
 		if (!((sx+width-1) & 1)) {
-		    src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*16;
-		    dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*16;
+		    src = p->fb_info->screen_base + sy * linesize + ((sx+width-1)>>1)*16;
+		    dst = p->fb_info->screen_base + dy * linesize + ((dx+width-1)>>1)*16;
 		    memmove_8p_col(dst, src, colsize, bytes);
 		    --width;
 		}
-		src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
-		dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
+		src = p->fb_info->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
+		dst = p->fb_info->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
 		if (width > 1) {
 		    src += colsize * bytes + (sx & 1)*15;
 		    dst += colsize * bytes + (sx & 1)*15;
@@ -282,8 +282,8 @@
 	/* odd->even or even->odd */
 
 	    if (upwards) {
-		src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
-		dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
+		src = p->fb_info->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
+		dst = p->fb_info->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
 		for(cols = width; cols > 0; --cols) {
 		    memmove_8p_col(dst, src, colsize, bytes);
 		    INC_8P(src);
@@ -292,8 +292,8 @@
 	    } else {
 		sx += width-1;
 		dx += width-1;
-		src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
-		dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
+		src = p->fb_info->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
+		dst = p->fb_info->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
 		for(cols = width; cols > 0; --cols) {
 		    memmove_8p_col(dst, src, colsize, bytes);
 		    DEC_8P(src);
@@ -328,13 +328,13 @@
 	else
 	    offset = sy * bytes * fontheight(p);
 	size    = lines * bytes;
-	memset_even_8p(p->screen_base+offset, size, cval1, cval2, cval3, cval4);
+	memset_even_8p(p->fb_info->screen_base+offset, size, cval1, cval2, cval3, cval4);
     } else {
 	if (fontheightlog(p))
 	    offset = ((sy * bytes) << fontheightlog(p)) + (sx>>1)*16 + (sx & 1);
 	else
 	    offset = sy * bytes * fontheight(p) + (sx>>1)*16 + (sx & 1);
-	start = p->screen_base + offset;
+	start = p->fb_info->screen_base + offset;
 	expand8dl(attr_bgcol_ec(p,conp), &pcval1, &pcval2);
 
 	/* Clears are split if the region starts at an odd column or
@@ -370,11 +370,11 @@
     u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
 
     if (fontheightlog(p)) {
-	dest = (p->screen_base + ((yy * bytes) << fontheightlog(p)) +
+	dest = (p->fb_info->screen_base + ((yy * bytes) << fontheightlog(p)) +
 		(xx>>1)*16 + (xx & 1));
 	cdat = p->fontdata + ((c & p->charmask) << fontheightlog(p));
     } else {
-	dest = (p->screen_base + yy * bytes * fontheight(p) +
+	dest = (p->fb_info->screen_base + yy * bytes * fontheight(p) +
 		(xx>>1)*16 + (xx & 1));
 	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
     }
@@ -401,10 +401,10 @@
 
     bytes = p->next_line;
     if (fontheightlog(p))
-	dest0 = (p->screen_base + ((yy * bytes) << fontheightlog(p)) +
+	dest0 = (p->fb_info->screen_base + ((yy * bytes) << fontheightlog(p)) +
 		 (xx>>1)*16 + (xx & 1));
     else
-	dest0 = (p->screen_base + yy * bytes * fontheight(p) +
+	dest0 = (p->fb_info->screen_base + yy * bytes * fontheight(p) +
 		 (xx>>1)*16 + (xx & 1));
 
     c = scr_readw(s);
@@ -442,10 +442,10 @@
     int bytes;
 
     if (fontheightlog(p))
-	dest = (p->screen_base + ((yy * p->next_line) << fontheightlog(p)) +
+	dest = (p->fb_info->screen_base + ((yy * p->next_line) << fontheightlog(p)) +
 		(xx>>1)*16 + (xx & 1));
     else
-	dest = (p->screen_base + yy * p->next_line * fontheight(p) +
+	dest = (p->fb_info->screen_base + yy * p->next_line * fontheight(p) +
 		(xx>>1)*16 + (xx & 1));
     j = fontheight(p);
     bytes = p->next_line;
@@ -485,7 +485,7 @@
     }
     if (lines) {
 	expand8ql(attr_bgcol_ec(p,conp), &cval1, &cval2, &cval3, &cval4);
-	memset_even_8p(p->screen_base+offset, lines * bytes,
+	memset_even_8p(p->fb_info->screen_base+offset, lines * bytes,
 		       cval1, cval2, cval3, cval4);
     }
 }
diff -Nru a/drivers/video/fbcon-mac.c b/drivers/video/fbcon-mac.c
--- a/drivers/video/fbcon-mac.c	Thu May  2 17:22:16 2002
+++ b/drivers/video/fbcon-mac.c	Thu May  2 17:22:16 2002
@@ -57,8 +57,8 @@
    int dl,dr,dt,db,dw,dlo;
    int move_up;
 
-   src = (u8 *) (p->screen_base + sy * fontheight(p) * p->next_line);
-   dest = (u8 *) (p->screen_base + dy * fontheight(p) * p->next_line);
+   src = (u8 *) (p->fb_info->screen_base + sy * fontheight(p) * p->next_line);
+   dest = (u8 *) (p->fb_info->screen_base + dy * fontheight(p) * p->next_line);
 
    if( sx == 0 && width == p->conp->vc_cols) {
      s = height * fontheight(p) * p->next_line;
@@ -197,7 +197,7 @@
 
    inverse = conp ? attr_reverse(p,conp->vc_attr) : 0;
    pixel = inverse ? PIXEL_WHITE_MAC : PIXEL_BLACK_MAC;
-   dest = (u8 *) (p->screen_base + sy * fontheight(p) * p->next_line);
+   dest = (u8 *) (p->fb_info->screen_base + sy * fontheight(p) * p->next_line);
 
    if( sx == 0 && width == p->conp->vc_cols) {
      s = height * fontheight(p) * p->next_line;
@@ -353,32 +353,32 @@
 
   switch (p->var.bits_per_pixel) {
   case 1:
-    dest = (u8 *) ((pixel_x >> 3) + p->screen_base + pixel_y * p->next_line);
+    dest = (u8 *) ((pixel_x >> 3) + p->fb_info->screen_base + pixel_y * p->next_line);
     bit = 0x80 >> (pixel_x & 7);
     plot_helper(dest, bit, bw);
     break;
 
   case 2:
-    dest = (u8 *) ((pixel_x >> 2) + p->screen_base + pixel_y * p->next_line);
+    dest = (u8 *) ((pixel_x >> 2) + p->fb_info->screen_base + pixel_y * p->next_line);
     bit = 0xC0 >> ((pixel_x & 3) << 1);
     plot_helper(dest, bit, bw);
     break;
 
   case 4:
-    dest = (u8 *) ((pixel_x >> 1) + p->screen_base + pixel_y * p->next_line);
+    dest = (u8 *) ((pixel_x >> 1) + p->fb_info->screen_base + pixel_y * p->next_line);
     bit = 0xF0 >> ((pixel_x & 1) << 2);
     plot_helper(dest, bit, bw);
     break;
 
   case 8:
-    dest = (u8 *) (pixel_x + p->screen_base + pixel_y * p->next_line);
+    dest = (u8 *) (pixel_x + p->fb_info->screen_base + pixel_y * p->next_line);
     bit = 0xFF;
     plot_helper(dest, bit, bw);
     break;
 
 /* FIXME: You can't access framebuffer directly like this! */
   case 16:
-    dest16 = (u16 *) ((pixel_x *2) + p->screen_base + pixel_y * p->next_line);
+    dest16 = (u16 *) ((pixel_x *2) + p->fb_info->screen_base + pixel_y * p->next_line);
     pix16 = 0xFFFF;
     switch (bw) {
     case PIXEL_BLACK_MAC:  *dest16 = ~pix16; break;
@@ -389,7 +389,7 @@
     break;
 
   case 32:
-    dest32 = (u32 *) ((pixel_x *4) + p->screen_base + pixel_y * p->next_line);
+    dest32 = (u32 *) ((pixel_x *4) + p->fb_info->screen_base + pixel_y * p->next_line);
     pix32 = 0xFFFFFFFF;
     switch (bw) {
     case PIXEL_BLACK_MAC:  *dest32 = ~pix32; break;
@@ -410,30 +410,30 @@
 
   switch (p->var.bits_per_pixel) {
   case 1:
-    dest = (u8 *) ((pixel_x / 8) + p->screen_base + pixel_y * p->next_line);
+    dest = (u8 *) ((pixel_x / 8) + p->fb_info->screen_base + pixel_y * p->next_line);
     bit = 0x80 >> (pixel_x & 7);
     pixel = *dest & bit;
     break;
   case 2:
-    dest = (u8 *) ((pixel_x / 4) + p->screen_base + pixel_y * p->next_line);
+    dest = (u8 *) ((pixel_x / 4) + p->fb_info->screen_base + pixel_y * p->next_line);
     bit = 0xC0 >> (pixel_x & 3);
     pixel = *dest & bit;
     break;
   case 4:
-    dest = (u8 *) ((pixel_x / 2) + p->screen_base + pixel_y * p->next_line);
+    dest = (u8 *) ((pixel_x / 2) + p->fb_info->screen_base + pixel_y * p->next_line);
     bit = 0xF0 >> (pixel_x & 1);
     pixel = *dest & bit;
     break;
   case 8:
-    dest = (u8 *) (pixel_x + p->screen_base + pixel_y * p->next_line);
+    dest = (u8 *) (pixel_x + p->fb_info->screen_base + pixel_y * p->next_line);
     pixel = *dest;
     break;
   case 16:
-    dest16 = (u16 *) ((pixel_x *2) + p->screen_base + pixel_y * p->next_line);
+    dest16 = (u16 *) ((pixel_x *2) + p->fb_info->screen_base + pixel_y * p->next_line);
     pixel = *dest16 ? 1 : 0;
     break;
   case 32:
-    dest32 = (u32 *) ((pixel_x *4) + p->screen_base + pixel_y * p->next_line);
+    dest32 = (u32 *) ((pixel_x *4) + p->fb_info->screen_base + pixel_y * p->next_line);
     pixel = *dest32 ? 1 : 0;
     break;
   }
diff -Nru a/drivers/video/fbcon-mfb.c b/drivers/video/fbcon-mfb.c
--- a/drivers/video/fbcon-mfb.c	Thu May  2 17:22:17 2002
+++ b/drivers/video/fbcon-mfb.c	Thu May  2 17:22:17 2002
@@ -39,20 +39,20 @@
     u_int rows;
 
     if (sx == 0 && dx == 0 && width == p->next_line) {
-	src = p->screen_base+sy*fontheight(p)*width;
-	dest = p->screen_base+dy*fontheight(p)*width;
+	src = p->fb_info->screen_base+sy*fontheight(p)*width;
+	dest = p->fb_info->screen_base+dy*fontheight(p)*width;
 	fb_memmove(dest, src, height*fontheight(p)*width);
     } else if (dy <= sy) {
-	src = p->screen_base+sy*fontheight(p)*p->next_line+sx;
-	dest = p->screen_base+dy*fontheight(p)*p->next_line+dx;
+	src = p->fb_info->screen_base+sy*fontheight(p)*p->next_line+sx;
+	dest = p->fb_info->screen_base+dy*fontheight(p)*p->next_line+dx;
 	for (rows = height*fontheight(p); rows--;) {
 	    fb_memmove(dest, src, width);
 	    src += p->next_line;
 	    dest += p->next_line;
 	}
     } else {
-	src = p->screen_base+((sy+height)*fontheight(p)-1)*p->next_line+sx;
-	dest = p->screen_base+((dy+height)*fontheight(p)-1)*p->next_line+dx;
+	src = p->fb_info->screen_base+((sy+height)*fontheight(p)-1)*p->next_line+sx;
+	dest = p->fb_info->screen_base+((dy+height)*fontheight(p)-1)*p->next_line+dx;
 	for (rows = height*fontheight(p); rows--;) {
 	    fb_memmove(dest, src, width);
 	    src -= p->next_line;
@@ -68,7 +68,7 @@
     u_int rows;
     int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
 
-    dest = p->screen_base+sy*fontheight(p)*p->next_line+sx;
+    dest = p->fb_info->screen_base+sy*fontheight(p)*p->next_line+sx;
 
     if (sx == 0 && width == p->next_line) {
 	if (inverse)
@@ -90,7 +90,7 @@
     u_int rows, bold, revs, underl;
     u8 d;
 
-    dest = p->screen_base+yy*fontheight(p)*p->next_line+xx;
+    dest = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
     cdat = p->fontdata+(c&p->charmask)*fontheight(p);
     bold = attr_bold(p,c);
     revs = attr_reverse(p,c);
@@ -116,7 +116,7 @@
     u8 d;
     u16 c;
 
-    dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
+    dest0 = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
     c = scr_readw(s);
     bold = attr_bold(p, c);
     revs = attr_reverse(p, c);
@@ -144,7 +144,7 @@
     u8 *dest, d;
     u_int rows;
 
-    dest = p->screen_base+yy*fontheight(p)*p->next_line+xx;
+    dest = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
     for (rows = fontheight(p); rows--; dest += p->next_line) {
     	d = fb_readb(dest);
 	fb_writeb (~d, dest);
@@ -166,7 +166,7 @@
     bottom = conp->vc_rows + p->yscroll;
     if (bottom >= p->vrows)
 	bottom -= p->vrows;
-    dest = p->screen_base + bottom * fontheight(p) * p->next_line;
+    dest = p->fb_info->screen_base + bottom * fontheight(p) * p->next_line;
     if (inverse)
 	fb_memset255(dest, height * p->next_line);
     else
diff -Nru a/drivers/video/fbcon-sti.c b/drivers/video/fbcon-sti.c
--- a/drivers/video/fbcon-sti.c	Thu May  2 17:22:17 2002
+++ b/drivers/video/fbcon-sti.c	Thu May  2 17:22:17 2002
@@ -158,20 +158,20 @@
 	u_int rows;
 
 	if (sx == 0 && dx == 0 && width == p->next_line) {
-		src = p->screen_base+sy*fontheight(p)*width;
-		dest = p->screen_base+dy*fontheight(p)*width;
+		src = p->fb_info->screen_base+sy*fontheight(p)*width;
+		dest = p->fb_info->screen_base+dy*fontheight(p)*width;
 		memcpy_fromhp_tohp(dest, src, height*fontheight(p)*width);
 	} else if (dy <= sy) {
-		src = p->screen_base+sy*fontheight(p)*p->next_line+sx;
-		dest = p->screen_base+dy*fontheight(p)*p->next_line+dx;
+		src = p->fb_info->screen_base+sy*fontheight(p)*p->next_line+sx;
+		dest = p->fb_info->screen_base+dy*fontheight(p)*p->next_line+dx;
 		for (rows = height*fontheight(p); rows--;) {
 			memcpy_fromhp_tohp(dest, src, width);
 			src += p->next_line;
 			dest += p->next_line;
 		}
 	} else {
-		src = p->screen_base+((sy+height)*fontheight(p)-1)*p->next_line+sx;
-		dest = p->screen_base+((dy+height)*fontheight(p)-1)*p->next_line+dx;
+		src = p->fb_info->screen_base+((sy+height)*fontheight(p)-1)*p->next_line+sx;
+		dest = p->fb_info->screen_base+((dy+height)*fontheight(p)-1)*p->next_line+dx;
 		for (rows = height*fontheight(p); rows--;) {
 			memcpy_fromhp_tohp(dest, src, width);
 			src -= p->next_line;
@@ -190,7 +190,7 @@
 	u_int rows;
 	int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
 
-	dest = p->screen_base+sy*fontheight(p)*p->next_line+sx;
+	dest = p->fb_info->screen_base+sy*fontheight(p)*p->next_line+sx;
 
 	if (sx == 0 && width == p->next_line) {
 		if (inverse)
@@ -213,7 +213,7 @@
 	u_int rows, bold, revs, underl;
 	u8 d;
 
-	dest = p->screen_base+yy*fontheight(p)*p->next_line+xx;
+	dest = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
 	cdat = p->fontdata+(c&p->charmask)*fontheight(p);
 	bold = attr_bold(p,c);
 	revs = attr_reverse(p,c);
@@ -248,11 +248,11 @@
 	}	
 
 
-	dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
+	dest0 = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
 	if(((u32)dest0&0xf0000000)!=0xf0000000) {
 		printk("refusing to putcs %p %p %p %d %d %d (%p) %p = %p + %d * %d * %ld + %d\n",
 			conp, p, s, count, yy, xx, __builtin_return_address(0),
-			dest0, p->screen_base, yy, fontheight(p), p->next_line,
+			dest0, p->fb_info->screen_base, yy, fontheight(p), p->next_line,
 			xx);
 		return;
 	}	
@@ -286,7 +286,7 @@
 	u_int rows;
 
 
-	dest = p->screen_base+yy*fontheight(p)*p->next_line+xx;
+	dest = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
 	for (rows = fontheight(p); rows--; dest += p->next_line) {
 		d = readb_hp(dest);
 		writeb_hp (~d, dest);
@@ -311,7 +311,7 @@
 	bottom = conp->vc_rows + p->yscroll;
 	if (bottom >= p->vrows)
 		bottom -= p->vrows;
-	dest = p->screen_base + bottom * fontheight(p) * p->next_line;
+	dest = p->fb_info->screen_base + bottom * fontheight(p) * p->next_line;
 	if (inverse)
 		memset_tohp(dest, 0xffffffff, height * p->next_line);
 	else
diff -Nru a/drivers/video/fbcon-vga-planes.c b/drivers/video/fbcon-vga-planes.c
--- a/drivers/video/fbcon-vga-planes.c	Thu May  2 17:22:17 2002
+++ b/drivers/video/fbcon-vga-planes.c	Thu May  2 17:22:17 2002
@@ -120,8 +120,8 @@
 
 	if (dy < sy || (dy == sy && dx < sx)) {
 		line_ofs = p->line_length - width;
-		dest = p->screen_base + dx + dy * p->line_length;
-		src = p->screen_base + sx + sy * p->line_length;
+		dest = p->fb_info->screen_base + dx + dy * p->line_length;
+		src = p->fb_info->screen_base + sx + sy * p->line_length;
 		while (height--) {
 			for (x = 0; x < width; x++) {
 				readb(src);
@@ -134,8 +134,8 @@
 		}
 	} else {
 		line_ofs = p->line_length - width;
-		dest = p->screen_base + dx + width + (dy + height - 1) * p->line_length;
-		src = p->screen_base + sx + width + (sy + height - 1) * p->line_length;
+		dest = p->fb_info->screen_base + dx + width + (dy + height - 1) * p->line_length;
+		src = p->fb_info->screen_base + sx + width + (sy + height - 1) * p->line_length;
 		while (height--) {
 			for (x = 0; x < width; x++) {
 				dest--;
@@ -167,7 +167,7 @@
 	sy *= fontheight(p);
 	height *= fontheight(p);
 
-	where = p->screen_base + sx + sy * p->line_length;
+	where = p->fb_info->screen_base + sx + sy * p->line_length;
 	while (height--) {
 		for (x = 0; x < width; x++) {
 			writeb(0, where);
@@ -184,7 +184,7 @@
 
 	int y;
 	u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
-	char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+	char *where = p->fb_info->screen_base + xx + yy * p->line_length * fontheight(p);
 
 	setmode(0);
 	setop(0);
@@ -213,7 +213,7 @@
 
 	int y;
 	u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
-	char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+	char *where = p->fb_info->screen_base + xx + yy * p->line_length * fontheight(p);
 
 	setmode(2);
 	setop(0);
@@ -248,7 +248,7 @@
 	selectmask();
 
 	setmask(0xff);
-	where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+	where = p->fb_info->screen_base + xx + yy * p->line_length * fontheight(p);
 	writeb(bg, where);
 	rmb();
 	readb(where); /* fill latches */
@@ -289,7 +289,7 @@
 	selectmask();
 
 	setmask(0xff);
-	where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+	where = p->fb_info->screen_base + xx + yy * p->line_length * fontheight(p);
 	writeb(bg, where);
 	rmb();
 	readb(where); /* fill latches */
@@ -312,7 +312,7 @@
 
 void fbcon_vga_planes_revc(struct display *p, int xx, int yy)
 {
-	char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+	char *where = p->fb_info->screen_base + xx + yy * p->line_length * fontheight(p);
 	int y;
 	
 	setmode(0);
diff -Nru a/drivers/video/fbcon-vga.c b/drivers/video/fbcon-vga.c
--- a/drivers/video/fbcon-vga.c	Thu May  2 17:22:15 2002
+++ b/drivers/video/fbcon-vga.c	Thu May  2 17:22:15 2002
@@ -103,20 +103,20 @@
     int rows;
 
     if (sx == 0 && dx == 0 && width == p->next_line/2) {
-	src = (u16 *)(p->screen_base+sy*p->next_line);
-	dst = (u16 *)(p->screen_base+dy*p->next_line);
+	src = (u16 *)(p->fb_info->screen_base+sy*p->next_line);
+	dst = (u16 *)(p->fb_info->screen_base+dy*p->next_line);
 	vga_memmovew(dst, src, height*width);
     } else if (dy < sy || (dy == sy && dx < sx)) {
-	src = (u16 *)(p->screen_base+sy*p->next_line+sx*2);
-	dst = (u16 *)(p->screen_base+dy*p->next_line+dx*2);
+	src = (u16 *)(p->fb_info->screen_base+sy*p->next_line+sx*2);
+	dst = (u16 *)(p->fb_info->screen_base+dy*p->next_line+dx*2);
 	for (rows = height; rows-- ;) {
 	    vga_memmovew(dst, src, width);
 	    src += p->next_line/2;
 	    dst += p->next_line/2;
 	}
     } else {
-	src = (u16 *)(p->screen_base+(sy+height-1)*p->next_line+sx*2);
-	dst = (u16 *)(p->screen_base+(dy+height-1)*p->next_line+dx*2);
+	src = (u16 *)(p->fb_info->screen_base+(sy+height-1)*p->next_line+sx*2);
+	dst = (u16 *)(p->fb_info->screen_base+(dy+height-1)*p->next_line+dx*2);
 	for (rows = height; rows-- ;) {
 	    vga_memmovew(dst, src, width);
 	    src -= p->next_line/2;
@@ -128,7 +128,7 @@
 void fbcon_vga_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 		     int height, int width)
 {
-    u16 *dest = (u16 *)(p->screen_base+sy*p->next_line+sx*2);
+    u16 *dest = (u16 *)(p->fb_info->screen_base+sy*p->next_line+sx*2);
     int rows;
 
     if (sx == 0 && width*2 == p->next_line)      
@@ -141,7 +141,7 @@
 void fbcon_vga_putc(struct vc_data *conp, struct display *p, int c, int y,
 		    int x)
 {
-    u16 *dst = (u16 *)(p->screen_base+y*p->next_line+x*2);
+    u16 *dst = (u16 *)(p->fb_info->screen_base+y*p->next_line+x*2);
     if (conp->vc_can_do_color)
     	vga_writew(c, dst);
     else
@@ -151,7 +151,7 @@
 void fbcon_vga_putcs(struct vc_data *conp, struct display *p, 
 		     const unsigned short *s, int count, int y, int x)
 {
-    u16 *dst = (u16 *)(p->screen_base+y*p->next_line+x*2);
+    u16 *dst = (u16 *)(p->fb_info->screen_base+y*p->next_line+x*2);
     u16 sattr;
     if (conp->vc_can_do_color)
     	while (count--)
@@ -165,7 +165,7 @@
 
 void fbcon_vga_revc(struct display *p, int x, int y)
 {
-    u16 *dst = (u16 *)(p->screen_base+y*p->next_line+x*2);
+    u16 *dst = (u16 *)(p->fb_info->screen_base+y*p->next_line+x*2);
     u16 val = vga_readw(dst);
     val = (val & 0x88ff) | ((val<<4) & 0x7000) | ((val>>4) & 0x0700);
     vga_writew(val, dst);
diff -Nru a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c
--- a/drivers/video/fm2fb.c	Thu May  2 17:22:16 2002
+++ b/drivers/video/fm2fb.c	Thu May  2 17:22:16 2002
@@ -356,7 +356,6 @@
 	disp.cmap.start = 0;
 	disp.cmap.len = 0;
 	disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
-	disp.screen_base = (char *)fm2fb_mem;
 	disp.visual = fb_fix.visual;
 	disp.type = fb_fix.type;
 	disp.type_aux = fb_fix.type_aux;
@@ -376,6 +375,7 @@
 	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';
diff -Nru a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
--- a/drivers/video/matrox/matroxfb_base.c	Thu May  2 17:22:17 2002
+++ b/drivers/video/matrox/matroxfb_base.c	Thu May  2 17:22:17 2002
@@ -68,7 +68,7 @@
  *               "Samuel Hocevar" <sam@via.ecp.fr>
  *                     Fixes
  *
- *               "Anton Altaparmakov" <AntonA@bigfoot.com>
+ *               "Anton Altaparmakov"
  *                     G400 MAX/non-MAX distinction
  *
  *               "Ken Aaker" <kdaaker@rchland.vnet.ibm.com>
diff -Nru a/drivers/video/neofb.c b/drivers/video/neofb.c
--- a/drivers/video/neofb.c	Thu May  2 17:22:15 2002
+++ b/drivers/video/neofb.c	Thu May  2 17:22:15 2002
@@ -1535,7 +1535,6 @@
 
   fb->fix.line_length = display->next_line;
 
-  display->screen_base    = fb->screen_base;
   display->line_length    = fb->fix.line_length;
   display->visual         = fb->fix.visual;
   display->type	          = fb->fix.type;
diff -Nru a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
--- a/drivers/video/pm2fb.c	Thu May  2 17:22:17 2002
+++ b/drivers/video/pm2fb.c	Thu May  2 17:22:17 2002
@@ -129,7 +129,7 @@
 
 static char curblink __initdata = 1;
 
-static const struct {
+static struct {
 	char name[16];
 	struct pm2fb_par par;
 } user_mode[] __initdata = {
diff -Nru a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c
--- a/drivers/video/retz3fb.c	Thu May  2 17:22:17 2002
+++ b/drivers/video/retz3fb.c	Thu May  2 17:22:17 2002
@@ -1219,7 +1219,6 @@
 			struct fb_fix_screeninfo fix;
 			retz3fb_get_fix(&fix, con, info);
 
-			display->screen_base = zinfo->fbmem;
 			display->visual = fix.visual;
 			display->type = fix.type;
 			display->type_aux = fix.type_aux;
diff -Nru a/drivers/video/sbusfb.c b/drivers/video/sbusfb.c
--- a/drivers/video/sbusfb.c	Thu May  2 17:22:16 2002
+++ b/drivers/video/sbusfb.c	Thu May  2 17:22:16 2002
@@ -804,9 +804,10 @@
     struct fb_info_sbusfb *fb = sbusfbinfo(info);
     
     if (blank && fb->blank)
-    	return fb->blank(fb);
+	    return fb->blank(fb);
     else if (!blank && fb->unblank)
-    	return fb->unblank(fb);
+	    return fb->unblank(fb);
+    return 0;
 }
 
     /*
diff -Nru a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
--- a/drivers/video/sis/sis_main.c	Thu May  2 17:22:17 2002
+++ b/drivers/video/sis/sis_main.c	Thu May  2 17:22:17 2002
@@ -579,7 +579,6 @@
 
 	sisfb_get_fix (&fix, con, 0);
 
-	display->screen_base = ivideo.video_vbase;
 	display->visual = fix.visual;
 	display->type = fix.type;
 	display->type_aux = fix.type_aux;
@@ -2769,6 +2768,7 @@
 	fb_info.changevar = NULL;
 	fb_info.node = NODEV;
 	fb_info.fbops = &sisfb_ops;
+	fb_info.screen_base = ivideo.video_vbase;
 	fb_info.disp = &disp;
 	fb_info.currcon = -1;
 	fb_info.switch_con = &sisfb_switch;
diff -Nru a/fs/attr.c b/fs/attr.c
--- a/fs/attr.c	Thu May  2 17:22:16 2002
+++ b/fs/attr.c	Thu May  2 17:22:16 2002
@@ -134,7 +134,7 @@
 		attr->ia_mtime = now;
 	if (ia_valid & ATTR_KILL_SUID) {
 		if (mode & S_ISUID) {
-			if (!ia_valid & ATTR_MODE) {
+			if (!(ia_valid & ATTR_MODE)) {
 				ia_valid = attr->ia_valid |= ATTR_MODE;
 				attr->ia_mode = inode->i_mode;
 			}
@@ -143,7 +143,7 @@
 	}
 	if (ia_valid & ATTR_KILL_SGID) {
 		if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
-			if (!ia_valid & ATTR_MODE) {
+			if (!(ia_valid & ATTR_MODE)) {
 				ia_valid = attr->ia_valid |= ATTR_MODE;
 				attr->ia_mode = inode->i_mode;
 			}
diff -Nru a/fs/autofs/inode.c b/fs/autofs/inode.c
--- a/fs/autofs/inode.c	Thu May  2 17:22:17 2002
+++ b/fs/autofs/inode.c	Thu May  2 17:22:17 2002
@@ -61,7 +61,7 @@
 
 	if ( !options ) return 1;
 	while ((this_char = strsep(&options,",")) != NULL) {
-		if (!*value)
+		if (!*this_char)
 			continue;
 		if ((value = strchr(this_char,'=')) != NULL)
 			*value++ = 0;
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Thu May  2 17:22:17 2002
+++ b/fs/block_dev.c	Thu May  2 17:22:17 2002
@@ -25,13 +25,13 @@
 
 #define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
 
-static unsigned long max_block(kdev_t dev)
+static unsigned long max_block(struct block_device *bdev)
 {
 	unsigned int retval = ~0U;
-	loff_t sz = blkdev_size_in_bytes(dev);
+	loff_t sz = bdev->bd_inode->i_size;
 
 	if (sz) {
-		unsigned int size = block_size(dev);
+		unsigned int size = block_size(bdev);
 		unsigned int sizebits = blksize_bits(size);
 		retval = (sz >> sizebits);
 	}
@@ -53,10 +53,10 @@
 	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
 }	
 
-int set_blocksize(kdev_t dev, int size)
+int set_blocksize(struct block_device *bdev, int size)
 {
 	int oldsize;
-	struct block_device *bdev;
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
 
 	/* Size must be a power of two, and between 512 and PAGE_SIZE */
 	if (size > PAGE_SIZE || size < 512 || (size & (size-1)))
@@ -66,36 +66,22 @@
 	if (size < get_hardsect_size(dev))
 		return -EINVAL;
 
-	/* No blocksize array? Implies hardcoded BLOCK_SIZE */
-	if (!blksize_size[major(dev)]) {
-		if (size == BLOCK_SIZE)
-			return 0;
-		return -EINVAL;
-	}
-
-	oldsize = blksize_size[major(dev)][minor(dev)];
+	oldsize = bdev->bd_block_size;
 	if (oldsize == size)
 		return 0;
 
-	if (!oldsize && size == BLOCK_SIZE) {
-		blksize_size[major(dev)][minor(dev)] = size;
-		return 0;
-	}
-
 	/* Ok, we're actually changing the blocksize.. */
-	bdev = bdget(kdev_t_to_nr(dev));
 	sync_blockdev(bdev);
-	blksize_size[major(dev)][minor(dev)] = size;
+	bdev->bd_block_size = size;
 	bdev->bd_inode->i_blkbits = blksize_bits(size);
 	kill_bdev(bdev);
-	bdput(bdev);
 	return 0;
 }
 
 int sb_set_blocksize(struct super_block *sb, int size)
 {
 	int bits;
-	if (set_blocksize(sb->s_dev, size) < 0)
+	if (set_blocksize(sb->s_bdev, size) < 0)
 		return 0;
 	sb->s_blocksize = size;
 	for (bits = 9, size >>= 9; size >>= 1; bits++)
@@ -114,7 +100,7 @@
 
 static int blkdev_get_block(struct inode * inode, sector_t iblock, struct buffer_head * bh, int create)
 {
-	if (iblock >= max_block(inode->i_rdev))
+	if (iblock >= max_block(inode->i_bdev))
 		return -EIO;
 
 	bh->b_bdev = inode->i_bdev;
@@ -333,7 +319,6 @@
 		struct inode *inode = new_inode(bd_mnt->mnt_sb);
 		if (inode) {
 			kdev_t kdev = to_kdev_t(dev);
-			unsigned long *ra_pages;
 
 			atomic_set(&new_bdev->bd_count,1);
 			new_bdev->bd_dev = dev;
@@ -346,10 +331,7 @@
 			inode->i_bdev = new_bdev;
 			inode->i_data.a_ops = &def_blk_aops;
 			inode->i_data.gfp_mask = GFP_USER;
-			ra_pages = blk_get_ra_pages(kdev);
-			if (ra_pages == NULL)
-				ra_pages = &default_ra_pages;
-			inode->i_data.ra_pages = ra_pages;
+			inode->i_data.ra_pages = &default_ra_pages;
 			spin_lock(&bdev_lock);
 			bdev = bdfind(dev, head);
 			if (!bdev) {
@@ -612,14 +594,29 @@
 			}
 		}
 	}
+	if (bdev->bd_inode->i_data.ra_pages == &default_ra_pages) {
+		unsigned long *ra_pages = blk_get_ra_pages(bdev);
+		if (ra_pages == NULL)
+			ra_pages = &default_ra_pages;
+		inode->i_data.ra_pages = ra_pages;
+	}
 	if (bdev->bd_op->open) {
 		ret = bdev->bd_op->open(inode, file);
 		if (ret)
 			goto out2;
 	}
-	bdev->bd_openers++;
 	bdev->bd_inode->i_size = blkdev_size(dev);
-	bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev));
+	if (!bdev->bd_openers) {
+		unsigned bsize = bdev_hardsect_size(bdev);
+		while (bsize < PAGE_CACHE_SIZE) {
+			if (bdev->bd_inode->i_size & bsize)
+				break;
+			bsize <<= 1;
+		}
+		bdev->bd_block_size = bsize;
+		bdev->bd_inode->i_blkbits = blksize_bits(bsize);
+	}
+	bdev->bd_openers++;
 	unlock_kernel();
 	up(&bdev->bd_sem);
 	return 0;
@@ -627,6 +624,7 @@
 out2:
 	if (!bdev->bd_openers) {
 		bdev->bd_op = NULL;
+		bdev->bd_inode->i_data.ra_pages = &default_ra_pages;
 		if (bdev != bdev->bd_contains) {
 			blkdev_put(bdev->bd_contains, BDEV_RAW);
 			bdev->bd_contains = NULL;
@@ -700,6 +698,7 @@
 		__MOD_DEC_USE_COUNT(bdev->bd_op->owner);
 	if (!bdev->bd_openers) {
 		bdev->bd_op = NULL;
+		bdev->bd_inode->i_data.ra_pages = &default_ra_pages;
 		if (bdev != bdev->bd_contains) {
 			blkdev_put(bdev->bd_contains, BDEV_RAW);
 			bdev->bd_contains = NULL;
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Thu May  2 17:22:15 2002
+++ b/fs/buffer.c	Thu May  2 17:22:15 2002
@@ -439,21 +439,6 @@
 	return ret;
 }
 
-struct buffer_head *get_hash_table(kdev_t dev, sector_t block, int size)
-{
-	struct block_device *bdev;
-	struct buffer_head *bh;
-	bdev = bdget(kdev_t_to_nr(dev));
-	if (!bdev) {
-		printk("No block device for %s\n", __bdevname(dev));
-		BUG();
-	}
-	bh = __get_hash_table(bdev, block, size);
-	atomic_dec(&bdev->bd_count);
-	return bh;
-}
-EXPORT_SYMBOL(get_hash_table);
-
 void buffer_insert_list(spinlock_t *lock,
 		struct buffer_head *bh, struct list_head *list)
 {
@@ -988,21 +973,6 @@
 	}
 }
 
-struct buffer_head *getblk(kdev_t dev, sector_t block, int size)
-{
-	struct block_device *bdev;
-	struct buffer_head *bh;
-	bdev = bdget(kdev_t_to_nr(dev));
-	if (!bdev) {
-		printk("No block device for %s\n", __bdevname(dev));
-		BUG();
-	}
-	bh = __getblk(bdev, block, size);
-	atomic_dec(&bdev->bd_count);
-	return bh;
-}
-EXPORT_SYMBOL(getblk);
-
 /*
  * The relationship between dirty buffers and dirty pages:
  *
@@ -1071,7 +1041,7 @@
 }
 
 /**
- *  bread() - reads a specified block and returns the bh
+ *  __bread() - reads a specified block and returns the bh
  *  @block: number of block
  *  @size: size (in bytes) to read
  * 
@@ -1102,21 +1072,6 @@
 	return NULL;
 }
 
-struct buffer_head *bread(kdev_t dev, int block, int size)
-{
-	struct block_device *bdev;
-	struct buffer_head *bh;
-	bdev = bdget(kdev_t_to_nr(dev));
-	if (!bdev) {
-		printk("No block device for %s\n", __bdevname(dev));
-		BUG();
-	}
-	bh = __bread(bdev, block, size);
-	atomic_dec(&bdev->bd_count);
-	return bh;
-}
-EXPORT_SYMBOL(bread);
-
 void set_bh_page(struct buffer_head *bh,
 		struct page *page, unsigned long offset)
 {
@@ -1231,6 +1186,7 @@
 
 	return 1;
 }
+EXPORT_SYMBOL(block_flushpage);
 
 /*
  * We attach and possibly dirty the buffers atomically wrt
@@ -2154,8 +2110,12 @@
 	 * ->i_size will be enough for everything) and zero it out.
 	 * OTOH it's obviously correct and should make the page up-to-date.
 	 */
-	err = mapping->a_ops->readpage(NULL, page);
-	wait_on_page_locked(page);
+	if (!PageUptodate(page)) {
+		err = mapping->a_ops->readpage(NULL, page);
+		wait_on_page_locked(page);
+	} else {
+		unlock_page(page);
+	}
 	page_cache_release(page);
 	if (err < 0)
 		goto fail;
diff -Nru a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
--- a/fs/exportfs/expfs.c	Thu May  2 17:22:16 2002
+++ b/fs/exportfs/expfs.c	Thu May  2 17:22:16 2002
@@ -34,7 +34,7 @@
 
 #define	CALL(ops,fun) ((ops->fun)?(ops->fun):export_op_default.fun)
 
-#define dprintk(x, ...) do{}while(0)
+#define dprintk(x, a...) do{}while(0)
 
 struct dentry *
 find_exported_dentry(struct super_block *sb, void *obj, void *parent,
diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c
--- a/fs/ext2/inode.c	Thu May  2 17:22:16 2002
+++ b/fs/ext2/inode.c	Thu May  2 17:22:16 2002
@@ -591,6 +591,8 @@
 	commit_write: generic_commit_write,
 	bmap: ext2_bmap,
 	direct_IO: ext2_direct_IO,
+	writeback_mapping: generic_writeback_mapping,
+	vm_writeback: generic_vm_writeback,
 };
 
 /*
diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c
--- a/fs/ext3/super.c	Thu May  2 17:22:17 2002
+++ b/fs/ext3/super.c	Thu May  2 17:22:17 2002
@@ -1330,7 +1330,7 @@
 	
 	sb_block = EXT3_MIN_BLOCK_SIZE / blocksize;
 	offset = EXT3_MIN_BLOCK_SIZE % blocksize;
-	set_blocksize(j_dev, blocksize);
+	set_blocksize(bdev, blocksize);
 	if (!(bh = __bread(bdev, sb_block, blocksize))) {
 		printk(KERN_ERR "EXT3-fs: couldn't read superblock of "
 		       "external journal\n");
diff -Nru a/fs/fs-writeback.c b/fs/fs-writeback.c
--- a/fs/fs-writeback.c	Thu May  2 17:22:17 2002
+++ b/fs/fs-writeback.c	Thu May  2 17:22:17 2002
@@ -219,7 +219,7 @@
 	struct list_head * tmp;
 	LIST_HEAD(hold);	/* Unready inodes go here */
 
-	while ((tmp = head->next) != head) {
+	while ((tmp = head->prev) != head) {
 		struct inode *inode = list_entry(tmp, struct inode, i_list);
 		struct address_space *mapping = inode->i_mapping;
 		int really_sync;
diff -Nru a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c	Thu May  2 17:22:16 2002
+++ b/fs/namei.c	Thu May  2 17:22:16 2002
@@ -324,6 +324,12 @@
 	if (mode & MAY_EXEC)
 		return 0;
 
+	if ((inode->i_mode & S_IXUGO) && capable(CAP_DAC_OVERRIDE))
+		return 0;
+
+	if (S_ISDIR(inode->i_mode) && capable(CAP_DAC_READ_SEARCH))
+		return 0;
+
 	return -EACCES;
 }
 
diff -Nru a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
--- a/fs/nfs/mount_clnt.c	Thu May  2 17:22:15 2002
+++ b/fs/nfs/mount_clnt.c	Thu May  2 17:22:15 2002
@@ -13,7 +13,6 @@
 #include <linux/uio.h>
 #include <linux/net.h>
 #include <linux/in.h>
-#include <linux/inet.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/xprt.h>
 #include <linux/sunrpc/sched.h>
@@ -69,7 +68,7 @@
 	dprintk("NFS:      nfs_mount(%08x:%s)\n",
 			(unsigned)ntohl(addr->sin_addr.s_addr), path);
 
-	strcpy(hostname, in_ntoa(addr->sin_addr.s_addr));
+	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr->sin_addr.s_addr));
 	if (!(mnt_clnt = mnt_create(hostname, addr, version)))
 		return -EACCES;
 
diff -Nru a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
--- a/fs/nfs/nfsroot.c	Thu May  2 17:22:17 2002
+++ b/fs/nfs/nfsroot.c	Thu May  2 17:22:17 2002
@@ -78,7 +78,6 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/in.h>
-#include <linux/inet.h>
 #include <linux/major.h>
 #include <linux/utsname.h>
 #include <net/ipconfig.h>
@@ -281,7 +280,8 @@
 		return -1;
 	}
 
-	strncpy(nfs_data.hostname, in_ntoa(servaddr), sizeof(nfs_data.hostname)-1);
+	snprintf(nfs_data.hostname, sizeof(nfs_data.hostname),
+		 "%u.%u.%u.%u", NIPQUAD(servaddr));
 	return 0;
 }
 
diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
--- a/fs/ntfs/ChangeLog	Thu May  2 17:22:16 2002
+++ b/fs/ntfs/ChangeLog	Thu May  2 17:22:16 2002
@@ -27,6 +27,18 @@
 	  quite big. Modularising them a bit, e.g. a-la get_block(), will make
 	  them cleaner and make code reuse easier.
 
+2.0.5 - Major bugfix. Buffer overflow in extent inode handling.
+
+	- No need to set old blocksize in super.c::ntfs_fill_super() as the
+	  VFS does so via invocation of deactivate_super() calling
+	  fs->fill_super() calling block_kill_super() which does it.
+	- BKL moved from VFS into dir.c::ntfs_readdir(). (Linus Torvalds)
+	  -> Do we really need it? I don't think so as we have exclusion on
+	  the directory ntfs_inode rw_semaphore mrec_lock. We mmight have to
+	  move the ->f_pos accesses under the mrec_lock though. Check this...
+	- Fix really, really, really stupid buffer overflow in extent inode
+	  handling in mft.c::map_extent_mft_record().
+
 2.0.4 - Cleanups and updates for kernel 2.5.11.
 
 	- Add documentation on how to use the MD driver to be able to use NTFS
@@ -35,7 +47,7 @@
 	Remove all uses of kdev_t in favour of struct block_device *:
 	- Change compress.c::ntfs_file_read_compressed_block() to use
 	  sb_getblk() instead of getblk().
-	- Change super.c::ntfs_fill_suoer() to use bdev_hardsect_size() instead
+	- Change super.c::ntfs_fill_super() to use bdev_hardsect_size() instead
 	  of get_hardsect_size().
 	- No need to get old blocksize in super.c::ntfs_fill_super() as
 	  fs/super.c::get_sb_bdev() already does this.
diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile
--- a/fs/ntfs/Makefile	Thu May  2 17:22:15 2002
+++ b/fs/ntfs/Makefile	Thu May  2 17:22:15 2002
@@ -7,7 +7,7 @@
 
 obj-m   := $(O_TARGET)
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.4\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.5\"
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c
--- a/fs/ntfs/inode.c	Thu May  2 17:22:16 2002
+++ b/fs/ntfs/inode.c	Thu May  2 17:22:16 2002
@@ -1191,7 +1191,8 @@
 				"for $MFT/$DATA. Driver bug or "
 				"corrupt $MFT. Run chkdsk.");
 		ntfs_debug("highest_vcn = 0x%Lx, last_vcn - 1 = 0x%Lx",
-				(long long)highest_vcn, (long long)last_vcn - 1);
+				(long long)highest_vcn,
+				(long long)last_vcn - 1);
 		goto put_err_out;
 	}
 	put_attr_search_ctx(ctx);
diff -Nru a/fs/ntfs/mft.c b/fs/ntfs/mft.c
--- a/fs/ntfs/mft.c	Thu May  2 17:22:16 2002
+++ b/fs/ntfs/mft.c	Thu May  2 17:22:16 2002
@@ -459,7 +459,7 @@
 		goto unm_err_out;
 	}
 	/* Attach extent inode to base inode, reallocating memory if needed. */
-	if (!(base_ni->nr_extents & ~3)) {
+	if (!(base_ni->nr_extents & 3)) {
 		ntfs_inode **tmp;
 		int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *);
 
diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c
--- a/fs/ntfs/super.c	Thu May  2 17:22:16 2002
+++ b/fs/ntfs/super.c	Thu May  2 17:22:16 2002
@@ -1555,7 +1555,7 @@
 	if (sb_set_blocksize(sb, NTFS_BLOCK_SIZE) != NTFS_BLOCK_SIZE) {
 		if (!silent)
 			ntfs_error(sb, "Unable to set block size.");
-		goto set_blk_size_err_out_now;
+		goto err_out_now;
 	}
 
 	/* Get the size of the device in units of NTFS_BLOCK_SIZE bytes. */
@@ -1565,7 +1565,7 @@
 	if (!(bh = read_ntfs_boot_sector(sb, silent))) {
 		if (!silent)
 			ntfs_error(sb, "Not an NTFS volume.");
-		goto set_blk_size_err_out_now;
+		goto err_out_now;
 	}
 	
 	/*
@@ -1579,7 +1579,7 @@
 	if (!result) {
 		if (!silent)
 			ntfs_error(sb, "Unsupported NTFS filesystem.");
-		goto set_blk_size_err_out_now;
+		goto err_out_now;
 	}
 
 	/* 
@@ -1750,10 +1750,7 @@
 		printk("VFS: Busy inodes after umount. Self-destruct in 5 "
 				"seconds.  Have a nice day...\n");
 	}
-set_blk_size_err_out_now:
 	/* Errors at this stage are irrelevant. */
-	// FIXME: This should be done in fs/super.c::get_sb_bdev() itself! (AIA)
-	sb_set_blocksize(sb, sb->s_old_blocksize);
 err_out_now:
 	sb->u.generic_sbp = NULL;
 	kfree(vol);
@@ -1936,7 +1933,7 @@
 }
 
 EXPORT_NO_SYMBOLS;
-MODULE_AUTHOR("Anton Altaparmakov <aia21@cam.ac.uk>");
+MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>");
 MODULE_DESCRIPTION("NTFS 1.2/3.x driver");
 MODULE_LICENSE("GPL");
 #ifdef DEBUG
diff -Nru a/fs/ntfs/upcase.c b/fs/ntfs/upcase.c
--- a/fs/ntfs/upcase.c	Thu May  2 17:22:15 2002
+++ b/fs/ntfs/upcase.c	Thu May  2 17:22:15 2002
@@ -3,7 +3,7 @@
  *	      Part of the Linux-NTFS project.
  *
  * Copyright (C) 2001 Richard Russon <ntfs@flatcap.org>
- * Copyright (c) 2001 Anton Altaparmakov <aia21@cam.ac.uk>
+ * Copyright (c) 2001,2002 Anton Altaparmakov
  *
  * Modified for mkntfs inclusion 9 June 2001 by Anton Altaparmakov.
  * Modified for kernel inclusion 10 September 2001 by Anton Altparmakov.
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Thu May  2 17:22:16 2002
+++ b/fs/partitions/check.c	Thu May  2 17:22:16 2002
@@ -253,7 +253,16 @@
 	bdev = bdget(kdev_t_to_nr(dev));
 	bdev->bd_contains = bdev;
 	bdev->bd_inode->i_size = (loff_t)hd->part[minor(dev)].nr_sects << 9;
-	bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev));
+	if (!bdev->bd_openers) {
+		unsigned bsize = bdev_hardsect_size(bdev);
+		while (bsize < PAGE_CACHE_SIZE) {
+			if (bdev->bd_inode->i_size & bsize)
+				break;
+			bsize <<= 1;
+		}
+		bdev->bd_block_size = bsize;
+		bdev->bd_inode->i_blkbits = blksize_bits(bsize);
+	}
 	for (i = 0; check_part[i]; i++) {
 		int res;
 		res = check_part[i](hd, bdev, first_sector, first_part_minor);
@@ -477,12 +486,6 @@
 		g->part[minor].start_sect = 0;
 		g->part[minor].nr_sects = 0;
 	}
-
-	/* some places do blksize_size[major][minor] = 1024,
-	   as preparation for reading partition table - superfluous */
-	/* sd.c used to set blksize_size to 2048 in case
-	   rscsi_disks[target].device->sector_size == 2048 */
-
 	return 0;
 }
 
diff -Nru a/fs/partitions/efi.c b/fs/partitions/efi.c
--- a/fs/partitions/efi.c	Thu May  2 17:22:15 2002
+++ b/fs/partitions/efi.c	Thu May  2 17:22:15 2002
@@ -713,21 +713,20 @@
 	      unsigned long first_sector, int first_part_minor)
 {
 
-	kdev_t dev = to_kdev_t(bdev->bd_dev);
 	int hardblocksize = bdev_hardsect_size(bdev);
-	int orig_blksize_size = block_size(dev);
+	int orig_blksize_size = block_size(bdev);
 	int rc = 0;
 
 	/* Need to change the block size that the block layer uses */
 
 	if (orig_blksize_size != hardblocksize)
-		set_blocksize(dev, hardblocksize);
+		set_blocksize(bdev, hardblocksize);
 
 	rc = add_gpt_partitions(hd, bdev, first_part_minor);
 
 	/* change back */
 	if (orig_blksize_size != hardblocksize)
-		set_blocksize(dev, orig_blksize_size);
+		set_blocksize(bdev, orig_blksize_size);
 
 	return rc;
 }
diff -Nru a/fs/partitions/ldm.c b/fs/partitions/ldm.c
--- a/fs/partitions/ldm.c	Thu May  2 17:22:16 2002
+++ b/fs/partitions/ldm.c	Thu May  2 17:22:16 2002
@@ -2,7 +2,7 @@
  * ldm - Part of the Linux-NTFS project.
  *
  * Copyright (C) 2001 Richard Russon <ldm@flatcap.org>
- * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net> (AIA)
+ * Copyright (C) 2001 Anton Altaparmakov (AIA)
  *
  * Documentation is available at http://linux-ntfs.sf.net/ldm
  *
diff -Nru a/fs/partitions/ldm.h b/fs/partitions/ldm.h
--- a/fs/partitions/ldm.h	Thu May  2 17:22:16 2002
+++ b/fs/partitions/ldm.h	Thu May  2 17:22:16 2002
@@ -4,7 +4,7 @@
  * ldm - Part of the Linux-NTFS project.
  *
  * Copyright (C) 2001 Richard Russon <ldm@flatcap.org>
- * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net>
+ * Copyright (C) 2001 Anton Altaparmakov
  *
  * Documentation is available at http://linux-ntfs.sf.net/ldm
  *
diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Thu May  2 17:22:16 2002
+++ b/fs/proc/proc_misc.c	Thu May  2 17:22:16 2002
@@ -159,7 +159,7 @@
 		"SwapTotal:    %8lu kB\n"
 		"SwapFree:     %8lu kB\n"
 		"Dirty:        %8lu kB\n"
-		"Locked:       %8lu kB\n",
+		"Writeback:    %8lu kB\n",
 		K(i.totalram),
 		K(i.freeram),
 		K(i.sharedram),
@@ -175,7 +175,7 @@
 		K(i.totalswap),
 		K(i.freeswap),
 		K(ps.nr_dirty),
-		K(ps.nr_locked)
+		K(ps.nr_writeback)
 		);
 
 	return proc_calc_metrics(page, start, off, count, eof, len);
diff -Nru a/fs/super.c b/fs/super.c
--- a/fs/super.c	Thu May  2 17:22:17 2002
+++ b/fs/super.c	Thu May  2 17:22:17 2002
@@ -516,7 +516,7 @@
 	} else {
 		s->s_flags = flags;
 		strncpy(s->s_id, bdevname(bdev), sizeof(s->s_id));
-		s->s_old_blocksize = block_size(dev);
+		s->s_old_blocksize = block_size(bdev);
 		sb_set_blocksize(s, s->s_old_blocksize);
 		error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
 		if (error) {
@@ -540,7 +540,7 @@
 {
 	struct block_device *bdev = sb->s_bdev;
 	generic_shutdown_super(sb);
-	set_blocksize(to_kdev_t(bdev->bd_dev), sb->s_old_blocksize);
+	set_blocksize(bdev, sb->s_old_blocksize);
 	bd_release(bdev);
 	blkdev_put(bdev, BDEV_FS);
 }
diff -Nru a/fs/udf/ecma_167.h b/fs/udf/ecma_167.h
--- a/fs/udf/ecma_167.h	Thu May  2 17:22:16 2002
+++ b/fs/udf/ecma_167.h	Thu May  2 17:22:16 2002
@@ -606,7 +606,7 @@
 #define FE_RECORD_FMT_CRLF		0x0A
 #define FE_RECORD_FMT_LFCR		0x0B
 
-#define Record Display Attributes (ECMA 167r3 4/14.9.8) */
+/* Record Display Attributes (ECMA 167r3 4/14.9.8) */
 #define FE_RECORD_DISPLAY_ATTR_UNDEF	0x00
 #define FE_RECORD_DISPLAY_ATTR_1	0x01
 #define FE_RECORD_DISPLAY_ATTR_2	0x02
diff -Nru a/fs/ufs/super.c b/fs/ufs/super.c
--- a/fs/ufs/super.c	Thu May  2 17:22:15 2002
+++ b/fs/ufs/super.c	Thu May  2 17:22:15 2002
@@ -651,16 +651,34 @@
 	uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask);
 	uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift);
 
-	/* block size must be a power-of-two between 4k and 32k */
-	if ((uspi->s_bsize & (uspi->s_bsize-1)) ||
-	    (uspi->s_bsize < 4096 || uspi->s_bsize > 32768)) {
-		printk("ufs_read_super: fs_bsize %u != {4096, 8192, 16384, 32768}\n", uspi->s_bsize);
+	if (uspi->s_fsize & (uspi->s_fsize - 1)) {
+		printk("ufs_read_super: fragment size %u is not a power of 2\n",
+			uspi->s_fsize);
+			goto failed;
+	}
+	if (uspi->s_fsize < 512) {
+		printk("ufs_read_super: fragment size %u is too small\n"
+			uspi->s_fsize);
+		goto failed;
+	}
+	if (uspi->s_fsize > 4096) {
+		printk("ufs_read_super: fragment size %u is too large\n"
+			uspi->s_fsize);
+		goto failed;
+	}
+	if (uspi->s_bsize & (uspi->s_bsize - 1)) {
+		printk("ufs_read_super: block size %u is not a power of 2\n",
+			uspi->s_bsize);
+		goto failed;
+	}
+	if (uspi->s_bsize < 4096) {
+		printk("ufs_read_super: block size %u is too small\n"
+			uspi->s_fsize);
 		goto failed;
 	}
-	/* fragment size must be a power-of-two between 512 and 4096 bytes */
-	if ((uspi->s_fsize & (uspi->s_fsize-1)) ||
-	    (uspi->s_fsize < 512 || uspi->s_fsize > 4096)) {
-		printk("ufs_read_super: fs_fsize %u != {512, 1024, 2048. 4096}\n", uspi->s_fsize);
+	if (uspi->s_bsize / uspi->s_fsize > 8) {
+		printk("ufs_read_super: too many fragments per block (%u)\n"
+			uspi->s_bsize / uspi->s_fsize);
 		goto failed;
 	}
 	if (uspi->s_fsize != block_size || uspi->s_sbsize != super_block_size) {
diff -Nru a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
--- a/include/asm-arm/arch-pxa/pxa-regs.h	Thu May  2 17:22:17 2002
+++ b/include/asm-arm/arch-pxa/pxa-regs.h	Thu May  2 17:22:17 2002
@@ -361,7 +361,7 @@
 #define LSR_OE		(1 << 1)	/* Overrun Error */
 #define LSR_DR		(1 << 0)	/* Data Ready */
 
-#define MCR_LOOP	(1 << 4)	*/
+#define MCR_LOOP	(1 << 4)
 #define MCR_OUT2	(1 << 3)	/* force MSR_DCD in loopback mode */
 #define MCR_OUT1	(1 << 2)	/* force MSR_RI in loopback mode */
 #define MCR_RTS		(1 << 1)	/* Request to Send */
diff -Nru a/include/asm-ppc64/Naca.h b/include/asm-ppc64/Naca.h
--- a/include/asm-ppc64/Naca.h	Thu May  2 17:22:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,39 +0,0 @@
-#ifndef _NACA_H
-#define _NACA_H
-
-/* 
- * c 2001 PPC 64 Team, IBM Corp
- *
- * 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 <asm/types.h>
-
-struct Naca
-{
-	void *xItVpdAreas;
-	void *xRamDisk;
-	u64 xRamDiskSize;		/* In pages */
-	struct Paca *paca;		/* Ptr to an array of pacas */
-	u64 debug_switch;		/* Bits to control debug printing */
-	u16 processorCount;		/* # of physical processors */
-	u16 dCacheL1LineSize;		/* Line size of L1 DCache in bytes */
-	u16 dCacheL1LogLineSize;	/* Log-2 of DCache line size */
-	u16 dCacheL1LinesPerPage;	/* DCache lines per page */
-	u16 iCacheL1LineSize;		/* Line size of L1 ICache in bytes */
-	u16 iCacheL1LogLineSize;	/* Log-2 of ICache line size */
-	u16 iCacheL1LinesPerPage;	/* ICache lines per page */
-	u16 slb_size;			/* SLB size in entries */
-	u64 physicalMemorySize;		/* Size of real memory in bytes */
-	u64 pftSize;			/* Log base 2 of page table size */
-	u64 serialPortAddr;		/* Phyical address of serial port */
-	u8 interrupt_controller;	/* Type of interrupt controller */ 
-	u8 resv0[6];			/* Padding */
-};
-
-extern struct Naca *naca;
-
-#endif /* _NACA_H */
diff -Nru a/include/asm-ppc64/Paca.h b/include/asm-ppc64/Paca.h
--- a/include/asm-ppc64/Paca.h	Thu May  2 17:22:16 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,164 +0,0 @@
-#ifndef _PPC64_PACA_H
-#define _PPC64_PACA_H
-
-/*============================================================================
- *                                                         Header File Id
- * Name______________:	Paca.H
- *
- * Description_______:
- *
- * This control block defines the PACA which defines the processor 
- * specific data for each logical processor on the system.  
- * There are some pointers defined that are utilized by PLIC.
- *
- * C 2001 PPC 64 Team, IBM Corp
- *
- * 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	<asm/types.h>
-
-#define N_EXC_STACK    2
-
-/*-----------------------------------------------------------------------------
- * Other Includes
- *-----------------------------------------------------------------------------
- */
-#include	<asm/iSeries/ItLpPaca.h>
-#include	<asm/iSeries/ItLpRegSave.h>
-#include	<asm/iSeries/ItLpQueue.h>
-#include	<asm/rtas.h>
-#include	<asm/mmu.h>
-#include	<asm/processor.h>
-
-/* A Paca entry is required for each logical processor.  On systems
- * that support hardware multi-threading, this is equal to twice the
- * number of physical processors.  On LPAR systems, we are required
- * to have space for the maximum number of logical processors we
- * could ever possibly have.  Currently, we are limited to allocating
- * 24 processors to a partition which gives 48 logical processors on
- * an HMT box.  Therefore, we reserve this many Paca entries.
- */
-#define maxProcessors 24
-#define maxPacas maxProcessors * 2
-
-extern struct Paca   xPaca[];
-#define get_paca() ((struct Paca *)mfspr(SPRG3))
-
-/*============================================================================
- * Name_______:	Paca
- *
- * Description:
- *
- *	Defines the layout of the Paca.  
- *
- *	This structure is not directly accessed by PLIC or the SP except
- *	for the first two pointers that point to the ItLpPaca area and the
- *	ItLpRegSave area for this processor.  Both the ItLpPaca and
- *	ItLpRegSave objects are currently contained within the
- *	PACA but they do not need to be.
- *
- *============================================================================
- */
-struct Paca
-{
-/*=====================================================================================
- * CACHE_LINE_1 0x0000 - 0x007F
- *=====================================================================================
- */
-	struct ItLpPaca *xLpPacaPtr;	/* Pointer to LpPaca for PLIC		0x00 */
-	struct ItLpRegSave *xLpRegSavePtr; /* Pointer to LpRegSave for PLIC	0x08 */
-	u64 xCurrent;  		        /* Pointer to current			0x10 */
-	u16 xPacaIndex;			/* Logical processor number		0x18 */
-	u16 xHwProcNum;			/* Actual Hardware Processor Number	0x1a */
-	u32 default_decr;		/* Default decrementer value		0x1c */	
-	u64 xHrdIntStack;		/* Stack for hardware interrupts	0x20 */
-	u64 xKsave;			/* Saved Kernel stack addr or zero	0x28 */
-	u64 pvr;			/* Processor version register		0x30 */
-	u8 *exception_sp;		/*					0x38 */
-
-	struct ItLpQueue *lpQueuePtr;	/* LpQueue handled by this processor    0x40 */
-	u64  xTOC;			/* Kernel TOC address			0x48 */
-	STAB xStab_data;		/* Segment table information		0x50,0x58,0x60 */
-	u8 xSegments[STAB_CACHE_SIZE];	/* Cache of used stab entries		0x68,0x70 */
-	u8 xProcEnabled;		/* 1=soft enabled			0x78 */
-	u8 xHrdIntCount;		/* Count of active hardware interrupts  0x79  */
-	u8 prof_enabled;		/* 1=iSeries profiling enabled          0x7A */
-	u8 resv1[5];			/*					0x7B-0x7F */
-
-/*=====================================================================================
- * CACHE_LINE_2 0x0080 - 0x00FF
- *=====================================================================================
- */
-	u64 spare1;			/*					0x00 */
-	u64 spare2;			/*					0x08 */
-	u64 spare3;			/*					0x10 */
-	u64 spare4;		/*					0x18 */
-	u64 next_jiffy_update_tb;	/* TB value for next jiffy update	0x20 */
-	u32 lpEvent_count;		/* lpEvents processed			0x28 */
-	u32 prof_multiplier;		/*					0x2C */
-	u32 prof_counter;		/*					0x30 */
-	u32 prof_shift;			/* iSeries shift for profile bucket size0x34 */
-	u32 *prof_buffer;		/* iSeries profiling buffer		0x38 */
-	u32 *prof_stext;		/* iSeries start of kernel text		0x40 */
-	u32 prof_len;			/* iSeries length of profile buffer -1	0x48 */
-	u8  rsvd2[128-76];		/*					0x4C */
-
-/*=====================================================================================
- * CACHE_LINE_3 0x0100 - 0x017F
- *=====================================================================================
- */
-	u8		xProcStart;	/* At startup, processor spins until	0x100 */
-  					/* xProcStart becomes non-zero. */
-	u8		rsvd3[127];
-
-/*=====================================================================================
- * CACHE_LINE_4-8  0x0180 - 0x03FF Contains ItLpPaca
- *=====================================================================================
- */
-	struct ItLpPaca xLpPaca;	/* Space for ItLpPaca */
-
-/*=====================================================================================
- * CACHE_LINE_9-16 0x0400 - 0x07FF Contains ItLpRegSave
- *=====================================================================================
- */
-	struct ItLpRegSave xRegSav;	/* Register save for proc */
-
-/*=====================================================================================
- * CACHE_LINE_17-18 0x0800 - 0x0EFF Reserved
- *=====================================================================================
- */
-	struct rtas_args xRtas;		/* Per processor RTAS struct */
-	u64 xR1;			/* r1 save for RTAS calls */
-	u64 xSavedMsr;			/* Old msr saved here by HvCall */
-	u8 rsvd5[256-16-sizeof(struct rtas_args)];
-
-/*=====================================================================================
- * CACHE_LINE_19-30 0x0800 - 0x0EFF Reserved
- *=====================================================================================
- */
-	u8 rsvd6[0x600];
-
-/*=====================================================================================
- * CACHE_LINE_31 0x0F00 - 0x0F7F Exception stack
- *=====================================================================================
- */
-	u8 exception_stack[N_EXC_STACK*EXC_FRAME_SIZE];
-
-/*=====================================================================================
- * CACHE_LINE_32 0x0F80 - 0x0FFF Reserved
- *=====================================================================================
- */
-	u8 rsvd7[0x80];                  /* Give the stack some rope ... */
-
-/*=====================================================================================
- * Page 2 Reserved for guard page.  Also used as a stack early in SMP boots before
- *        relocation is enabled.
- *=====================================================================================
- */
-	u8 guard[0x1000];               /* ... and then hang 'em         */ 
-};
-
-#endif /* _PPC64_PACA_H */
diff -Nru a/include/asm-ppc64/atomic.h b/include/asm-ppc64/atomic.h
--- a/include/asm-ppc64/atomic.h	Thu May  2 17:22:17 2002
+++ b/include/asm-ppc64/atomic.h	Thu May  2 17:22:17 2002
@@ -41,6 +41,7 @@
 	int t;
 
 	__asm__ __volatile__(
+	EIEIO_ON_SMP
 "1:	lwarx	%0,0,%2		# atomic_add_return\n\
 	add	%0,%1,%0\n\
 	stwcx.	%0,0,%2\n\
@@ -72,6 +73,7 @@
 	int t;
 
 	__asm__ __volatile__(
+	EIEIO_ON_SMP
 "1:	lwarx	%0,0,%2		# atomic_sub_return\n\
 	subf	%0,%1,%0\n\
 	stwcx.	%0,0,%2\n\
@@ -103,6 +105,7 @@
 	int t;
 
 	__asm__ __volatile__(
+	EIEIO_ON_SMP
 "1:	lwarx	%0,0,%1		# atomic_inc_return\n\
 	addic	%0,%0,1\n\
 	stwcx.	%0,0,%1\n\
@@ -134,6 +137,7 @@
 	int t;
 
 	__asm__ __volatile__(
+	EIEIO_ON_SMP
 "1:	lwarx	%0,0,%1		# atomic_dec_return\n\
 	addic	%0,%0,-1\n\
 	stwcx.	%0,0,%1\n\
@@ -158,6 +162,7 @@
 	int t;
 
 	__asm__ __volatile__(
+	EIEIO_ON_SMP
 "1:	lwarx	%0,0,%1		# atomic_dec_if_positive\n\
 	addic.	%0,%0,-1\n\
 	blt-	2f\n\
diff -Nru a/include/asm-ppc64/bitops.h b/include/asm-ppc64/bitops.h
--- a/include/asm-ppc64/bitops.h	Thu May  2 17:22:17 2002
+++ b/include/asm-ppc64/bitops.h	Thu May  2 17:22:17 2002
@@ -41,12 +41,12 @@
 #define smp_mb__before_clear_bit()	smp_mb()
 #define smp_mb__after_clear_bit()	smp_mb()
 
-static __inline__ int test_bit(unsigned long nr, __const__ volatile void *addr)
+static __inline__ int test_bit(unsigned long nr, __const__ volatile unsigned long *addr)
 {
 	return (1UL & (((__const__ long *) addr)[nr >> 6] >> (nr & 63)));
 }
 
-static __inline__ void set_bit(unsigned long nr, volatile void *addr)
+static __inline__ void set_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	unsigned long old;
 	unsigned long mask = 1UL << (nr & 0x3f);
@@ -62,7 +62,7 @@
 	: "cc");
 }
 
-static __inline__ void clear_bit(unsigned long nr, volatile void *addr)
+static __inline__ void clear_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	unsigned long old;
 	unsigned long mask = 1UL << (nr & 0x3f);
@@ -78,7 +78,7 @@
 	: "cc");
 }
 
-static __inline__ void change_bit(unsigned long nr, volatile void *addr)
+static __inline__ void change_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	unsigned long old;
 	unsigned long mask = 1UL << (nr & 0x3f);
@@ -94,7 +94,7 @@
 	: "cc");
 }
 
-static __inline__ int test_and_set_bit(unsigned long nr, volatile void *addr)
+static __inline__ int test_and_set_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	unsigned long old, t;
 	unsigned long mask = 1UL << (nr & 0x3f);
@@ -114,7 +114,7 @@
 	return (old & mask) != 0;
 }
 
-static __inline__ int test_and_clear_bit(unsigned long nr, volatile void *addr)
+static __inline__ int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	unsigned long old, t;
 	unsigned long mask = 1UL << (nr & 0x3f);
@@ -134,7 +134,7 @@
 	return (old & mask) != 0;
 }
 
-static __inline__ int test_and_change_bit(unsigned long nr, volatile void *addr)
+static __inline__ int test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	unsigned long old, t;
 	unsigned long mask = 1UL << (nr & 0x3f);
@@ -157,7 +157,7 @@
 /*
  * non-atomic versions
  */
-static __inline__ void __set_bit(unsigned long nr, volatile void *addr)
+static __inline__ void __set_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	unsigned long mask = 1UL << (nr & 0x3f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
@@ -165,7 +165,7 @@
 	*p |= mask;
 }
 
-static __inline__ void __clear_bit(unsigned long nr, volatile void *addr)
+static __inline__ void __clear_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	unsigned long mask = 1UL << (nr & 0x3f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
@@ -173,7 +173,7 @@
 	*p &= ~mask;
 }
 
-static __inline__ void __change_bit(unsigned long nr, volatile void *addr)
+static __inline__ void __change_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	unsigned long mask = 1UL << (nr & 0x3f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
@@ -181,7 +181,7 @@
 	*p ^= mask;
 }
 
-static __inline__ int __test_and_set_bit(unsigned long nr, volatile void *addr)
+static __inline__ int __test_and_set_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	unsigned long mask = 1UL << (nr & 0x3f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
@@ -191,7 +191,7 @@
 	return (old & mask) != 0;
 }
 
-static __inline__ int __test_and_clear_bit(unsigned long nr, volatile void *addr)
+static __inline__ int __test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	unsigned long mask = 1UL << (nr & 0x3f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
@@ -201,7 +201,7 @@
 	return (old & mask) != 0;
 }
 
-static __inline__ int __test_and_change_bit(unsigned long nr, volatile void *addr)
+static __inline__ int __test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	unsigned long mask = 1UL << (nr & 0x3f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
@@ -267,19 +267,19 @@
 #define hweight16(x) generic_hweight16(x)
 #define hweight8(x) generic_hweight8(x)
 
-extern unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset);
+extern unsigned long find_next_zero_bit(unsigned long *addr, unsigned long size, unsigned long offset);
 #define find_first_zero_bit(addr, size) \
 	find_next_zero_bit((addr), (size), 0)
 
-extern unsigned long find_next_bit(void *addr, unsigned long size, unsigned long offset);
+extern unsigned long find_next_bit(unsigned long *addr, unsigned long size, unsigned long offset);
 #define find_first_bit(addr, size) \
 	find_next_bit((addr), (size), 0)
 
-extern unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset);
+extern unsigned long find_next_zero_le_bit(unsigned long *addr, unsigned long size, unsigned long offset);
 #define find_first_zero_le_bit(addr, size) \
 	find_next_zero_le_bit((addr), (size), 0)
 
-static __inline__ int test_le_bit(unsigned long nr, __const__ void * addr)
+static __inline__ int test_le_bit(unsigned long nr, __const__ unsigned long * addr)
 {
 	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
 	return (ADDR[nr >> 3] >> (nr & 7)) & 1;
@@ -288,7 +288,7 @@
 /*
  * non-atomic versions
  */
-static __inline__ void __set_le_bit(unsigned long nr, void *addr)
+static __inline__ void __set_le_bit(unsigned long nr, unsigned long *addr)
 {
 	unsigned char *ADDR = (unsigned char *)addr;
 
@@ -296,7 +296,7 @@
 	*ADDR |= 1 << (nr & 0x07);
 }
 
-static __inline__ void __clear_le_bit(unsigned long nr, void *addr)
+static __inline__ void __clear_le_bit(unsigned long nr, unsigned long *addr)
 {
 	unsigned char *ADDR = (unsigned char *)addr;
 
@@ -304,7 +304,7 @@
 	*ADDR &= ~(1 << (nr & 0x07));
 }
 
-static __inline__ int __test_and_set_le_bit(unsigned long nr, void *addr)
+static __inline__ int __test_and_set_le_bit(unsigned long nr, unsigned long *addr)
 {
 	int mask, retval;
 	unsigned char *ADDR = (unsigned char *)addr;
@@ -316,7 +316,7 @@
 	return retval;
 }
 
-static __inline__ int __test_and_clear_le_bit(unsigned long nr, void *addr)
+static __inline__ int __test_and_clear_le_bit(unsigned long nr, unsigned long *addr)
 {
 	int mask, retval;
 	unsigned char *ADDR = (unsigned char *)addr;
@@ -328,11 +328,15 @@
 	return retval;
 }
 
-#define ext2_set_bit			__test_and_set_le_bit
-#define ext2_clear_bit			__test_and_clear_le_bit
-#define ext2_test_bit			test_le_bit
-#define ext2_find_first_zero_bit	find_first_zero_le_bit
-#define ext2_find_next_zero_bit		find_next_zero_le_bit
+#define ext2_set_bit(nr,addr) \
+	__test_and_set_le_bit((nr),(unsigned long*)addr)
+#define ext2_clear_bit(nr, addr) \
+	__test_and_clear_le_bit((nr),(unsigned long*)addr)
+#define ext2_test_bit(nr, addr)      test_le_bit((nr),(unsigned long*)addr)
+#define ext2_find_first_zero_bit(addr, size) \
+	find_first_zero_le_bit((unsigned long*)addr, size)
+#define ext2_find_next_zero_bit(addr, size, off) \
+	find_next_zero_le_bit((unsigned long*)addr, size, off)
 
 #define minix_test_and_set_bit(nr,addr)		test_and_set_bit(nr,addr)
 #define minix_set_bit(nr,addr)			set_bit(nr,addr)
diff -Nru a/include/asm-ppc64/eeh.h b/include/asm-ppc64/eeh.h
--- a/include/asm-ppc64/eeh.h	Thu May  2 17:22:17 2002
+++ b/include/asm-ppc64/eeh.h	Thu May  2 17:22:17 2002
@@ -37,11 +37,13 @@
 #define EEH_STATE_OVERRIDE 1   /* IOA does not require eeh traps */
 #define EEH_STATE_FAILURE  16  /* */
 
-/* This is for profiling only and should be removed */
-extern unsigned long eeh_total_mmio_reads;
+/* This is for profiling only */
 extern unsigned long eeh_total_mmio_ffs;
 
+extern int eeh_implemented;
+
 void eeh_init(void);
+static inline int is_eeh_implemented(void) { return eeh_implemented; }
 int eeh_get_state(unsigned long ea);
 unsigned long eeh_check_failure(void *token, unsigned long val);
 
@@ -83,7 +85,7 @@
  */
 /* #define EEH_POSSIBLE_ERROR(addr, vaddr, val) ((vaddr) != (addr) && ~(val) == 0 && !IS_EEH_TOKEN_DISABLED(addr)) */
 /* This version is rearranged to collect some profiling data */
-#define EEH_POSSIBLE_ERROR(addr, vaddr, val) (++eeh_total_mmio_reads, (~(val) == 0 && (++eeh_total_mmio_ffs, (vaddr) != (addr) && !IS_EEH_TOKEN_DISABLED(addr))))
+#define EEH_POSSIBLE_ERROR(addr, vaddr, val) (~(val) == 0 && (++eeh_total_mmio_ffs, (vaddr) != (addr) && !IS_EEH_TOKEN_DISABLED(addr)))
 
 /* 
  * MMIO read/write operations with EEH support.
diff -Nru a/include/asm-ppc64/iSeries/HvCall.h b/include/asm-ppc64/iSeries/HvCall.h
--- a/include/asm-ppc64/iSeries/HvCall.h	Thu May  2 17:22:16 2002
+++ b/include/asm-ppc64/iSeries/HvCall.h	Thu May  2 17:22:16 2002
@@ -35,7 +35,7 @@
 #include <asm/iSeries/HvTypes.h>
 #endif
 
-#include <asm/Paca.h>
+#include <asm/paca.h>
 
 //-------------------------------------------------------------------
 // Constants
@@ -133,10 +133,9 @@
 //=====================================================================================
 static inline void		HvCall_setVirtualDecr(void)
 {
-	// Ignore any error return codes - most likely means that the target value for the
-	// LP has been increased and this vary off would bring us below the new target.
+	/* Ignore any error return codes - most likely means that the target value for the
+	 * LP has been increased and this vary off would bring us below the new target. */
 	HvCall0(HvCallBaseSetVirtualDecr);
-	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
 }
 //=====================================================================
 static inline void		HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm)
@@ -147,21 +146,18 @@
 static inline void		HvCall_setEnabledInterrupts(u64 enabledInterrupts)
 {
 	HvCall1(HvCallBaseSetEnabledInterrupts,enabledInterrupts);
-	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
 }
 
 //=====================================================================
 static inline void		HvCall_clearLogBuffer(HvLpIndex lpindex)
 {
 	HvCall1(HvCallBaseClearLogBuffer,lpindex);
-	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
 }
 
 //=====================================================================
 static inline u32  		HvCall_getLogBufferCodePage(HvLpIndex lpindex)
 {
 	u32 retVal = HvCall1(HvCallBaseGetLogBufferCodePage,lpindex);
-	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
 	return retVal;
 }
 
@@ -169,7 +165,6 @@
 static inline int  		HvCall_getLogBufferFormat(HvLpIndex lpindex)
 {
 	int retVal = HvCall1(HvCallBaseGetLogBufferFormat,lpindex);
-	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
 	return retVal;
 }
 
@@ -177,7 +172,6 @@
 static inline u32  		HvCall_getLogBufferLength(HvLpIndex lpindex)
 {
 	u32 retVal = HvCall1(HvCallBaseGetLogBufferLength,lpindex);
-	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
 	return retVal;
 }
 
@@ -185,7 +179,6 @@
 static inline void  		HvCall_setLogBufferFormatAndCodepage(int format, u32 codePage)
 {
 	HvCall2(HvCallBaseSetLogBufferFormatAndCodePage,format, codePage);
-	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
 }
 
 //=====================================================================
@@ -193,7 +186,7 @@
 void HvCall_writeLogBuffer(const void *buffer, u64 bufLen);
 
 //=====================================================================
-static inline void		HvCall_sendIPI(struct Paca * targetPaca)
+static inline void		HvCall_sendIPI(struct paca_struct * targetPaca)
 {
 	HvCall1( HvCallBaseSendIPI, targetPaca->xPacaIndex );
 }
diff -Nru a/include/asm-ppc64/iSeries/HvCallHpt.h b/include/asm-ppc64/iSeries/HvCallHpt.h
--- a/include/asm-ppc64/iSeries/HvCallHpt.h	Thu May  2 17:22:15 2002
+++ b/include/asm-ppc64/iSeries/HvCallHpt.h	Thu May  2 17:22:15 2002
@@ -106,21 +106,21 @@
 	return compressedStatus;
 }
 //=============================================================================
-static inline u64		HvCallHpt_findValid( struct _HPTE *hpte, u64 vpn )
+static inline u64		HvCallHpt_findValid( struct HPTE *hpte, u64 vpn )
 {
 	u64 retIndex = HvCall3Ret16( HvCallHptFindValid, hpte, vpn, 0, 0 );
 	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
 	return retIndex;
 }
 //=============================================================================
-static inline u64		HvCallHpt_findNextValid( struct _HPTE *hpte, u32 hpteIndex, u8 bitson, u8 bitsoff )
+static inline u64		HvCallHpt_findNextValid( struct HPTE *hpte, u32 hpteIndex, u8 bitson, u8 bitsoff )
 {
 	u64 retIndex = HvCall3Ret16( HvCallHptFindNextValid, hpte, hpteIndex, bitson, bitsoff );
 	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
 	return retIndex;
 }
 //=============================================================================
-static inline void		HvCallHpt_get( struct _HPTE *hpte, u32 hpteIndex )
+static inline void		HvCallHpt_get( struct HPTE *hpte, u32 hpteIndex )
 {
 	HvCall2Ret16( HvCallHptGet, hpte, hpteIndex, 0 );
 	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
@@ -128,7 +128,7 @@
 //============================================================================
 static inline void		HvCallHpt_addValidate( u32 hpteIndex,
 						       u32 hBit,
-						       struct _HPTE *hpte )
+						       struct HPTE *hpte )
 						
 {
 	HvCall4( HvCallHptAddValidate, hpteIndex,
diff -Nru a/include/asm-ppc64/iSeries/HvReleaseData.h b/include/asm-ppc64/iSeries/HvReleaseData.h
--- a/include/asm-ppc64/iSeries/HvReleaseData.h	Thu May  2 17:22:15 2002
+++ b/include/asm-ppc64/iSeries/HvReleaseData.h	Thu May  2 17:22:15 2002
@@ -52,7 +52,7 @@
 	u32	xDesc;			// Descriptor	"HvRD" ebcdic	x00-x03
 	u16	xSize;			// Size of this control block	x04-x05
 	u16	xVpdAreasPtrOffset;	// Offset in NACA of ItVpdAreas	x06-x07
-	struct Naca * xSlicNacaAddr;	// Virtual address of SLIC NACA x08-x0F
+	struct  naca_struct * xSlicNacaAddr; // Virt addr of SLIC NACA  x08-x0F
 	u32	xMsNucDataOffset;	// Offset of Linux Mapping Data x10-x13
 	u32	xRsvd1;			// Reserved			x14-x17
 	u16	xTagsMode:1;		// 0 == tags active, 1 == tags inactive
diff -Nru a/include/asm-ppc64/iSeries/LparData.h b/include/asm-ppc64/iSeries/LparData.h
--- a/include/asm-ppc64/iSeries/LparData.h	Thu May  2 17:22:15 2002
+++ b/include/asm-ppc64/iSeries/LparData.h	Thu May  2 17:22:15 2002
@@ -28,11 +28,11 @@
 #include <asm/page.h>
 #include <asm/abs_addr.h>
 
-#include <asm/Naca.h>
+#include <asm/naca.h>
 #include <asm/iSeries/ItLpNaca.h>
 #include <asm/iSeries/ItLpPaca.h>
 #include <asm/iSeries/ItLpRegSave.h>
-#include <asm/Paca.h>
+#include <asm/paca.h>
 #include <asm/iSeries/HvReleaseData.h>
 #include <asm/iSeries/LparMap.h>
 #include <asm/iSeries/ItVpdAreas.h>
@@ -42,8 +42,6 @@
 #include <asm/page.h>
 
 extern struct LparMap	xLparMap;
-extern struct Naca	xNaca;
-extern struct Paca	xPaca[];
 extern struct HvReleaseData hvReleaseData;
 extern struct ItLpNaca	itLpNaca;
 extern struct ItIplParmsReal xItIplParmsReal;
diff -Nru a/include/asm-ppc64/iSeries/iSeries_pci.h b/include/asm-ppc64/iSeries/iSeries_pci.h
--- a/include/asm-ppc64/iSeries/iSeries_pci.h	Thu May  2 17:22:16 2002
+++ b/include/asm-ppc64/iSeries/iSeries_pci.h	Thu May  2 17:22:16 2002
@@ -39,7 +39,8 @@
 #define ISERIES_SUBBUS(DevPtr) DevPtr->DsaAddr.subBusNumber
 #define ISERIES_DEVICE(DevPtr) DevPtr->DsaAddr.deviceId
 #define ISERIES_DEVFUN(DevPtr) DevPtr->DevFn
-#define ISERIES_DSA(DevPtr)   (*(u64*)&DevPtr->DsaAddr)  
+#define ISERIES_DSA(DevPtr)   (*(u64*)&DevPtr->DsaAddr)
+#define ISERIES_DEVNODE(PciDev) ((struct iSeries_Device_Node*)PciDev->sysdata)
 
 #define EADsMaxAgents 7
 /************************************************************************************/
@@ -87,6 +88,7 @@
 	int              IoRetry;        /* Current Retry Count         */
 	int              Flags;          /* Possible flags(disable/bist)*/
 	u16              Vendor;         /* Vendor ID                   */
+	u8               LogicalSlot;    /* Hv Slot Index for Tces      */
 	struct TceTable* DevTceTable;    /* Device TCE Table            */ 
 	u8               PhbId;          /* Phb Card is on.             */
 	u16              Board;          /* Board Number                */
diff -Nru a/include/asm-ppc64/io.h b/include/asm-ppc64/io.h
--- a/include/asm-ppc64/io.h	Thu May  2 17:22:17 2002
+++ b/include/asm-ppc64/io.h	Thu May  2 17:22:17 2002
@@ -51,7 +51,6 @@
 #define outl(data,addr)		writel(data,((unsigned long)(addr)))
 #else
 #define IS_MAPPED_VADDR(port)	((unsigned long)(port) >> 60UL)
-#ifdef CONFIG_PPC_EEH
 #define readb(addr)		eeh_readb((void*)(addr))  
 #define readw(addr)		eeh_readw((void*)(addr))  
 #define readl(addr)		eeh_readl((void*)(addr))
@@ -61,17 +60,6 @@
 #define memset_io(a,b,c)	eeh_memset((void *)(a),(b),(c))
 #define memcpy_fromio(a,b,c)	eeh_memcpy_fromio((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)	eeh_memcpy_toio((void *)(a),(b),(c))
-#else
-#define readb(addr)		in_8((volatile u8 *)(addr))
-#define writeb(b,addr)		out_8((volatile u8 *)(addr), (b))
-#define readw(addr)		in_le16((volatile u16 *)(addr))
-#define readl(addr)		in_le32((volatile u32 *)(addr))
-#define writew(b,addr)		out_le16((volatile u16 *)(addr),(b))
-#define writel(b,addr)		out_le32((volatile u32 *)(addr),(b))
-#define memset_io(a,b,c)	memset((void *)(a),(b),(c))
-#define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
-#define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
-#endif
 #define inb(port)		_inb((unsigned long)port)
 #define outb(val, port)		_outb(val, (unsigned long)port)
 #define inw(port)		_inw((unsigned long)port)
@@ -146,7 +134,7 @@
  * Change virtual addresses to physical addresses and vv, for
  * addresses in the area where the kernel has the RAM mapped.
  */
-extern inline unsigned long virt_to_phys(volatile void * address)
+static inline unsigned long virt_to_phys(volatile void * address)
 {
 #ifdef __IO_DEBUG
 	printk("virt_to_phys: 0x%08lx -> 0x%08lx\n", 
@@ -156,7 +144,7 @@
 	return __pa((unsigned long)address);
 }
 
-extern inline void * phys_to_virt(unsigned long address)
+static inline void * phys_to_virt(unsigned long address)
 {
 #ifdef __IO_DEBUG
 	printk("phys_to_virt: 0x%08lx -> 0x%08lx\n", address, __va(address));
@@ -175,7 +163,7 @@
 
 #endif /* __KERNEL__ */
 
-extern inline void iosync(void)
+static inline void iosync(void)
 {
         __asm__ __volatile__ ("sync" : : : "memory");
 }
@@ -190,7 +178,7 @@
 /*
  * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
  */
-extern inline int in_8(volatile unsigned char *addr)
+static inline int in_8(volatile unsigned char *addr)
 {
 	int ret;
 
@@ -198,12 +186,12 @@
 	return ret;
 }
 
-extern inline void out_8(volatile unsigned char *addr, int val)
+static inline void out_8(volatile unsigned char *addr, int val)
 {
 	__asm__ __volatile__("stb%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
 }
 
-extern inline int in_le16(volatile unsigned short *addr)
+static inline int in_le16(volatile unsigned short *addr)
 {
 	int ret;
 
@@ -212,7 +200,7 @@
 	return ret;
 }
 
-extern inline int in_be16(volatile unsigned short *addr)
+static inline int in_be16(volatile unsigned short *addr)
 {
 	int ret;
 
@@ -220,18 +208,18 @@
 	return ret;
 }
 
-extern inline void out_le16(volatile unsigned short *addr, int val)
+static inline void out_le16(volatile unsigned short *addr, int val)
 {
 	__asm__ __volatile__("sthbrx %1,0,%2" : "=m" (*addr) :
 			      "r" (val), "r" (addr));
 }
 
-extern inline void out_be16(volatile unsigned short *addr, int val)
+static inline void out_be16(volatile unsigned short *addr, int val)
 {
 	__asm__ __volatile__("sth%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
 }
 
-extern inline unsigned in_le32(volatile unsigned *addr)
+static inline unsigned in_le32(volatile unsigned *addr)
 {
 	unsigned ret;
 
@@ -240,7 +228,7 @@
 	return ret;
 }
 
-extern inline unsigned in_be32(volatile unsigned *addr)
+static inline unsigned in_be32(volatile unsigned *addr)
 {
 	unsigned ret;
 
@@ -248,22 +236,20 @@
 	return ret;
 }
 
-extern inline void out_le32(volatile unsigned *addr, int val)
+static inline void out_le32(volatile unsigned *addr, int val)
 {
 	__asm__ __volatile__("stwbrx %1,0,%2" : "=m" (*addr) :
 			     "r" (val), "r" (addr));
 }
 
-extern inline void out_be32(volatile unsigned *addr, int val)
+static inline void out_be32(volatile unsigned *addr, int val)
 {
 	__asm__ __volatile__("stw%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
 }
 
-#ifdef CONFIG_PPC_EEH
+#ifndef CONFIG_PPC_ISERIES 
 #include <asm/eeh.h>
-#endif
 
-#ifndef CONFIG_PPC_ISERIES 
 static inline u8 _inb(unsigned long port) {
 	if (IS_MAPPED_VADDR(port))
 		return readb((void *)port);
diff -Nru a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
--- a/include/asm-ppc64/machdep.h	Thu May  2 17:22:16 2002
+++ b/include/asm-ppc64/machdep.h	Thu May  2 17:22:16 2002
@@ -55,10 +55,8 @@
 				     long tcenum,
 				     unsigned long uaddr,
 				     int direction);
-	void		(*tce_free)(struct TceTable *tbl,
-				    dma_addr_t dma_addr, 
-				    unsigned order,
-				    unsigned numPages);
+	void		(*tce_free_one)(struct TceTable *tbl,
+				        long tcenum);    
 
 	void		(*smp_message_pass)(int target,
 					    int msg, 
@@ -78,7 +76,6 @@
 	void		(*init_IRQ)(void);
 	void		(*init_ras_IRQ)(void);
 	int		(*get_irq)(struct pt_regs *);
-	void		(*post_irq)( struct pt_regs *, int );
 	
 	/* A general init function, called by ppc_init in init/main.c.
 	   May be NULL. */
diff -Nru a/include/asm-ppc64/memory.h b/include/asm-ppc64/memory.h
--- a/include/asm-ppc64/memory.h	Thu May  2 17:22:17 2002
+++ b/include/asm-ppc64/memory.h	Thu May  2 17:22:17 2002
@@ -41,4 +41,24 @@
 #define isync_on_smp()	__asm__ __volatile__("": : :"memory")
 #endif
 
+/* Macros for adjusting thread priority (hardware multi-threading) */
+
+#if defined(CONFIG_PPC_ISERIES) || defined(CONFIG_HMT)
+#define HMT_low()	asm volatile("or 1,1,1		# low priority")
+#define HMT_medium()	asm volatile("or 2,2,2		# medium priority")
+#define HMT_high()	asm volatile("or 3,3,3		# high priority")
+
+#define HMT_LOW		"\tor	1,1,1		# low priority\n"
+#define HMT_MEDIUM	"\tor	2,2,2		# medium priority\n"
+#define HMT_MEDIUM	"\tor	3,3,3		# high priority\n"
+#else
+#define HMT_low()	do { } while(0)
+#define HMT_medium()	do { } while(0)
+#define HMT_high()	do { } while(0)
+
+#define HMT_LOW
+#define HMT_MEDIUM
+#define HMT_LOW
+#endif
+
 #endif
diff -Nru a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h
--- a/include/asm-ppc64/mmu.h	Thu May  2 17:22:16 2002
+++ b/include/asm-ppc64/mmu.h	Thu May  2 17:22:16 2002
@@ -22,7 +22,7 @@
  * Define the size of the cache used for segment table entries.  The first
  * entry is used as a cache pointer, therefore the actual number of entries
  * stored is one less than defined here.  Do not change this value without
- * considering the impact it will have on the layout of the paca in Paca.h.
+ * considering the impact it will have on the layout of the paca in paca.h.
  */
 #define STAB_CACHE_SIZE 16
 
@@ -90,7 +90,7 @@
 } SLBE;
 
 /*
- * This structure is used in Paca.h where the layout depends on the 
+ * This structure is used in paca.h where the layout depends on the 
  * size being 24B.
  */
 typedef struct {
diff -Nru a/include/asm-ppc64/naca.h b/include/asm-ppc64/naca.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/naca.h	Thu May  2 17:22:17 2002
@@ -0,0 +1,40 @@
+#ifndef _NACA_H
+#define _NACA_H
+
+/* 
+ * c 2001 PPC 64 Team, IBM Corp
+ *
+ * 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 <asm/types.h>
+
+struct naca_struct {
+	void *xItVpdAreas;
+	void *xRamDisk;
+	u64 xRamDiskSize;		/* In pages */
+	struct paca_struct *paca;	/* Ptr to an array of pacas */
+	u64 debug_switch;		/* Bits to control debug printing */
+	u16 processorCount;		/* # of physical processors */
+	u16 dCacheL1LineSize;		/* Line size of L1 DCache in bytes */
+	u16 dCacheL1LogLineSize;	/* Log-2 of DCache line size */
+	u16 dCacheL1LinesPerPage;	/* DCache lines per page */
+	u16 iCacheL1LineSize;		/* Line size of L1 ICache in bytes */
+	u16 iCacheL1LogLineSize;	/* Log-2 of ICache line size */
+	u16 iCacheL1LinesPerPage;	/* ICache lines per page */
+	u16 slb_size;			/* SLB size in entries */
+	u64 physicalMemorySize;		/* Size of real memory in bytes */
+	u64 pftSize;			/* Log base 2 of page table size */
+	u64 serialPortAddr;		/* Phyical address of serial port */
+	u8 interrupt_controller;	/* Type of interrupt controller */ 
+	u8 resv0;    			/* Type of interrupt controller */
+	u16 platform;			/* Platform flags */
+	u8 resv1[12];			/* Padding */
+};
+
+extern struct naca_struct *naca;
+
+#endif /* _NACA_H */
diff -Nru a/include/asm-ppc64/paca.h b/include/asm-ppc64/paca.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/paca.h	Thu May  2 17:22:16 2002
@@ -0,0 +1,163 @@
+#ifndef _PPC64_PACA_H
+#define _PPC64_PACA_H
+
+/*============================================================================
+ *                                                         Header File Id
+ * Name______________:	paca.h
+ *
+ * Description_______:
+ *
+ * This control block defines the PACA which defines the processor 
+ * specific data for each logical processor on the system.  
+ * There are some pointers defined that are utilized by PLIC.
+ *
+ * C 2001 PPC 64 Team, IBM Corp
+ *
+ * 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	<asm/types.h>
+
+#define N_EXC_STACK    2
+
+/*-----------------------------------------------------------------------------
+ * Other Includes
+ *-----------------------------------------------------------------------------
+ */
+#include	<asm/iSeries/ItLpPaca.h>
+#include	<asm/iSeries/ItLpRegSave.h>
+#include	<asm/iSeries/ItLpQueue.h>
+#include	<asm/rtas.h>
+#include	<asm/mmu.h>
+#include	<asm/processor.h>
+
+/* A paca entry is required for each logical processor.  On systems
+ * that support hardware multi-threading, this is equal to twice the
+ * number of physical processors.  On LPAR systems, we are required
+ * to have space for the maximum number of logical processors we
+ * could ever possibly have.  Currently, we are limited to allocating
+ * 24 processors to a partition which gives 48 logical processors on
+ * an HMT box.  Therefore, we reserve this many paca entries.
+ */
+#define MAX_PROCESSORS 24
+#define MAX_PACAS MAX_PROCESSORS * 2
+
+extern struct paca_struct paca[];
+#define get_paca() ((struct paca_struct *)mfspr(SPRG3))
+
+/*============================================================================
+ * Name_______:	paca
+ *
+ * Description:
+ *
+ *	Defines the layout of the paca.  
+ *
+ *	This structure is not directly accessed by PLIC or the SP except
+ *	for the first two pointers that point to the ItLpPaca area and the
+ *	ItLpRegSave area for this processor.  Both the ItLpPaca and
+ *	ItLpRegSave objects are currently contained within the
+ *	PACA but they do not need to be.
+ *
+ *============================================================================
+ */
+struct paca_struct {
+/*=====================================================================================
+ * CACHE_LINE_1 0x0000 - 0x007F
+ *=====================================================================================
+ */
+	struct ItLpPaca *xLpPacaPtr;	/* Pointer to LpPaca for PLIC		0x00 */
+	struct ItLpRegSave *xLpRegSavePtr; /* Pointer to LpRegSave for PLIC	0x08 */
+	u64 xCurrent;  		        /* Pointer to current			0x10 */
+	u16 xPacaIndex;			/* Logical processor number		0x18 */
+	u16 xHwProcNum;			/* Actual Hardware Processor Number	0x1a */
+	u32 default_decr;		/* Default decrementer value		0x1c */	
+	u64 xHrdIntStack;		/* Stack for hardware interrupts	0x20 */
+	u64 xKsave;			/* Saved Kernel stack addr or zero	0x28 */
+	u64 pvr;			/* Processor version register		0x30 */
+	u8 *exception_sp;		/*					0x38 */
+
+	struct ItLpQueue *lpQueuePtr;	/* LpQueue handled by this processor    0x40 */
+	u64  xTOC;			/* Kernel TOC address			0x48 */
+	STAB xStab_data;		/* Segment table information		0x50,0x58,0x60 */
+	u8 xSegments[STAB_CACHE_SIZE];	/* Cache of used stab entries		0x68,0x70 */
+	u8 xProcEnabled;		/* 1=soft enabled			0x78 */
+	u8 xHrdIntCount;		/* Count of active hardware interrupts  0x79  */
+	u8 prof_enabled;		/* 1=iSeries profiling enabled          0x7A */
+	u8 resv1[5];			/*					0x7B-0x7F */
+
+/*=====================================================================================
+ * CACHE_LINE_2 0x0080 - 0x00FF
+ *=====================================================================================
+ */
+	u64 spare1;			/*					0x00 */
+	u64 spare2;			/*					0x08 */
+	u64 spare3;			/*					0x10 */
+	u64 spare4;		/*					0x18 */
+	u64 next_jiffy_update_tb;	/* TB value for next jiffy update	0x20 */
+	u32 lpEvent_count;		/* lpEvents processed			0x28 */
+	u32 prof_multiplier;		/*					0x2C */
+	u32 prof_counter;		/*					0x30 */
+	u32 prof_shift;			/* iSeries shift for profile bucket size0x34 */
+	u32 *prof_buffer;		/* iSeries profiling buffer		0x38 */
+	u32 *prof_stext;		/* iSeries start of kernel text		0x40 */
+	u32 prof_len;			/* iSeries length of profile buffer -1	0x48 */
+	u8  rsvd2[128-76];		/*					0x4C */
+
+/*=====================================================================================
+ * CACHE_LINE_3 0x0100 - 0x017F
+ *=====================================================================================
+ */
+	u8		xProcStart;	/* At startup, processor spins until	0x100 */
+  					/* xProcStart becomes non-zero. */
+	u8		rsvd3[127];
+
+/*=====================================================================================
+ * CACHE_LINE_4-8  0x0180 - 0x03FF Contains ItLpPaca
+ *=====================================================================================
+ */
+	struct ItLpPaca xLpPaca;	/* Space for ItLpPaca */
+
+/*=====================================================================================
+ * CACHE_LINE_9-16 0x0400 - 0x07FF Contains ItLpRegSave
+ *=====================================================================================
+ */
+	struct ItLpRegSave xRegSav;	/* Register save for proc */
+
+/*=====================================================================================
+ * CACHE_LINE_17-18 0x0800 - 0x0EFF Reserved
+ *=====================================================================================
+ */
+	struct rtas_args xRtas;		/* Per processor RTAS struct */
+	u64 xR1;			/* r1 save for RTAS calls */
+	u64 xSavedMsr;			/* Old msr saved here by HvCall */
+	u8 rsvd5[256-16-sizeof(struct rtas_args)];
+
+/*=====================================================================================
+ * CACHE_LINE_19-30 0x0800 - 0x0EFF Reserved
+ *=====================================================================================
+ */
+	u8 rsvd6[0x600];
+
+/*=====================================================================================
+ * CACHE_LINE_31 0x0F00 - 0x0F7F Exception stack
+ *=====================================================================================
+ */
+	u8 exception_stack[N_EXC_STACK*EXC_FRAME_SIZE];
+
+/*=====================================================================================
+ * CACHE_LINE_32 0x0F80 - 0x0FFF Reserved
+ *=====================================================================================
+ */
+	u8 rsvd7[0x80];                  /* Give the stack some rope ... */
+
+/*=====================================================================================
+ * Page 2 Reserved for guard page.  Also used as a stack early in SMP boots before
+ *        relocation is enabled.
+ *=====================================================================================
+ */
+	u8 guard[0x1000];               /* ... and then hang 'em         */ 
+};
+
+#endif /* _PPC64_PACA_H */
diff -Nru a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h
--- a/include/asm-ppc64/page.h	Thu May  2 17:22:15 2002
+++ b/include/asm-ppc64/page.h	Thu May  2 17:22:15 2002
@@ -31,7 +31,7 @@
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
-#include <asm/Naca.h>
+#include <asm/naca.h>
 
 #define STRICT_MM_TYPECHECKS
 
@@ -130,15 +130,8 @@
 
 #define PAGE_BUG(page) do { BUG(); } while (0)
 
-/*
- * XXX A bug in the current ppc64 compiler prevents an optimisation
- * where a divide is replaced by a multiply by shifted inverse. For
- * the moment use page->virtaul
- */
-#define WANT_PAGE_VIRTUAL 1
-
 /* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
+static inline int get_order(unsigned long size)
 {
 	int order;
 
diff -Nru a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h
--- a/include/asm-ppc64/pci.h	Thu May  2 17:22:16 2002
+++ b/include/asm-ppc64/pci.h	Thu May  2 17:22:16 2002
@@ -25,12 +25,12 @@
 #define PCIBIOS_MIN_IO		0x1000
 #define PCIBIOS_MIN_MEM		0x10000000
 
-extern inline void pcibios_set_master(struct pci_dev *dev)
+static inline void pcibios_set_master(struct pci_dev *dev)
 {
 	/* No special bus mastering setup handling */
 }
 
-extern inline void pcibios_penalize_isa_irq(int irq)
+static inline void pcibios_penalize_isa_irq(int irq)
 {
 	/* We don't do dynamic PCI IRQ allocation */
 }
@@ -78,7 +78,7 @@
 
 extern void pSeries_pcibios_init_early(void);
 
-extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
+static inline void pci_dma_sync_single(struct pci_dev *hwdev,
 				       dma_addr_t dma_handle,
 				       size_t size, int direction)
 {
@@ -87,7 +87,7 @@
 	/* nothing to do */
 }
 
-extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
 				   struct scatterlist *sg,
 				   int nelems, int direction)
 {
@@ -101,7 +101,7 @@
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
+static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
 {
 	return 1;
 }
diff -Nru a/include/asm-ppc64/pci_dma.h b/include/asm-ppc64/pci_dma.h
--- a/include/asm-ppc64/pci_dma.h	Thu May  2 17:22:16 2002
+++ b/include/asm-ppc64/pci_dma.h	Thu May  2 17:22:16 2002
@@ -85,12 +85,14 @@
 	u64	index;			/* Index of this tce table (token?) */
 	u16	maxTceTableIndex;	/* Max num of tables for partition */
 	u8	virtualBusFlag;		/* Flag to indicate virtual bus */
-	u8	rsvd[5];
+ 	u8	logicalSlot;		/* IOA Tce Slot Index */
+ 	u8	rsvd[4];
 };
 
 extern struct TceTable virtBusTceTable;	/* Tce table for virtual bus */
 
 extern void create_tce_tables(void);
+extern void create_pci_bus_tce_table(unsigned long);
 
 void tce_init_pSeries(void);
 void tce_init_iSeries(void);
diff -Nru a/include/asm-ppc64/percpu.h b/include/asm-ppc64/percpu.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/percpu.h	Thu May  2 17:22:17 2002
@@ -0,0 +1,6 @@
+#ifndef __ARCH_I386_PERCPU__
+#define __ARCH_I386_PERCPU__
+
+#include <asm-generic/percpu.h>
+
+#endif /* __ARCH_I386_PERCPU__ */
diff -Nru a/include/asm-ppc64/pgalloc.h b/include/asm-ppc64/pgalloc.h
--- a/include/asm-ppc64/pgalloc.h	Thu May  2 17:22:15 2002
+++ b/include/asm-ppc64/pgalloc.h	Thu May  2 17:22:15 2002
@@ -3,8 +3,6 @@
 
 #include <linux/threads.h>
 #include <asm/processor.h>
-#include <asm/Naca.h>
-#include <asm/Paca.h>
 
 /*
  * This program is free software; you can redistribute it and/or
diff -Nru a/include/asm-ppc64/pgtable.h b/include/asm-ppc64/pgtable.h
--- a/include/asm-ppc64/pgtable.h	Thu May  2 17:22:16 2002
+++ b/include/asm-ppc64/pgtable.h	Thu May  2 17:22:16 2002
@@ -7,7 +7,6 @@
  */
 
 #ifndef __ASSEMBLY__
-#include <linux/threads.h>
 #include <asm/processor.h>		/* For TASK_SIZE */
 #include <asm/mmu.h>
 #include <asm/page.h>
@@ -247,35 +246,35 @@
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-extern inline int pte_read(pte_t pte)  { return pte_val(pte) & _PAGE_USER;}
-extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
-extern inline int pte_exec(pte_t pte)  { return pte_val(pte) & _PAGE_EXEC;}
-extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
-extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
+static inline int pte_read(pte_t pte)  { return pte_val(pte) & _PAGE_USER;}
+static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
+static inline int pte_exec(pte_t pte)  { return pte_val(pte) & _PAGE_EXEC;}
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
 
-extern inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
-extern inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
+static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
+static inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
 
-extern inline pte_t pte_rdprotect(pte_t pte) {
+static inline pte_t pte_rdprotect(pte_t pte) {
 	pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte) {
+static inline pte_t pte_exprotect(pte_t pte) {
 	pte_val(pte) &= ~_PAGE_EXEC; return pte; }
-extern inline pte_t pte_wrprotect(pte_t pte) {
+static inline pte_t pte_wrprotect(pte_t pte) {
 	pte_val(pte) &= ~(_PAGE_RW); return pte; }
-extern inline pte_t pte_mkclean(pte_t pte) {
+static inline pte_t pte_mkclean(pte_t pte) {
 	pte_val(pte) &= ~(_PAGE_DIRTY); return pte; }
-extern inline pte_t pte_mkold(pte_t pte) {
+static inline pte_t pte_mkold(pte_t pte) {
 	pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
 
-extern inline pte_t pte_mkread(pte_t pte) {
+static inline pte_t pte_mkread(pte_t pte) {
 	pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte) {
+static inline pte_t pte_mkexec(pte_t pte) {
 	pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte) {
+static inline pte_t pte_mkwrite(pte_t pte) {
 	pte_val(pte) |= _PAGE_RW; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte) {
+static inline pte_t pte_mkdirty(pte_t pte) {
 	pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte) {
+static inline pte_t pte_mkyoung(pte_t pte) {
 	pte_val(pte) |= _PAGE_ACCESSED; return pte; }
 
 /* Atomic PTE updates */
@@ -359,20 +358,6 @@
 extern void paging_init(void);
 
 /*
- * Page tables may have changed.  We don't need to do anything here
- * as entries are faulted into the hash table by the low-level
- * data/instruction access exception handlers.
- */
-#if 0
-/*
- * We won't be able to use update_mmu_cache to update the 
- * hardware page table because we need to update the pte
- * as well, but we don't get the address of the pte, only
- * its value.
- */
-#define update_mmu_cache(vma, addr, pte)	do { } while (0)
-#else
-/*
  * This gets called at the end of handling a page fault, when
  * the kernel has put a new PTE into the page table for the process.
  * We use it to put a corresponding HPTE into the hash table
@@ -380,7 +365,6 @@
  * hash-table miss exception.
  */
 extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
-#endif
 
 /* Encode and de-code a swap entry */
 #define SWP_TYPE(entry)			(((entry).val >> 1) & 0x3f)
diff -Nru a/include/asm-ppc64/posix_types.h b/include/asm-ppc64/posix_types.h
--- a/include/asm-ppc64/posix_types.h	Thu May  2 17:22:17 2002
+++ b/include/asm-ppc64/posix_types.h	Thu May  2 17:22:17 2002
@@ -18,17 +18,17 @@
 #ifdef DRENG_TYPES
 typedef unsigned long	__kernel_dev_t;
 typedef unsigned long	__kernel_ino_t;
-typedef unsigned long	__kernel_nlink_t;
+typedef unsigned long  	__kernel_nlink_t;
 #else
 typedef unsigned int	__kernel_dev_t;
 typedef unsigned int	__kernel_ino_t;
-typedef unsigned int	__kernel_nlink_t;
+typedef unsigned int  	__kernel_nlink_t;
 #endif
 typedef unsigned int	__kernel_mode_t;
 typedef long		__kernel_off_t;
 typedef long long	__kernel_loff_t;
 typedef int		__kernel_pid_t;
-typedef int		__kernel_ipc_pid_t;
+typedef int             __kernel_ipc_pid_t;
 typedef unsigned int	__kernel_uid_t;
 typedef unsigned int	__kernel_gid_t;
 typedef unsigned long	__kernel_size_t;
diff -Nru a/include/asm-ppc64/ppc_asm.tmpl b/include/asm-ppc64/ppc_asm.tmpl
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/ppc_asm.tmpl	Thu May  2 17:22:16 2002
@@ -0,0 +1,115 @@
+/* Condition Register Bit Fields */
+
+#define	cr0	0
+#define	cr1	1
+#define	cr2	2
+#define	cr3	3
+#define	cr4	4
+#define	cr5	5
+#define	cr6	6
+#define	cr7	7
+
+
+/* General Purpose Registers (GPRs) */
+
+#define	r0	0
+#define	r1	1
+#define	r2	2
+#define	r3	3
+#define	r4	4
+#define	r5	5
+#define	r6	6
+#define	r7	7
+#define	r8	8
+#define	r9	9
+#define	r10	10
+#define	r11	11
+#define	r12	12
+#define	r13	13
+#define	r14	14
+#define	r15	15
+#define	r16	16
+#define	r17	17
+#define	r18	18
+#define	r19	19
+#define	r20	20
+#define	r21	21
+#define	r22	22
+#define	r23	23
+#define	r24	24
+#define	r25	25
+#define	r26	26
+#define	r27	27
+#define	r28	28
+#define	r29	29
+#define	r30	30
+#define	r31	31
+
+
+/* Floating Point Registers (FPRs) */
+
+#define	fr0	0
+#define	fr1	1
+#define	fr2	2
+#define	fr3	3
+#define	fr4	4
+#define	fr5	5
+#define	fr6	6
+#define	fr7	7
+#define	fr8	8
+#define	fr9	9
+#define	fr10	10
+#define	fr11	11
+#define	fr12	12
+#define	fr13	13
+#define	fr14	14
+#define	fr15	15
+#define	fr16	16
+#define	fr17	17
+#define	fr18	18
+#define	fr19	19
+#define	fr20	20
+#define	fr21	21
+#define	fr22	22
+#define	fr23	23
+#define	fr24	24
+#define	fr25	25
+#define	fr26	26
+#define	fr27	27
+#define	fr28	28
+#define	fr29	29
+#define	fr30	30
+#define	fr31	31
+
+#define	vr0	0
+#define	vr1	1
+#define	vr2	2
+#define	vr3	3
+#define	vr4	4
+#define	vr5	5
+#define	vr6	6
+#define	vr7	7
+#define	vr8	8
+#define	vr9	9
+#define	vr10	10
+#define	vr11	11
+#define	vr12	12
+#define	vr13	13
+#define	vr14	14
+#define	vr15	15
+#define	vr16	16
+#define	vr17	17
+#define	vr18	18
+#define	vr19	19
+#define	vr20	20
+#define	vr21	21
+#define	vr22	22
+#define	vr23	23
+#define	vr24	24
+#define	vr25	25
+#define	vr26	26
+#define	vr27	27
+#define	vr28	28
+#define	vr29	29
+#define	vr30	30
+#define	vr31	31
diff -Nru a/include/asm-ppc64/ppcdebug.h b/include/asm-ppc64/ppcdebug.h
--- a/include/asm-ppc64/ppcdebug.h	Thu May  2 17:22:17 2002
+++ b/include/asm-ppc64/ppcdebug.h	Thu May  2 17:22:17 2002
@@ -22,7 +22,7 @@
 #define PPCDBG_BITVAL(X)     ((1UL)<<((unsigned long)(X)))
 
 /* Defined below are the bit positions of various debug flags in the
- * debug_switch variable (defined in Naca.h).
+ * debug_switch variable (defined in naca.h).
  * -- When adding new values, please enter them into trace names below -- 
  *
  * Values 62 & 63 can be used to stress the hardware page table management
diff -Nru a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
--- a/include/asm-ppc64/processor.h	Thu May  2 17:22:16 2002
+++ b/include/asm-ppc64/processor.h	Thu May  2 17:22:16 2002
@@ -490,18 +490,10 @@
 #define	PV_630        	0x0040
 #define	PV_630p	        0x0041
 
-/* Platforms supported by PPC64.  _machine is actually a set of flags */
-#define _MACH_pSeriesHW 0x00010000
-#define _MACH_iSeriesHW 0x00020000
-#define _MACH_LPAR	0x00000001
-
-#define _MACH_unknown	0x00000000
-#define _MACH_pSeries	(_MACH_pSeriesHW)
-#define _MACH_pSeriesLP	(_MACH_pSeriesHW | _MACH_LPAR)
-#define _MACH_iSeries	(_MACH_iSeriesHW | _MACH_LPAR)
-
-/* Compat defines for drivers */
-#define _MACH_Pmac	0xf0000000	/* bogus value */
+/* Platforms supported by PPC64 */
+#define PLATFORM_PSERIES      0x0100
+#define PLATFORM_PSERIES_LPAR 0x0101
+#define PLATFORM_ISERIES_LPAR 0x0201
 	
 /*
  * List of interrupt controllers.
@@ -597,11 +589,6 @@
 #define CTRLF		0x088
 #define RUNLATCH	0x0001
 
-/* Macros for adjusting thread priority (hardware multi-threading) */
-#define HMT_low()	asm volatile("or 1,1,1")
-#define HMT_medium()	asm volatile("or 2,2,2")
-#define HMT_high()	asm volatile("or 3,3,3")
-
 /* Size of an exception stack frame contained in the paca. */
 #define EXC_FRAME_SIZE 64
 
@@ -609,7 +596,6 @@
 			asm volatile("mfasr %0" : "=r" (rval)); rval;})
 
 #ifndef __ASSEMBLY__
-extern int _machine;
 extern int have_of;
 
 struct task_struct;
@@ -715,12 +701,12 @@
 #define ARCH_HAS_PREFETCHW
 #define ARCH_HAS_SPINLOCK_PREFETCH
 
-extern inline void prefetch(const void *x)
+static inline void prefetch(const void *x)
 {
 	__asm__ __volatile__ ("dcbt 0,%0" : : "r" (x));
 }
 
-extern inline void prefetchw(const void *x)
+static inline void prefetchw(const void *x)
 {
 	__asm__ __volatile__ ("dcbtst 0,%0" : : "r" (x));
 }
diff -Nru a/include/asm-ppc64/semaphore.h b/include/asm-ppc64/semaphore.h
--- a/include/asm-ppc64/semaphore.h	Thu May  2 17:22:17 2002
+++ b/include/asm-ppc64/semaphore.h	Thu May  2 17:22:17 2002
@@ -72,7 +72,7 @@
 extern int  __down_interruptible(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
-extern inline void down(struct semaphore * sem)
+static inline void down(struct semaphore * sem)
 {
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
@@ -86,7 +86,7 @@
 	smp_wmb();
 }
 
-extern inline int down_interruptible(struct semaphore * sem)
+static inline int down_interruptible(struct semaphore * sem)
 {
 	int ret = 0;
 
@@ -100,7 +100,7 @@
 	return ret;
 }
 
-extern inline int down_trylock(struct semaphore * sem)
+static inline int down_trylock(struct semaphore * sem)
 {
 	int ret;
 
@@ -113,7 +113,7 @@
 	return ret;
 }
 
-extern inline void up(struct semaphore * sem)
+static inline void up(struct semaphore * sem)
 {
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
diff -Nru a/include/asm-ppc64/siginfo.h b/include/asm-ppc64/siginfo.h
--- a/include/asm-ppc64/siginfo.h	Thu May  2 17:22:17 2002
+++ b/include/asm-ppc64/siginfo.h	Thu May  2 17:22:17 2002
@@ -223,7 +223,7 @@
 #ifdef __KERNEL__
 #include <linux/string.h>
 
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
+static inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
 {
 	if (from->si_code < 0)
 		memcpy(to, from, sizeof(siginfo_t));
diff -Nru a/include/asm-ppc64/signal.h b/include/asm-ppc64/signal.h
--- a/include/asm-ppc64/signal.h	Thu May  2 17:22:16 2002
+++ b/include/asm-ppc64/signal.h	Thu May  2 17:22:16 2002
@@ -58,12 +58,6 @@
 #define SIGRTMIN	32
 #define SIGRTMAX	(_NSIG-1)
 
-
-
-
-
-
-
 /*
  * SA_FLAGS values:
  *
diff -Nru a/include/asm-ppc64/smp.h b/include/asm-ppc64/smp.h
--- a/include/asm-ppc64/smp.h	Thu May  2 17:22:15 2002
+++ b/include/asm-ppc64/smp.h	Thu May  2 17:22:15 2002
@@ -25,7 +25,7 @@
 
 #ifndef __ASSEMBLY__
 
-#include <asm/Paca.h>
+#include <asm/paca.h>
 
 extern unsigned long cpu_online_map;
 
@@ -46,7 +46,7 @@
 
 #define smp_processor_id() (get_paca()->xPacaIndex)
 #define hard_smp_processor_id() (get_paca()->xHwProcNum)
-#define get_hard_smp_processor_id(CPU) (xPaca[(CPU)].xHwProcNum)
+#define get_hard_smp_processor_id(CPU) (paca[(CPU)].xHwProcNum)
 
 
 
diff -Nru a/include/asm-ppc64/spinlock.h b/include/asm-ppc64/spinlock.h
--- a/include/asm-ppc64/spinlock.h	Thu May  2 17:22:15 2002
+++ b/include/asm-ppc64/spinlock.h	Thu May  2 17:22:15 2002
@@ -49,12 +49,13 @@
 
 	__asm__ __volatile__(
 	"b		2f		# spin_lock\n\
-1:	or		1,1,1		# spin at low priority\n\
-	lwzx		%0,0,%1\n\
-	cmpwi		0,%0,0\n\
-	bne+		1b\n\
-	or		2,2,2		# back to medium priority\n\
-2:	lwarx		%0,0,%1\n\
+1:"
+	HMT_LOW
+"	lwzx		%0,0,%1\n\
+	cmpwi		0,%0,0\n\
+	bne+		1b\n"
+	HMT_MEDIUM
+"2:	lwarx		%0,0,%1\n\
 	cmpwi		0,%0,0\n\
 	bne-		1b\n\
 	stwcx.		%2,0,%1\n\
@@ -67,7 +68,7 @@
 
 static __inline__ void _raw_spin_unlock(spinlock_t *lock)
 {
-	__asm__ __volatile__("lwsync	# spin_unlock": : :"memory");
+	__asm__ __volatile__("eieio	# spin_unlock": : :"memory");
 	lock->lock = 0;
 }
 
@@ -115,12 +116,13 @@
 
 	__asm__ __volatile__(
 	"b		2f		# read_lock\n\
-1:	or		1,1,1		# spin at low priority\n\
-	lwax		%0,0,%1\n\
-	cmpwi		0,%0,0\n\
-	blt+		1b\n\
-	or		2,2,2		# back to medium priority\n\
-2:	lwarx		%0,0,%1\n\
+1:"
+	HMT_LOW
+"	lwax		%0,0,%1\n\
+	cmpwi		0,%0,0\n\
+	blt+		1b\n"
+	HMT_MEDIUM
+"2:	lwarx		%0,0,%1\n\
 	extsw		%0,%0\n\
 	addic.		%0,%0,1\n\
 	ble-		1b\n\
@@ -137,7 +139,7 @@
 	unsigned int tmp;
 
 	__asm__ __volatile__(
-	"lwsync				# read_unlock\n\
+	"eieio				# read_unlock\n\
 1:	lwarx		%0,0,%1\n\
 	addic		%0,%0,-1\n\
 	stwcx.		%0,0,%1\n\
@@ -174,12 +176,13 @@
 
 	__asm__ __volatile__(
 	"b		2f		# write_lock\n\
-1:	or		1,1,1		# spin at low priority\n\
-	lwax		%0,0,%1\n\
-	cmpwi		0,%0,0\n\
-	bne+		1b\n\
-	or		2,2,2		# back to medium priority\n\
-2:	lwarx		%0,0,%1\n\
+1:"
+	HMT_LOW
+	"lwax		%0,0,%1\n\
+	cmpwi		0,%0,0\n\
+	bne+		1b\n"
+	HMT_MEDIUM
+"2:	lwarx		%0,0,%1\n\
 	cmpwi		0,%0,0\n\
 	bne-		1b\n\
 	stwcx.		%2,0,%1\n\
@@ -192,7 +195,7 @@
 
 static __inline__ void _raw_write_unlock(rwlock_t *rw)
 {
-	__asm__ __volatile__("lwsync		# write_unlock": : :"memory");
+	__asm__ __volatile__("eieio		# write_unlock": : :"memory");
 	rw->lock = 0;
 }
 
diff -Nru a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h
--- a/include/asm-ppc64/system.h	Thu May  2 17:22:17 2002
+++ b/include/asm-ppc64/system.h	Thu May  2 17:22:17 2002
@@ -38,7 +38,7 @@
  * give any ordering guarantees about loads, we have to use the
  * stronger but slower sync instruction for mb and rmb.
  */
-#define mb()  __asm__ __volatile__ ("sync" : : : "memory")
+#define mb()   __asm__ __volatile__ ("sync" : : : "memory")
 #define rmb()  __asm__ __volatile__ ("lwsync" : : : "memory")
 #define wmb()  __asm__ __volatile__ ("eieio" : : : "memory")
 
diff -Nru a/include/asm-ppc64/time.h b/include/asm-ppc64/time.h
--- a/include/asm-ppc64/time.h	Thu May  2 17:22:17 2002
+++ b/include/asm-ppc64/time.h	Thu May  2 17:22:17 2002
@@ -1,5 +1,4 @@
 /*
- * 
  * Common time prototypes and such for all ppc machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -19,7 +18,7 @@
 #include <linux/mc146818rtc.h>
 
 #include <asm/processor.h>
-#include <asm/Paca.h>
+#include <asm/paca.h>
 #include <asm/iSeries/HvCall.h>
 
 /* time.c */
@@ -74,22 +73,23 @@
 
 static __inline__ void set_dec(int val)
 {
-    struct Paca * paca;
-    int cur_dec;
-
-    paca = (struct Paca *)mfspr(SPRG3);
-    if ( paca->xLpPaca.xSharedProc ) {
-	paca->xLpPaca.xVirtualDecr = val;
-	cur_dec = get_dec();
-	if ( cur_dec > val )
-	    HvCall_setVirtualDecr();
-    }
-    else
-	mtspr(SPRN_DEC, val);
+#ifdef CONFIG_PPC_ISERIES
+	struct paca_struct *lpaca = get_paca();
+	int cur_dec;
+
+	if (lpaca->xLpPaca.xSharedProc) {
+		lpaca->xLpPaca.xVirtualDecr = val;
+		cur_dec = get_dec();
+		if (cur_dec > val)
+			HvCall_setVirtualDecr();
+	} else
+#endif
+		mtspr(SPRN_DEC, val);
 }
 
-extern __inline__ unsigned long tb_ticks_since(unsigned long tstamp) {
-    return get_tb() - tstamp;
+static inline unsigned long tb_ticks_since(unsigned long tstamp)
+{
+	return get_tb() - tstamp;
 }
 
 #define mulhwu(x,y) \
diff -Nru a/include/asm-ppc64/tlbflush.h b/include/asm-ppc64/tlbflush.h
--- a/include/asm-ppc64/tlbflush.h	Thu May  2 17:22:15 2002
+++ b/include/asm-ppc64/tlbflush.h	Thu May  2 17:22:15 2002
@@ -25,7 +25,7 @@
 #define flush_tlb_kernel_range(start, end) \
 	__flush_tlb_range(&init_mm, (start), (end))
 
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
 				      unsigned long start, unsigned long end)
 {
 	/* PPC has hw page tables. */
diff -Nru a/include/asm-ppc64/uaccess.h b/include/asm-ppc64/uaccess.h
--- a/include/asm-ppc64/uaccess.h	Thu May  2 17:22:15 2002
+++ b/include/asm-ppc64/uaccess.h	Thu May  2 17:22:15 2002
@@ -38,7 +38,7 @@
 #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
 
-extern inline int verify_area(int type, const void * addr, unsigned long size)
+static inline int verify_area(int type, const void * addr, unsigned long size)
 {
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
@@ -200,7 +200,7 @@
 
 extern unsigned long __copy_tofrom_user(void *to, const void *from, unsigned long size);
 
-extern inline unsigned long
+static inline unsigned long
 copy_from_user(void *to, const void *from, unsigned long n)
 {
 	unsigned long over;
@@ -214,7 +214,7 @@
 	return n;
 }
 
-extern inline unsigned long
+static inline unsigned long
 copy_to_user(void *to, const void *from, unsigned long n)
 {
 	unsigned long over;
@@ -235,7 +235,7 @@
 
 extern unsigned long __clear_user(void *addr, unsigned long size);
 
-extern inline unsigned long
+static inline unsigned long
 clear_user(void *addr, unsigned long size)
 {
 	if (access_ok(VERIFY_WRITE, addr, size))
@@ -245,7 +245,7 @@
 
 extern int __strncpy_from_user(char *dst, const char *src, long count);
 
-extern inline long
+static inline long
 strncpy_from_user(char *dst, const char *src, long count)
 {
 	if (access_ok(VERIFY_READ, src, 1))
@@ -269,7 +269,7 @@
  * The `top' parameter to __strnlen_user is to make sure that
  * we can never overflow from the user area into kernel space.
  */
-extern __inline__ int strnlen_user(const char *str, long len)
+static inline int strnlen_user(const char *str, long len)
 {
 	unsigned long top = __kernel_ok? ~0UL: TASK_SIZE - 1;
 
diff -Nru a/include/asm-ppc64/vga.h b/include/asm-ppc64/vga.h
--- a/include/asm-ppc64/vga.h	Thu May  2 17:22:16 2002
+++ b/include/asm-ppc64/vga.h	Thu May  2 17:22:16 2002
@@ -26,12 +26,12 @@
  *  <linux/vt_buffer.h> has already done the right job for us.
  */
 
-extern inline void scr_writew(u16 val, volatile u16 *addr)
+static inline void scr_writew(u16 val, volatile u16 *addr)
 {
     st_le16(addr, val);
 }
 
-extern inline u16 scr_readw(volatile const u16 *addr)
+static inline u16 scr_readw(volatile const u16 *addr)
 {
     return ld_le16(addr);
 }
diff -Nru a/include/asm-sparc/apc.h b/include/asm-sparc/apc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-sparc/apc.h	Thu May  2 17:22:17 2002
@@ -0,0 +1,64 @@
+/* apc - Driver definitions for power management functions
+ * of Aurora Personality Chip (APC) on SPARCstation-4/5 and 
+ * derivatives
+ *
+ * Copyright (c) 2001 Eric Brower (ebrower@usa.net)
+ *
+ */
+
+#ifndef _SPARC_APC_H
+#define _SPARC_APC_H
+
+#include <linux/ioctl.h>
+
+#define APC_IOC	'A'
+
+#define APCIOCGFANCTL _IOR(APC_IOC, 0x00, int)	/* Get fan speed	*/
+#define APCIOCSFANCTL _IOW(APC_IOC, 0x01, int)	/* Set fan speed	*/
+
+#define APCIOCGCPWR   _IOR(APC_IOC, 0x02, int)	/* Get CPOWER state	*/
+#define APCIOCSCPWR   _IOW(APC_IOC, 0x03, int)	/* Set CPOWER state	*/
+
+#define APCIOCGBPORT   _IOR(APC_IOC, 0x04, int)	/* Get BPORT state 	*/
+#define APCIOCSBPORT   _IOW(APC_IOC, 0x05, int)	/* Set BPORT state	*/
+
+/*
+ * Register offsets
+ */
+#define APC_IDLE_REG	0x00
+#define APC_FANCTL_REG	0x20
+#define APC_CPOWER_REG	0x24
+#define APC_BPORT_REG	0x30
+
+#define APC_REGMASK		0x01
+#define APC_BPMASK		0x03
+
+/*
+ * IDLE - CPU standby values (set to initiate standby)
+ */
+#define APC_IDLE_ON		0x01
+
+/*
+ * FANCTL - Fan speed control state values
+ */
+#define APC_FANCTL_HI	0x00	/* Fan speed high	*/
+#define APC_FANCTL_LO	0x01	/* Fan speed low	*/
+
+/*
+ * CPWR - Convenience power outlet state values 
+ */
+#define APC_CPOWER_ON	0x00	/* Conv power on	*/
+#define APC_CPOWER_OFF	0x01	/* Conv power off	*/
+
+/*
+ * BPA/BPB - Read-Write "Bit Ports" state values (reset to 0 at power-on)
+ *
+ * WARNING: Internal usage of bit ports is platform dependent--
+ * don't modify BPORT settings unless you know what you are doing.
+ * 
+ * On SS5 BPA seems to toggle onboard ethernet loopback... -E
+ */
+#define APC_BPORT_A		0x01	/* Bit Port A		*/
+#define APC_BPORT_B		0x02	/* Bit Port B		*/
+
+#endif /* !(_SPARC_APC_H) */
diff -Nru a/include/asm-sparc/ioctls.h b/include/asm-sparc/ioctls.h
--- a/include/asm-sparc/ioctls.h	Thu May  2 17:22:17 2002
+++ b/include/asm-sparc/ioctls.h	Thu May  2 17:22:17 2002
@@ -51,8 +51,8 @@
 #define TIOCMBIC	_IOW('t', 107, int)
 #define TIOCMBIS	_IOW('t', 108, int)
 #define TIOCMSET	_IOW('t', 109, int)
-#define __TIOCSTART       _IO('t', 110) /* SunOS Specific */
-#define __TIOCSTOP        _IO('t', 111) /* SunOS Specific */
+#define TIOCSTART       _IO('t', 110)
+#define TIOCSTOP        _IO('t', 111)
 #define TIOCPKT		_IOW('t', 112, int)
 #define TIOCNOTTY	_IO('t', 113)
 #define TIOCSTI		_IOW('t', 114, char)
diff -Nru a/include/asm-sparc/percpu.h b/include/asm-sparc/percpu.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-sparc/percpu.h	Thu May  2 17:22:17 2002
@@ -0,0 +1,6 @@
+#ifndef __ARCH_SPARC_PERCPU__
+#define __ARCH_SPARC_PERCPU__
+
+#include <asm-generic/percpu.h>
+
+#endif /* __ARCH_SPARC_PERCPU__ */
diff -Nru a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
--- a/include/asm-sparc/unistd.h	Thu May  2 17:22:16 2002
+++ b/include/asm-sparc/unistd.h	Thu May  2 17:22:16 2002
@@ -175,8 +175,8 @@
 #define __NR_statfs             157 /* Common                                      */
 #define __NR_fstatfs            158 /* Common                                      */
 #define __NR_umount             159 /* Common                                      */
-/* #define __NR_async_daemon    160    SunOS Specific                              */
-/* #define __NR_getfh           161    SunOS Specific                              */
+#define __NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS    */
+#define __NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS           */
 #define __NR_getdomainname      162 /* SunOS Specific                              */
 #define __NR_setdomainname      163 /* Common                                      */
 /* #define __NR_ni_syscall	164    ENOSYS under SunOS			   */
diff -Nru a/include/asm-sparc64/cacheflush.h b/include/asm-sparc64/cacheflush.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-sparc64/cacheflush.h	Thu May  2 17:22:17 2002
@@ -0,0 +1,56 @@
+#ifndef _SPARC64_CACHEFLUSH_H
+#define _SPARC64_CACHEFLUSH_H
+
+#include <linux/config.h>
+#include <linux/mm.h>
+
+/* Cache flush operations. */
+
+/* These are the same regardless of whether this is an SMP kernel or not. */
+#define flush_cache_mm(__mm) \
+	do { if ((__mm) == current->mm) flushw_user(); } while(0)
+extern void flush_cache_range(struct vm_area_struct *, unsigned long, unsigned long);
+#define flush_cache_page(vma, page) \
+	flush_cache_mm((vma)->vm_mm)
+
+/* 
+ * On spitfire, the icache doesn't snoop local stores and we don't
+ * use block commit stores (which invalidate icache lines) during
+ * module load, so we need this.
+ */
+extern void flush_icache_range(unsigned long start, unsigned long end);
+
+extern void __flush_dcache_page(void *addr, int flush_icache);
+extern void __flush_icache_page(unsigned long);
+extern void flush_dcache_page_impl(struct page *page);
+#ifdef CONFIG_SMP
+extern void smp_flush_dcache_page_impl(struct page *page, int cpu);
+extern void flush_dcache_page_all(struct mm_struct *mm, struct page *page);
+#else
+#define smp_flush_dcache_page_impl(page,cpu) flush_dcache_page_impl(page)
+#define flush_dcache_page_all(mm,page) flush_dcache_page_impl(page)
+#endif
+
+extern void __flush_dcache_range(unsigned long start, unsigned long end);
+
+extern void __flush_cache_all(void);
+
+#ifndef CONFIG_SMP
+
+#define flush_cache_all()	__flush_cache_all()
+
+#else /* CONFIG_SMP */
+
+extern void smp_flush_cache_all(void);
+
+#endif /* ! CONFIG_SMP */
+
+#define flush_icache_page(vma, pg)	do { } while(0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
+
+extern void flush_dcache_page(struct page *page);
+
+/* This is unnecessary on the SpitFire since D-CACHE is write-through. */
+#define flush_page_to_ram(page)			do { } while (0)
+
+#endif /* _SPARC64_CACHEFLUSH_H */
diff -Nru a/include/asm-sparc64/elf.h b/include/asm-sparc64/elf.h
--- a/include/asm-sparc64/elf.h	Thu May  2 17:22:16 2002
+++ b/include/asm-sparc64/elf.h	Thu May  2 17:22:16 2002
@@ -21,8 +21,38 @@
 
 typedef unsigned long elf_greg_t;
 
-#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+#define ELF_NGREG 36
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+/* Format of 64-bit elf_gregset_t is:
+ * 	G0 --> G7
+ * 	O0 --> O7
+ * 	L0 --> L7
+ * 	I0 --> I7
+ *	TSTATE
+ *	TPC
+ *	TNPC
+ *	Y
+ */
+#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs)	\
+do {	unsigned long *dest = &(__elf_regs[0]);		\
+	struct pt_regs *src = (__pt_regs);		\
+	unsigned long *sp;				\
+	int i;						\
+	for(i = 0; i < 16; i++)				\
+		dest[i] = src->u_regs[i];		\
+	/* Don't try this at home kids... */		\
+	set_fs(USER_DS);				\
+	sp = (unsigned long *)				\
+	 ((src->u_regs[14] + STACK_BIAS)		\
+	  & 0xfffffffffffffff8UL);			\
+	for(i = 0; i < 16; i++)				\
+		__get_user(dest[i+16], &sp[i]);		\
+	set_fs(KERNEL_DS);				\
+	dest[32] = src->tstate;				\
+	dest[33] = src->tpc;				\
+	dest[34] = src->tnpc;				\
+	dest[35] = src->y;				\
+} while (0);
 
 typedef struct {
 	unsigned long	pr_regs[32];
@@ -69,10 +99,15 @@
 
 #ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2)			\
-do {	if ((ex).e_ident[EI_CLASS] == ELFCLASS32)	\
-		set_thread_flag(TIF_32BIT);		\
+do {	unsigned long new_flags = current_thread_info()->flags; \
+	new_flags &= _TIF_32BIT;			\
+	if ((ex).e_ident[EI_CLASS] == ELFCLASS32)	\
+		new_flags |= _TIF_32BIT;		\
 	else						\
-		clear_thread_flag(TIF_32BIT);		\
+		new_flags &= ~_TIF_32BIT;		\
+	if ((current_thread_info()->flags & _TIF_32BIT) \
+	    != new_flags)				\
+		set_thread_flag(TIF_ABI_PENDING);	\
 	/* flush_thread will update pgd cache */	\
 	if (ibcs2)					\
 		set_personality(PER_SVR4);		\
diff -Nru a/include/asm-sparc64/ioctls.h b/include/asm-sparc64/ioctls.h
--- a/include/asm-sparc64/ioctls.h	Thu May  2 17:22:15 2002
+++ b/include/asm-sparc64/ioctls.h	Thu May  2 17:22:15 2002
@@ -52,8 +52,8 @@
 #define TIOCMBIC	_IOW('t', 107, int)
 #define TIOCMBIS	_IOW('t', 108, int)
 #define TIOCMSET	_IOW('t', 109, int)
-#define __TIOCSTART       _IO('t', 110) /* SunOS Specific */
-#define __TIOCSTOP        _IO('t', 111) /* SunOS Specific */
+#define TIOCSTART       _IO('t', 110)
+#define TIOCSTOP        _IO('t', 111)
 #define TIOCPKT		_IOW('t', 112, int)
 #define TIOCNOTTY	_IO('t', 113)
 #define TIOCSTI		_IOW('t', 114, char)
diff -Nru a/include/asm-sparc64/percpu.h b/include/asm-sparc64/percpu.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-sparc64/percpu.h	Thu May  2 17:22:17 2002
@@ -0,0 +1,6 @@
+#ifndef __ARCH_SPARC64_PERCPU__
+#define __ARCH_SPARC64_PERCPU__
+
+#include <asm-generic/percpu.h>
+
+#endif /* __ARCH_SPARC64_PERCPU__ */
diff -Nru a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h
--- a/include/asm-sparc64/pgalloc.h	Thu May  2 17:22:16 2002
+++ b/include/asm-sparc64/pgalloc.h	Thu May  2 17:22:16 2002
@@ -10,32 +10,6 @@
 #include <asm/spitfire.h>
 #include <asm/pgtable.h>
 
-static __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start,
-					  unsigned long end)
-{
-	/* Note the signed type.  */
-	long s = start, e = end, vpte_base;
-	if (s > e)
-		/* Nobody should call us with start below VM hole and end above.
-		   See if it is really true.  */
-		BUG();
-#if 0
-	/* Currently free_pgtables guarantees this.  */
-	s &= PMD_MASK;
-	e = (e + PMD_SIZE - 1) & PMD_MASK;
-#endif
-	vpte_base = (tlb_type == spitfire ?
-		     VPTE_BASE_SPITFIRE :
-		     VPTE_BASE_CHEETAH);
-	{
-		struct vm_area_struct vma;
-		vma.vm_mm = mm;
-		flush_tlb_range(&vma,
-				vpte_base + (s >> (PAGE_SHIFT - 3)),
-				vpte_base + (e >> (PAGE_SHIFT - 3)));
-	}
-}
-
 /* Page table allocation/freeing. */
 #ifdef CONFIG_SMP
 /* Sliiiicck */
diff -Nru a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
--- a/include/asm-sparc64/pgtable.h	Thu May  2 17:22:15 2002
+++ b/include/asm-sparc64/pgtable.h	Thu May  2 17:22:15 2002
@@ -36,97 +36,6 @@
 #define LOW_OBP_ADDRESS		0x00000000f0000000
 #define HI_OBP_ADDRESS		0x0000000100000000
 
-#ifndef __ASSEMBLY__
-
-/* Cache and TLB flush operations. */
-
-/* These are the same regardless of whether this is an SMP kernel or not. */
-#define flush_cache_mm(__mm) \
-	do { if ((__mm) == current->mm) flushw_user(); } while(0)
-extern void flush_cache_range(struct vm_area_struct *, unsigned long, unsigned long);
-#define flush_cache_page(vma, page) \
-	flush_cache_mm((vma)->vm_mm)
-
-
-struct page;
-
-/* 
- * On spitfire, the icache doesn't snoop local stores and we don't
- * use block commit stores (which invalidate icache lines) during
- * module load, so we need this.
- */
-extern void flush_icache_range(unsigned long start, unsigned long end);
-
-extern void __flush_dcache_page(void *addr, int flush_icache);
-extern void __flush_icache_page(unsigned long);
-extern void flush_dcache_page_impl(struct page *page);
-#ifdef CONFIG_SMP
-extern void smp_flush_dcache_page_impl(struct page *page, int cpu);
-extern void flush_dcache_page_all(struct mm_struct *mm, struct page *page);
-#else
-#define smp_flush_dcache_page_impl(page,cpu) flush_dcache_page_impl(page)
-#define flush_dcache_page_all(mm,page) flush_dcache_page_impl(page)
-#endif
-
-extern void __flush_dcache_range(unsigned long start, unsigned long end);
-
-extern void __flush_cache_all(void);
-
-extern void __flush_tlb_all(void);
-extern void __flush_tlb_mm(unsigned long context, unsigned long r);
-extern void __flush_tlb_range(unsigned long context, unsigned long start,
-			      unsigned long r, unsigned long end,
-			      unsigned long pgsz, unsigned long size);
-extern void __flush_tlb_page(unsigned long context, unsigned long page, unsigned long r);
-
-#ifndef CONFIG_SMP
-
-#define flush_cache_all()	__flush_cache_all()
-#define flush_tlb_all()		__flush_tlb_all()
-
-#define flush_tlb_mm(__mm) \
-do { if(CTX_VALID((__mm)->context)) \
-	__flush_tlb_mm(CTX_HWBITS((__mm)->context), SECONDARY_CONTEXT); \
-} while(0)
-
-#define flush_tlb_range(__vma, start, end) \
-do { if(CTX_VALID((__vma)->vm_mm->context)) { \
-	unsigned long __start = (start)&PAGE_MASK; \
-	unsigned long __end = PAGE_ALIGN(end); \
-	__flush_tlb_range(CTX_HWBITS((__vma)->vm_mm->context), __start, \
-			  SECONDARY_CONTEXT, __end, PAGE_SIZE, \
-			  (__end - __start)); \
-     } \
-} while(0)
-
-#define flush_tlb_page(vma, page) \
-do { struct mm_struct *__mm = (vma)->vm_mm; \
-     if(CTX_VALID(__mm->context)) \
-	__flush_tlb_page(CTX_HWBITS(__mm->context), (page)&PAGE_MASK, \
-			 SECONDARY_CONTEXT); \
-} while(0)
-
-#else /* CONFIG_SMP */
-
-extern void smp_flush_cache_all(void);
-extern void smp_flush_tlb_all(void);
-extern void smp_flush_tlb_mm(struct mm_struct *mm);
-extern void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
-				unsigned long end);
-extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page);
-
-#define flush_cache_all()	smp_flush_cache_all()
-#define flush_tlb_all()		smp_flush_tlb_all()
-#define flush_tlb_mm(mm)	smp_flush_tlb_mm(mm)
-#define flush_tlb_range(vma, start, end) \
-	smp_flush_tlb_range(vma, start, end)
-#define flush_tlb_page(vma, page) \
-	smp_flush_tlb_page((vma)->vm_mm, page)
-
-#endif /* ! CONFIG_SMP */
-
-#endif /* ! __ASSEMBLY__ */
-
 /* XXX All of this needs to be rethought so we can take advantage
  * XXX cheetah's full 64-bit virtual address space, ie. no more hole
  * XXX in the middle like on spitfire. -DaveM
@@ -372,9 +281,6 @@
 
 extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
 
-#define flush_icache_page(vma, pg)	do { } while(0)
-#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
-
 /* Make a non-present pseudo-TTE. */
 extern inline pte_t mk_pte_io(unsigned long page, pgprot_t prot, int space)
 {
@@ -453,11 +359,6 @@
 #define pgtable_cache_init()	do { } while (0)
 
 extern void check_pgt_cache(void);
-
-extern void flush_dcache_page(struct page *page);
-
-/* This is unnecessary on the SpitFire since D-CACHE is write-through. */
-#define flush_page_to_ram(page)			do { } while (0)
 
 #endif /* !(__ASSEMBLY__) */
 
diff -Nru a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
--- a/include/asm-sparc64/system.h	Thu May  2 17:22:15 2002
+++ b/include/asm-sparc64/system.h	Thu May  2 17:22:15 2002
@@ -145,9 +145,9 @@
 #define flush_register_windows flushw_all
 #define prepare_to_switch flushw_all
 
-#ifndef CONFIG_DEBUG_SPINLOCk
+#ifndef CONFIG_DEBUG_SPINLOCK
 #define CHECK_LOCKS(PREV)	do { } while(0)
-#else /* CONFIG_DEBUG_SPINLOCk */
+#else /* CONFIG_DEBUG_SPINLOCK */
 #define CHECK_LOCKS(PREV)						\
 if ((PREV)->thread.smp_lock_count) {					\
 	unsigned long rpc;						\
@@ -161,7 +161,7 @@
 	printk(KERN_CRIT "(%s)[%d]: Sched caller %016lx\n",		\
 	       (PREV)->comm, (PREV)->pid, rpc);				\
 }
-#endif /* !(CONFIG_DEBUG_SPINLOCk) */
+#endif /* !(CONFIG_DEBUG_SPINLOCK) */
 
 	/* See what happens when you design the chip correctly?
 	 *
diff -Nru a/include/asm-sparc64/thread_info.h b/include/asm-sparc64/thread_info.h
--- a/include/asm-sparc64/thread_info.h	Thu May  2 17:22:17 2002
+++ b/include/asm-sparc64/thread_info.h	Thu May  2 17:22:17 2002
@@ -109,6 +109,8 @@
 #define THREAD_SHIFT PAGE_SHIFT
 #endif /* PAGE_SHIFT == 13 */
 
+#define PREEMPT_ACTIVE		0x4000000
+
 /*
  * macros/functions for gaining access to the thread information structure
  */
@@ -193,6 +195,7 @@
 #define TIF_BLKCOMMIT		9	/* use ASI_BLK_COMMIT_* in copy_user_page */
 
 #define TIF_POLLING_NRFLAG	10
+#define TIF_ABI_PENDING		11
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
@@ -205,6 +208,7 @@
 #define _TIF_NEWCHILD		(1<<TIF_NEWCHILD)
 #define _TIF_BLKCOMMIT		(1<<TIF_BLKCOMMIT)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+#define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
 
 #define _TIF_USER_WORK_MASK	((0xff << TI_FLAG_WSAVED_SHIFT) | \
 				 (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
diff -Nru a/include/asm-sparc64/timex.h b/include/asm-sparc64/timex.h
--- a/include/asm-sparc64/timex.h	Thu May  2 17:22:17 2002
+++ b/include/asm-sparc64/timex.h	Thu May  2 17:22:17 2002
@@ -16,7 +16,7 @@
 typedef unsigned long cycles_t;
 #define get_cycles() \
 ({	cycles_t ret; \
-	__asm__("rd	%%tick, %0" : "=r" (ret)); \
+	__asm__ __volatile__("rd	%%tick, %0" : "=r" (ret)); \
 	ret; \
 })
 
diff -Nru a/include/asm-sparc64/tlbflush.h b/include/asm-sparc64/tlbflush.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-sparc64/tlbflush.h	Thu May  2 17:22:17 2002
@@ -0,0 +1,93 @@
+#ifndef _SPARC64_TLBFLUSH_H
+#define _SPARC64_TLBFLUSH_H
+
+#include <linux/config.h>
+#include <linux/mm.h>
+
+/* TLB flush operations. */
+
+extern void __flush_tlb_all(void);
+extern void __flush_tlb_mm(unsigned long context, unsigned long r);
+extern void __flush_tlb_range(unsigned long context, unsigned long start,
+			      unsigned long r, unsigned long end,
+			      unsigned long pgsz, unsigned long size);
+extern void __flush_tlb_page(unsigned long context, unsigned long page, unsigned long r);
+
+extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end);
+
+#ifndef CONFIG_SMP
+
+#define flush_tlb_all()		__flush_tlb_all()
+#define flush_tlb_kernel_range(start,end) \
+	__flush_tlb_kernel_range(start,end)
+
+#define flush_tlb_mm(__mm) \
+do { if(CTX_VALID((__mm)->context)) \
+	__flush_tlb_mm(CTX_HWBITS((__mm)->context), SECONDARY_CONTEXT); \
+} while(0)
+
+#define flush_tlb_range(__vma, start, end) \
+do { if(CTX_VALID((__vma)->vm_mm->context)) { \
+	unsigned long __start = (start)&PAGE_MASK; \
+	unsigned long __end = PAGE_ALIGN(end); \
+	__flush_tlb_range(CTX_HWBITS((__vma)->vm_mm->context), __start, \
+			  SECONDARY_CONTEXT, __end, PAGE_SIZE, \
+			  (__end - __start)); \
+     } \
+} while(0)
+
+#define flush_tlb_page(vma, page) \
+do { struct mm_struct *__mm = (vma)->vm_mm; \
+     if(CTX_VALID(__mm->context)) \
+	__flush_tlb_page(CTX_HWBITS(__mm->context), (page)&PAGE_MASK, \
+			 SECONDARY_CONTEXT); \
+} while(0)
+
+#else /* CONFIG_SMP */
+
+extern void smp_flush_tlb_all(void);
+extern void smp_flush_tlb_mm(struct mm_struct *mm);
+extern void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+				unsigned long end);
+extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end);
+extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page);
+
+#define flush_cache_all()	smp_flush_cache_all()
+#define flush_tlb_all()		smp_flush_tlb_all()
+#define flush_tlb_mm(mm)	smp_flush_tlb_mm(mm)
+#define flush_tlb_range(vma, start, end) \
+	smp_flush_tlb_range(vma, start, end)
+#define flush_tlb_kernel_range(start, end) \
+	smp_flush_tlb_kernel_range(start, end)
+#define flush_tlb_page(vma, page) \
+	smp_flush_tlb_page((vma)->vm_mm, page)
+
+#endif /* ! CONFIG_SMP */
+
+static __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start,
+					  unsigned long end)
+{
+	/* Note the signed type.  */
+	long s = start, e = end, vpte_base;
+	if (s > e)
+		/* Nobody should call us with start below VM hole and end above.
+		   See if it is really true.  */
+		BUG();
+#if 0
+	/* Currently free_pgtables guarantees this.  */
+	s &= PMD_MASK;
+	e = (e + PMD_SIZE - 1) & PMD_MASK;
+#endif
+	vpte_base = (tlb_type == spitfire ?
+		     VPTE_BASE_SPITFIRE :
+		     VPTE_BASE_CHEETAH);
+	{
+		struct vm_area_struct vma;
+		vma.vm_mm = mm;
+		flush_tlb_range(&vma,
+				vpte_base + (s >> (PAGE_SHIFT - 3)),
+				vpte_base + (e >> (PAGE_SHIFT - 3)));
+	}
+}
+
+#endif /* _SPARC64_TLBFLUSH_H */
diff -Nru a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
--- a/include/asm-sparc64/unistd.h	Thu May  2 17:22:16 2002
+++ b/include/asm-sparc64/unistd.h	Thu May  2 17:22:16 2002
@@ -175,8 +175,8 @@
 #define __NR_statfs             157 /* Common                                      */
 #define __NR_fstatfs            158 /* Common                                      */
 #define __NR_umount             159 /* Common                                      */
-/* #define __NR_async_daemon    160    SunOS Specific                              */
-/* #define __NR_getfh           161    SunOS Specific                              */
+#define __NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS    */
+#define __NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS           */
 #define __NR_getdomainname      162 /* SunOS Specific                              */
 #define __NR_setdomainname      163 /* Common                                      */
 #define __NR_utrap_install	164 /* SYSV ABI/v9 required			   */
@@ -184,24 +184,24 @@
 /* #define __NR_exportfs        166    SunOS Specific                              */
 #define __NR_mount              167 /* Common                                      */
 #define __NR_ustat              168 /* Common                                      */
-/* #define __NR_semsys          169    SunOS Specific                              */
-/* #define __NR_msgsys          170    SunOS Specific                              */
-/* #define __NR_shmsys          171    SunOS Specific                              */
-/* #define __NR_auditsys        172    SunOS Specific                              */
-/* #define __NR_rfssys          173    SunOS Specific                              */
+#define __NR_setxattr           169 /* SunOS: semsys                               */
+#define __NR_lsetxattr          170 /* SunOS: msgsys                               */
+#define __NR_fsetxattr          171 /* SunOS: shmsys                               */
+#define __NR_getxattr           172 /* SunOS: auditsys                             */
+#define __NR_lgetxattr          173 /* SunOS: rfssys                               */
 #define __NR_getdents           174 /* Common                                      */
 #define __NR_setsid             175 /* Common                                      */
 #define __NR_fchdir             176 /* Common                                      */
-/* #define __NR_fchroot         177    SunOS Specific                              */
-/* #define __NR_vpixsys         178    SunOS Specific                              */
-/* #define __NR_aioread         179    SunOS Specific                              */
-/* #define __NR_aiowrite        180    SunOS Specific                              */
-/* #define __NR_aiowait         181    SunOS Specific                              */
-/* #define __NR_aiocancel       182    SunOS Specific                              */
+#define __NR_fgetxattr          177 /* SunOS: fchroot                              */
+#define __NR_listxattr          178 /* SunOS: vpixsys                              */
+#define __NR_llistxattr         179 /* SunOS: aioread                              */
+#define __NR_flistxattr         180 /* SunOS: aiowrite                             */
+#define __NR_removexattr        181 /* SunOS: aiowait                              */
+#define __NR_lremovexattr       182 /* SunOS: aiocancel                            */
 #define __NR_sigpending         183 /* Common                                      */
 #define __NR_query_module	184 /* Linux Specific				   */
 #define __NR_setpgid            185 /* Common                                      */
-/* #define __NR_pathconf        186    SunOS Specific                              */
+#define __NR_fremovexattr       186 /* SunOS: pathconf                             */
 #define __NR_tkill              187 /* SunOS: fpathconf                            */
 /* #define __NR_sysconf         188    SunOS Specific                              */
 #define __NR_uname              189 /* Linux Specific                              */
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Thu May  2 17:22:16 2002
+++ b/include/linux/blkdev.h	Thu May  2 17:22:16 2002
@@ -56,6 +56,7 @@
 
 	unsigned int current_nr_sectors;
 	unsigned int hard_cur_sectors;
+	int tag;
 	void *special;
 	char *buffer;
 	struct completion *waiting;
@@ -75,6 +76,7 @@
 	__REQ_NOMERGE,	/* don't touch this for merging */
 	__REQ_STARTED,	/* drive already may have started this one */
 	__REQ_DONTPREP,	/* don't call prep for this one */
+	__REQ_QUEUED,	/* uses queueing */
 	/*
 	 * for ATA/ATAPI devices
 	 */
@@ -97,6 +99,7 @@
 #define REQ_NOMERGE	(1 << __REQ_NOMERGE)
 #define REQ_STARTED	(1 << __REQ_STARTED)
 #define REQ_DONTPREP	(1 << __REQ_DONTPREP)
+#define REQ_QUEUED	(1 << __REQ_QUEUED)
 #define REQ_DRIVE_CMD	(1 << __REQ_DRIVE_CMD)
 #define REQ_DRIVE_ACB	(1 << __REQ_DRIVE_ACB)
 #define REQ_PC		(1 << __REQ_PC)
@@ -121,6 +124,17 @@
 	Queue_up,
 };
 
+#define BLK_TAGS_PER_LONG	(sizeof(unsigned long) * 8)
+#define BLK_TAGS_MASK		(BLK_TAGS_PER_LONG - 1)
+
+struct blk_queue_tag {
+	struct request **tag_index;	/* map of busy tags */
+	unsigned long *tag_map;		/* bit map of free/busy tags */
+	struct list_head busy_list;	/* fifo list of busy tags */
+	int busy;			/* current depth */
+	int max_depth;
+};
+
 /*
  * Default nr free requests per queue, ll_rw_blk will scale it down
  * according to available RAM at init time
@@ -193,6 +207,8 @@
 	unsigned long		seg_boundary_mask;
 
 	wait_queue_head_t	queue_wait;
+
+	struct blk_queue_tag	*queue_tags;
 };
 
 #define RQ_INACTIVE		(-1)
@@ -203,9 +219,11 @@
 
 #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 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)
+#define blk_queue_tagged(q)	test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags)
 #define blk_queue_empty(q)	elv_queue_empty(q)
 #define list_entry_rq(ptr)	list_entry((ptr), struct request, queuelist)
 
@@ -310,14 +328,26 @@
 extern void blk_queue_segment_boundary(request_queue_t *q, unsigned long);
 extern void blk_queue_assign_lock(request_queue_t *q, spinlock_t *);
 extern void blk_queue_prep_rq(request_queue_t *q, prep_rq_fn *pfn);
-extern unsigned long *blk_get_ra_pages(kdev_t kdev);
+extern unsigned long *blk_get_ra_pages(struct block_device *bdev);
 
 extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *);
 extern void blk_dump_rq_flags(struct request *, char *);
 extern void generic_unplug_device(void *);
 
+/*
+ * tag stuff
+ */
+#define blk_queue_tag_request(q, tag)	((q)->queue_tags->tag_index[(tag)])
+#define blk_queue_tag_depth(q)		((q)->queue_tags->busy)
+#define blk_queue_tag_queue(q)		((q)->queue_tags->busy < (q)->queue_tags->max_depth)
+#define blk_rq_tagged(rq)		((rq)->flags & REQ_QUEUED)
+extern int blk_queue_start_tag(request_queue_t *, struct request *);
+extern void blk_queue_end_tag(request_queue_t *, struct request *);
+extern int blk_queue_init_tags(request_queue_t *, int);
+extern void blk_queue_free_tags(request_queue_t *);
+extern void blk_queue_invalidate_tags(request_queue_t *);
+
 extern int * blk_size[MAX_BLKDEV];	/* in units of 1024 bytes */
-extern int * blksize_size[MAX_BLKDEV];
 
 #define MAX_PHYS_SEGMENTS 128
 #define MAX_HW_SEGMENTS 128
@@ -335,7 +365,6 @@
 #if 0
 	blk_size_in_bytes[major] = NULL;
 #endif
-	blksize_size[major] = NULL;
 }
 
 extern inline int queue_hardsect_size(request_queue_t *q)
@@ -372,17 +401,9 @@
 	return bits;
 }
 
-extern inline unsigned int block_size(kdev_t dev)
+extern inline unsigned int block_size(struct block_device *bdev)
 {
-	int retval = BLOCK_SIZE;
-	int major = major(dev);
-
-	if (blksize_size[major]) {
-		int minor = minor(dev);
-		if (blksize_size[major][minor])
-			retval = blksize_size[major][minor];
-	}
-	return retval;
+	return bdev->bd_block_size;
 }
 
 static inline loff_t blkdev_size_in_bytes(kdev_t dev)
diff -Nru a/include/linux/buffer_head.h b/include/linux/buffer_head.h
--- a/include/linux/buffer_head.h	Thu May  2 17:22:15 2002
+++ b/include/linux/buffer_head.h	Thu May  2 17:22:15 2002
@@ -151,10 +151,6 @@
 void end_buffer_io_sync(struct buffer_head *bh, int uptodate);
 void buffer_insert_list(spinlock_t *lock,
 			struct buffer_head *, struct list_head *);
-struct buffer_head *get_hash_table(kdev_t dev, sector_t block, int size);
-struct buffer_head *getblk(kdev_t dev, sector_t block, int size);
-struct buffer_head *bread(kdev_t dev, int block, int size);
-
 
 /* reiserfs_writepage needs this */
 void set_buffer_async_io(struct buffer_head *bh);
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Thu May  2 17:22:16 2002
+++ b/include/linux/fs.h	Thu May  2 17:22:16 2002
@@ -343,6 +343,7 @@
 	void *			bd_holder;
 	int			bd_holders;
 	struct block_device *	bd_contains;
+	unsigned		bd_block_size;
 };
 
 struct inode {
@@ -1259,7 +1260,7 @@
 struct bio;
 extern int submit_bio(int, struct bio *);
 extern int is_read_only(kdev_t);
-extern int set_blocksize(kdev_t, int);
+extern int set_blocksize(struct block_device *, int);
 extern int sb_set_blocksize(struct super_block *, int);
 extern int sb_min_blocksize(struct super_block *, int);
 
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Thu May  2 17:22:16 2002
+++ b/include/linux/ide.h	Thu May  2 17:22:16 2002
@@ -283,10 +283,8 @@
 	 */
 	request_queue_t	queue;	/* per device request queue */
 
-	/* Those are directly injected jiffie values. They should go away and
-	 * we should use generic timers instead!!!
-	 */
-	unsigned long PADAM_sleep;	/* sleep until this time */
+
+	unsigned long sleep;	/* sleep until this time */
 
 	/* Flags requesting/indicating one of the following special commands
 	 * executed on the request queue.
diff -Nru a/include/linux/inet.h b/include/linux/inet.h
--- a/include/linux/inet.h	Thu May  2 17:22:16 2002
+++ b/include/linux/inet.h	Thu May  2 17:22:16 2002
@@ -47,7 +47,6 @@
 #include <linux/net.h>
 
 extern void		inet_proto_init(struct net_proto *pro);
-extern char		*in_ntoa(__u32 in);
 extern __u32		in_aton(const char *str);
 
 #endif
diff -Nru a/include/linux/ioport.h b/include/linux/ioport.h
--- a/include/linux/ioport.h	Thu May  2 17:22:16 2002
+++ b/include/linux/ioport.h	Thu May  2 17:22:16 2002
@@ -113,8 +113,4 @@
 #define get_ioport_list(buf)	get_resource_list(&ioport_resource, buf, PAGE_SIZE)
 #define get_mem_list(buf)	get_resource_list(&iomem_resource, buf, PAGE_SIZE)
 
-#define HAVE_AUTOIRQ
-extern void autoirq_setup(int waittime);
-extern int autoirq_report(int waittime);
-
 #endif	/* _LINUX_IOPORT_H */
diff -Nru a/include/linux/irda.h b/include/linux/irda.h
--- a/include/linux/irda.h	Thu May  2 17:22:16 2002
+++ b/include/linux/irda.h	Thu May  2 17:22:16 2002
@@ -67,6 +67,7 @@
 	IRDA_AIRPORT_DONGLE      = 6,
 	IRDA_OLD_BELKIN_DONGLE   = 7,
 	IRDA_EP7211_IR           = 8,
+	IRDA_MCP2120_DONGLE      = 9,
 } IRDA_DONGLE;
 
 /* Protocol types to be used for SOCK_DGRAM */
diff -Nru a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h
--- a/include/linux/kernel_stat.h	Thu May  2 17:22:16 2002
+++ b/include/linux/kernel_stat.h	Thu May  2 17:22:16 2002
@@ -29,9 +29,6 @@
 #if !defined(CONFIG_ARCH_S390)
 	unsigned int irqs[NR_CPUS][NR_IRQS];
 #endif
-	unsigned int ipackets, opackets;
-	unsigned int ierrors, oerrors;
-	unsigned int collisions;
 };
 
 extern struct kernel_stat kstat;
diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h
--- a/include/linux/page-flags.h	Thu May  2 17:22:16 2002
+++ b/include/linux/page-flags.h	Thu May  2 17:22:16 2002
@@ -13,7 +13,7 @@
  *
  * The PG_private bitflag is set if page->private contains a valid value.
  *
- * During disk I/O, PG_locked_dontuse is used. This bit is set before I/O and
+ * During disk I/O, PG_locked is used. This bit is set before I/O and
  * reset when I/O completes. page_waitqueue(page) is a wait queue of all tasks
  * waiting for the I/O on this page to complete.
  *
@@ -28,7 +28,7 @@
  *
  * Note that the referenced bit, the page->lru list_head and the active,
  * inactive_dirty and inactive_clean lists are protected by the
- * pagemap_lru_lock, and *NOT* by the usual PG_locked_dontuse bit!
+ * pagemap_lru_lock, and *NOT* by the usual PG_locked bit!
  *
  * PG_error is set to indicate that an I/O error occurred on this page.
  *
@@ -47,7 +47,7 @@
  * locked- and dirty-page accounting.  The top eight bits of page->flags are
  * used for page->zone, so putting flag bits there doesn't work.
  */
-#define PG_locked_dontuse	 0	/* Page is locked. Don't touch. */
+#define PG_locked	 0	/* Page is locked. Don't touch. */
 #define PG_error		 1
 #define PG_referenced		 2
 #define PG_uptodate		 3
@@ -71,7 +71,7 @@
  */
 extern struct page_state {
 	unsigned long nr_dirty;
-	unsigned long nr_locked;
+	unsigned long nr_writeback;
 	unsigned long nr_pagecache;
 } ____cacheline_aligned_in_smp page_states[NR_CPUS];
 
@@ -91,37 +91,16 @@
 /*
  * Manipulation of page state flags
  */
-#define PageLocked(page)	test_bit(PG_locked_dontuse, &(page)->flags)
-#define SetPageLocked(page)						\
-	do {								\
-		if (!test_and_set_bit(PG_locked_dontuse,		\
-				&(page)->flags))			\
-			inc_page_state(nr_locked);			\
-	} while (0)
-#define TestSetPageLocked(page)						\
-	({								\
-		int ret;						\
-		ret = test_and_set_bit(PG_locked_dontuse,		\
-					&(page)->flags);		\
-		if (!ret)						\
-			inc_page_state(nr_locked);			\
-		ret;							\
-	})
-#define ClearPageLocked(page)						\
-	do {								\
-		if (test_and_clear_bit(PG_locked_dontuse,		\
-				&(page)->flags))			\
-			dec_page_state(nr_locked);			\
-	} while (0)
-#define TestClearPageLocked(page)					\
-	({								\
-		int ret;						\
-		ret = test_and_clear_bit(PG_locked_dontuse,		\
-				&(page)->flags);			\
-		if (ret)						\
-			dec_page_state(nr_locked);			\
-		ret;							\
-	})
+#define PageLocked(page)		\
+		test_bit(PG_locked, &(page)->flags)
+#define SetPageLocked(page)		\
+		set_bit(PG_locked, &(page)->flags)
+#define TestSetPageLocked(page)		\
+		test_and_set_bit(PG_locked, &(page)->flags)
+#define ClearPageLocked(page)		\
+		clear_bit(PG_locked, &(page)->flags)
+#define TestClearPageLocked(page)	\
+		test_and_clear_bit(PG_locked, &(page)->flags)
 
 #define PageError(page)		test_bit(PG_error, &(page)->flags)
 #define SetPageError(page)	set_bit(PG_error, &(page)->flags)
@@ -201,12 +180,36 @@
 #define PagePrivate(page)	test_bit(PG_private, &(page)->flags)
 
 #define PageWriteback(page)	test_bit(PG_writeback, &(page)->flags)
-#define SetPageWriteback(page)	set_bit(PG_writeback, &(page)->flags)
-#define ClearPageWriteback(page) clear_bit(PG_writeback, &(page)->flags)
-#define TestSetPageWriteback(page)	\
-	test_and_set_bit(PG_writeback, &(page)->flags)
-#define TestClearPageWriteback(page)	\
-	test_and_clear_bit(PG_writeback, &(page)->flags)
+#define SetPageWriteback(page)						\
+	do {								\
+		if (!test_and_set_bit(PG_writeback,			\
+				&(page)->flags))			\
+			inc_page_state(nr_writeback);			\
+	} while (0)
+#define TestSetPageWriteback(page)					\
+	({								\
+		int ret;						\
+		ret = test_and_set_bit(PG_writeback,			\
+					&(page)->flags);		\
+		if (!ret)						\
+			inc_page_state(nr_writeback);			\
+		ret;							\
+	})
+#define ClearPageWriteback(page)					\
+	do {								\
+		if (test_and_clear_bit(PG_writeback,			\
+				&(page)->flags))			\
+			dec_page_state(nr_writeback);			\
+	} while (0)
+#define TestClearPageWriteback(page)					\
+	({								\
+		int ret;						\
+		ret = test_and_clear_bit(PG_writeback,			\
+				&(page)->flags);			\
+		if (ret)						\
+			dec_page_state(nr_writeback);			\
+		ret;							\
+	})
 
 /*
  * The PageSwapCache predicate doesn't use a PG_flag at this time,
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Thu May  2 17:22:16 2002
+++ b/include/linux/pci_ids.h	Thu May  2 17:22:16 2002
@@ -1236,6 +1236,8 @@
 #define PCI_DEVICE_ID_PC300_RX_1	0x0301
 #define PCI_DEVICE_ID_PC300_TE_2	0x0310
 #define PCI_DEVICE_ID_PC300_TE_1	0x0311
+#define PCI_DEVICE_ID_PC300_TE_M_2	0x0320
+#define PCI_DEVICE_ID_PC300_TE_M_1	0x0321
 
 #define PCI_VENDOR_ID_ESSENTIAL		0x120f
 #define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER	0x0001
diff -Nru a/include/linux/swap.h b/include/linux/swap.h
--- a/include/linux/swap.h	Thu May  2 17:22:15 2002
+++ b/include/linux/swap.h	Thu May  2 17:22:15 2002
@@ -79,6 +79,7 @@
 	unsigned int flags;
 	spinlock_t sdev_lock;
 	struct file *swap_file;
+	unsigned old_block_size;
 	unsigned short * swap_map;
 	unsigned int lowest_bit;
 	unsigned int highest_bit;
diff -Nru a/include/linux/tcp.h b/include/linux/tcp.h
--- a/include/linux/tcp.h	Thu May  2 17:22:17 2002
+++ b/include/linux/tcp.h	Thu May  2 17:22:17 2002
@@ -231,9 +231,9 @@
 	/* Data for direct copy to user */
 	struct {
 		struct sk_buff_head	prequeue;
-		int			memory;
 		struct task_struct	*task;
 		struct iovec		*iov;
+		int			memory;
 		int			len;
 	} ucopy;
 
diff -Nru a/include/linux/wanrouter.h b/include/linux/wanrouter.h
--- a/include/linux/wanrouter.h	Thu May  2 17:22:16 2002
+++ b/include/linux/wanrouter.h	Thu May  2 17:22:16 2002
@@ -475,7 +475,6 @@
 
 #include <linux/fs.h>		/* support for device drivers */
 #include <linux/proc_fs.h>	/* proc filesystem pragmatics */
-#include <linux/inet.h>		/* in_aton(), in_ntoa() prototypes */
 #include <linux/netdevice.h>	/* support for network drivers */
 /*----------------------------------------------------------------------------
  * WAN device data space.
diff -Nru a/include/math-emu/op-common.h b/include/math-emu/op-common.h
--- a/include/math-emu/op-common.h	Thu May  2 17:22:16 2002
+++ b/include/math-emu/op-common.h	Thu May  2 17:22:16 2002
@@ -25,7 +25,7 @@
 #define __MATH_EMU_OP_COMMON_H__
 
 #define _FP_DECL(wc, X)			\
-  _FP_I_TYPE X##_c, X##_s, X##_e;	\
+  _FP_I_TYPE X##_c=0, X##_s=0, X##_e=0;	\
   _FP_FRAC_DECL_##wc(X)
 
 /*
@@ -780,11 +780,12 @@
 		X##_e -= (_FP_W_TYPE_SIZE - rsize);			\
 	X##_e = rsize - X##_e - 1;					\
 									\
-	if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)	\
-	  __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize);	\
 	r &= ~((rtype)1 << X##_e);					\
+	if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)	\
+	  __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs + 1), rsize);	\
 	_FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize);	\
-	_FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));		\
+	if ((_FP_WFRACBITS_##fs - X##_e - 1) > 0)			\
+	  _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));	\
       }									\
     else								\
       {									\
diff -Nru a/include/net/irda/irlap.h b/include/net/irda/irlap.h
--- a/include/net/irda/irlap.h	Thu May  2 17:22:16 2002
+++ b/include/net/irda/irlap.h	Thu May  2 17:22:16 2002
@@ -31,8 +31,6 @@
 #include <linux/types.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/ppp_defs.h>
-#include <linux/ppp-comp.h>
 #include <linux/timer.h>
 
 #include <net/irda/irlap_event.h>
@@ -52,8 +50,32 @@
 #define CBROADCAST 0xfe       /* Connection broadcast address */
 #define XID_FORMAT 0x01       /* Discovery XID format */
 
+/* Nobody seems to use this constant. */
 #define LAP_WINDOW_SIZE 8
-#define LAP_MAX_QUEUE  10
+/* We keep the LAP queue very small to minimise the amount of buffering.
+ * this improve latency and reduce resource consumption.
+ * This work only because we have synchronous refilling of IrLAP through
+ * the flow control mechanism (via scheduler and IrTTP).
+ * 2 buffers is the minimum we can work with, one that we send while polling
+ * IrTTP, and another to know that we should not send the pf bit.
+ * Jean II */
+#define LAP_HIGH_THRESHOLD     2
+/* Some rare non TTP clients don't implement flow control, and
+ * so don't comply with the above limit (and neither with this one).
+ * For IAP and management, it doesn't matter, because they never transmit much.
+ *.For IrLPT, this should be fixed.
+ * - Jean II */
+#define LAP_MAX_QUEUE 10
+/* Please note that all IrDA management frames (LMP/TTP conn req/disc and
+ * IAS queries) fall in the second category and are sent to LAP even if TTP
+ * is stopped. This means that those frames will wait only a maximum of
+ * two (2) data frames before beeing sent on the "wire", which speed up
+ * new socket setup when the link is saturated.
+ * Same story for two sockets competing for the medium : if one saturates
+ * the LAP, when the other want to transmit it only has to wait for
+ * maximum three (3) packets (2 + one scheduling), which improve performance
+ * of delay sensitive applications.
+ * Jean II */
 
 #define NR_EXPECTED     1
 #define NR_UNEXPECTED   0
@@ -215,5 +237,25 @@
 
 #define IRLAP_GET_HEADER_SIZE(self) (LAP_MAX_HEADER)
 #define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq)
+
+/* Return TRUE if the node is in primary mode (i.e. master)
+ * - Jean II */
+static inline int irlap_is_primary(struct irlap_cb *self)
+{
+	int ret;
+	switch(self->state) {
+	case LAP_XMIT_P:
+	case LAP_NRM_P:
+		ret = 1;
+		break;
+	case LAP_XMIT_S:
+	case LAP_NRM_S:
+		ret = 0;
+		break;
+	default:
+		ret = -1;
+	}
+	return(ret);
+}
 
 #endif
diff -Nru a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h
--- a/include/net/irda/irlmp.h	Thu May  2 17:22:15 2002
+++ b/include/net/irda/irlmp.h	Thu May  2 17:22:15 2002
@@ -132,6 +132,7 @@
 
 	struct irlap_cb *irlap;   /* Instance of IrLAP layer */
 	hashbin_t *lsaps;         /* LSAP associated with this link */
+	struct lsap_cb *flow_next;	/* Next lsap to be polled for Tx */
 
 	__u8  caddr;  /* Connection address */
  	__u32 saddr;  /* Source device address */
@@ -235,6 +236,7 @@
 
 void irlmp_status_request(void);
 void irlmp_status_indication(struct lap_cb *, LINK_STATUS link, LOCK_STATUS lock);
+void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow);
 
 int  irlmp_slsap_inuse(__u8 slsap);
 __u8 irlmp_find_free_slsap(void);
@@ -252,7 +254,9 @@
 
 static inline hashbin_t *irlmp_get_cachelog(void) { return irlmp->cachelog; }
 
-static inline int irlmp_get_lap_tx_queue_len(struct lsap_cb *self)
+/* Check if LAP queue is full.
+ * Used by IrTTP for low control, see comments in irlap.h - Jean II */
+static inline int irlmp_lap_tx_queue_full(struct lsap_cb *self)
 {
 	if (self == NULL)
 		return 0;
@@ -261,7 +265,7 @@
 	if (self->lap->irlap == NULL)
 		return 0;
 
-	return IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap);
+	return(IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap) >= LAP_HIGH_THRESHOLD);
 }
 
 /* After doing a irlmp_dup(), this get one of the two socket back into
@@ -274,6 +278,8 @@
 	self->dlsap_sel = LSAP_ANY;
 	self->lap = NULL;
 	self->lsap_state = LSAP_DISCONNECTED;
+	/* Started when we received the LM_CONNECT_INDICATION */
+	del_timer(&self->watchdog_timer);
 }
 
 #endif
diff -Nru a/include/net/irda/irttp.h b/include/net/irda/irttp.h
--- a/include/net/irda/irttp.h	Thu May  2 17:22:16 2002
+++ b/include/net/irda/irttp.h	Thu May  2 17:22:16 2002
@@ -42,11 +42,48 @@
 #define TTP_PARAMETERS         0x80
 #define TTP_MORE               0x80
 
-#define DEFAULT_INITIAL_CREDIT 14
+/* Transmission queue sizes */
+/* Worst case scenario, two window of data - Jean II */
+#define TTP_TX_MAX_QUEUE	14
+/* We need to keep at least 5 frames to make sure that we can refill
+ * appropriately the LAP layer. LAP keeps only two buffers, and we need
+ * to have 7 to make a full window - Jean II */
+#define TTP_TX_LOW_THRESHOLD	5
+/* Most clients are synchronous with respect to flow control, so we can
+ * keep a low number of Tx buffers in TTP - Jean II */
+#define TTP_TX_HIGH_THRESHOLD	7
+
+/* Receive queue sizes */
+/* Minimum of credit that the peer should hold.
+ * If the peer has less credits than 9 frames, we will explicitely send
+ * him some credits (through irttp_give_credit() and a specific frame).
+ * Note that when we give credits it's likely that it won't be sent in
+ * this LAP window, but in the next one. So, we make sure that the peer
+ * has something to send while waiting for credits (one LAP window == 7
+ * + 1 frames while he process the credits). - Jean II */
+#define TTP_RX_MIN_CREDIT	8
+/* This is the default maximum number of credits held by the peer, so the
+ * default maximum number of frames he can send us before needing flow
+ * control answer from us (this may be negociated differently at TSAP setup).
+ * We want to minimise the number of times we have to explicitely send some
+ * credit to the peer, hoping we can piggyback it on the return data. In
+ * particular, it doesn't make sense for us to send credit more than once
+ * per LAP window.
+ * Moreover, giving credits has some latency, so we need strictly more than
+ * a LAP window, otherwise we may already have credits in our Tx queue.
+ * But on the other hand, we don't want to keep too many Rx buffer here
+ * before starting to flow control the other end, so make it exactly one
+ * LAP window + 1 + MIN_CREDITS. - Jean II */
+#define TTP_RX_DEFAULT_CREDIT	16
+/* Maximum number of credits we can allow the peer to have, and therefore
+ * maximum Rx queue size.
+ * Note that we try to deliver packets to the higher layer every time we
+ * receive something, so in normal mode the Rx queue will never contains
+ * more than one or two packets. - Jean II */
+#define TTP_RX_MAX_CREDIT	21
 
-#define TTP_LOW_THRESHOLD       4
-#define TTP_HIGH_THRESHOLD     10
-#define TTP_MAX_QUEUE          14
+/* What clients should use when calling ttp_open_tsap() */
+#define DEFAULT_INITIAL_CREDIT	TTP_RX_DEFAULT_CREDIT
 
 /* Some priorities for disconnect requests */
 #define P_NORMAL    0
@@ -90,7 +127,7 @@
 
 	struct net_device_stats stats;
 	struct timer_list todo_timer; 
-	
+
 	__u32 max_seg_size;     /* Max data that fit into an IrLAP frame */
 	__u8  max_header_size;
 
@@ -131,6 +168,7 @@
 void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow);
 void irttp_status_indication(void *instance,
 			     LINK_STATUS link, LOCK_STATUS lock);
+void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow);
 struct tsap_cb *irttp_dup(struct tsap_cb *self, void *instance);
 
 static __inline __u32 irttp_get_saddr(struct tsap_cb *self)
@@ -157,6 +195,18 @@
 {
 	irlmp_listen(self->lsap);
 	self->dtsap_sel = LSAP_ANY;
+}
+
+/* Return TRUE if the node is in primary mode (i.e. master)
+ * - Jean II */
+static inline int irttp_is_primary(struct tsap_cb *self)
+{
+	if ((self == NULL) ||
+	    (self->lsap == NULL) ||
+	    (self->lsap->lap == NULL) ||
+	    (self->lsap->lap->irlap == NULL))
+		return -2;
+	return(irlap_is_primary(self->lsap->lap->irlap));
 }
 
 extern struct irttp_cb *irttp;
diff -Nru a/include/net/tcp.h b/include/net/tcp.h
--- a/include/net/tcp.h	Thu May  2 17:22:16 2002
+++ b/include/net/tcp.h	Thu May  2 17:22:16 2002
@@ -828,6 +828,11 @@
 
 extern const char timer_bug_msg[];
 
+/* Read 'sendfile()'-style from a TCP socket */
+typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *,
+				unsigned int, size_t);
+extern int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
+			 sk_read_actor_t recv_actor);
 
 static inline void tcp_clear_xmit_timer(struct sock *sk, int what)
 {
diff -Nru a/kernel/acct.c b/kernel/acct.c
--- a/kernel/acct.c	Thu May  2 17:22:17 2002
+++ b/kernel/acct.c	Thu May  2 17:22:17 2002
@@ -160,8 +160,6 @@
 {
 	struct file *old_acct = NULL;
 
-	BUG_ON(!spin_is_locked(&acct_globals.lock));
-
 	if (acct_globals.file) {
 		old_acct = acct_globals.file;
 		del_timer(&acct_globals.timer);
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Thu May  2 17:22:15 2002
+++ b/kernel/ksyms.c	Thu May  2 17:22:15 2002
@@ -144,6 +144,7 @@
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(follow_down);
 EXPORT_SYMBOL(lookup_mnt);
+EXPORT_SYMBOL(path_lookup);
 EXPORT_SYMBOL(path_init);
 EXPORT_SYMBOL(path_walk);
 EXPORT_SYMBOL(path_release);
@@ -317,7 +318,6 @@
 EXPORT_SYMBOL(tty_std_termios);
 
 /* block device driver support */
-EXPORT_SYMBOL(blksize_size);
 EXPORT_SYMBOL(blk_size);
 EXPORT_SYMBOL(blk_dev);
 EXPORT_SYMBOL(is_read_only);
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Thu May  2 17:22:16 2002
+++ b/mm/filemap.c	Thu May  2 17:22:16 2002
@@ -628,7 +628,7 @@
  */
 void ___wait_on_page_locked(struct page *page)
 {
-	wait_on_page_bit(page, PG_locked_dontuse);
+	wait_on_page_bit(page, PG_locked);
 }
 EXPORT_SYMBOL(___wait_on_page_locked);
 
diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c
--- a/mm/page-writeback.c	Thu May  2 17:22:16 2002
+++ b/mm/page-writeback.c	Thu May  2 17:22:16 2002
@@ -29,12 +29,12 @@
 /*
  * Start background writeback (via pdflush) at this level
  */
-static int dirty_background_ratio = 30;
+static int dirty_background_ratio = 40;
 
 /*
  * The generator of dirty data starts async writeback at this level
  */
-static int dirty_async_ratio = 45;
+static int dirty_async_ratio = 50;
 
 /*
  * The generator of dirty data performs sync writeout at this level
@@ -62,25 +62,27 @@
 	int async_thresh;
 	int sync_thresh;
 	int wake_pdflush = 0;
-	unsigned long dirty_and_locked;
+	unsigned long dirty_and_writeback;
 
 	get_page_state(&ps);
-	dirty_and_locked = ps.nr_dirty + ps.nr_locked;
+	dirty_and_writeback = ps.nr_dirty + ps.nr_writeback;
 
 	background_thresh = (dirty_background_ratio * tot) / 100;
 	async_thresh = (dirty_async_ratio * tot) / 100;
 	sync_thresh = (dirty_sync_ratio * tot) / 100;
 
-	if (dirty_and_locked > sync_thresh) {
-		int nr_to_write = dirty_and_locked - async_thresh;
+	if (dirty_and_writeback > sync_thresh) {
+		int nr_to_write = 1500;
 
 		writeback_unlocked_inodes(&nr_to_write, WB_SYNC_LAST, NULL);
+		get_page_state(&ps);
+		dirty_and_writeback = ps.nr_dirty + ps.nr_writeback;
 		wake_pdflush = 1;
-	} else if (dirty_and_locked > async_thresh) {
-		int nr_to_write = dirty_and_locked - async_thresh;
+	} else if (dirty_and_writeback > async_thresh) {
+		int nr_to_write = 1500;
 
 		writeback_unlocked_inodes(&nr_to_write, WB_SYNC_NONE, NULL);
-	} else if (dirty_and_locked > background_thresh) {
+	} else if (dirty_and_writeback > background_thresh) {
 		wake_pdflush = 1;
 	}
 
@@ -88,9 +90,8 @@
 		/*
 		 * There is no flush thread against this device. Start one now.
 		 */
-		get_page_state(&ps);
-		if (ps.nr_dirty > 0) {
-			pdflush_flush(ps.nr_dirty);
+		if (dirty_and_writeback > async_thresh) {
+			pdflush_flush(dirty_and_writeback - async_thresh);
 			yield();
 		}
 	}
@@ -109,7 +110,7 @@
 
 	preempt_disable();
 	cpu = smp_processor_id();
-	if (ratelimits[cpu].count++ >= 32) {
+	if (ratelimits[cpu].count++ >= 1000) {
 		ratelimits[cpu].count = 0;
 		preempt_enable();
 		balance_dirty_pages(mapping);
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Thu May  2 17:22:16 2002
+++ b/mm/page_alloc.c	Thu May  2 17:22:16 2002
@@ -584,7 +584,7 @@
 	int pcpu;
 
 	ret->nr_dirty = 0;
-	ret->nr_locked = 0;
+	ret->nr_writeback = 0;
 	ret->nr_pagecache = 0;
 
 	for (pcpu = 0; pcpu < smp_num_cpus; pcpu++) {
@@ -592,7 +592,7 @@
 
 		ps = &page_states[cpu_logical_map(pcpu)];
 		ret->nr_dirty += ps->nr_dirty;
-		ret->nr_locked += ps->nr_locked;
+		ret->nr_writeback += ps->nr_writeback;
 		ret->nr_pagecache += ps->nr_pagecache;
 	}
 }
diff -Nru a/mm/swapfile.c b/mm/swapfile.c
--- a/mm/swapfile.c	Thu May  2 17:22:16 2002
+++ b/mm/swapfile.c	Thu May  2 17:22:16 2002
@@ -14,6 +14,7 @@
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
 #include <linux/shm.h>
+#include <linux/blkdev.h>
 #include <linux/compiler.h>
 
 #include <asm/pgtable.h>
@@ -787,8 +788,12 @@
 	swap_device_unlock(p);
 	swap_list_unlock();
 	vfree(swap_map);
-	if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode))
-		bd_release(swap_file->f_dentry->d_inode->i_bdev);
+	if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) {
+		struct block_device *bdev;
+		bdev = swap_file->f_dentry->d_inode->i_bdev;
+		set_blocksize(bdev, p->old_block_size);
+		bd_release(bdev);
+	}
 	filp_close(swap_file, NULL);
 	err = 0;
 
@@ -879,6 +884,7 @@
 		nr_swapfiles = type+1;
 	p->flags = SWP_USED;
 	p->swap_file = NULL;
+	p->old_block_size = 0;
 	p->swap_map = NULL;
 	p->lowest_bit = 0;
 	p->highest_bit = 0;
@@ -914,7 +920,8 @@
 			bdev = NULL;
 			goto bad_swap;
 		}
-		error = set_blocksize(swap_file->f_dentry->d_inode->i_rdev,
+		p->old_block_size = block_size(bdev);
+		error = set_blocksize(swap_file->f_dentry->d_inode->i_bdev,
 				      PAGE_SIZE);
 		if (error < 0)
 			goto bad_swap;
@@ -1066,8 +1073,10 @@
 	error = 0;
 	goto out;
 bad_swap:
-	if (bdev)
+	if (bdev) {
+		set_blocksize(bdev, p->old_block_size);
 		bd_release(bdev);
+	}
 bad_swap_2:
 	swap_list_lock();
 	swap_map = p->swap_map;
diff -Nru a/net/Config.help b/net/Config.help
--- a/net/Config.help	Thu May  2 17:22:16 2002
+++ b/net/Config.help	Thu May  2 17:22:16 2002
@@ -190,11 +190,11 @@
   The module is called decnet.o.
 
 CONFIG_ATALK
-  AppleTalk is the way Apple computers speak to each other on a
-  network.  If your Linux box is connected to such a network and you
-  want to join the conversation, say Y.  You will need to use the
-  netatalk package so that your Linux box can act as a print and file
-  server for Macs as well as access AppleTalk printers.  Check out
+  AppleTalk is the protocol that Apple computers can use to communicate
+  on a network.  If your Linux box is connected to such a network and you
+  wish to connect to it, say Y.  You will need to use the netatalk package
+  so that your Linux box can act as a print and file server for Macs as
+  well as access AppleTalk printers.  Check out
   <http://www.zettabyte.net/netatalk/> on the WWW for details.
   EtherTalk is the name used for AppleTalk over Ethernet and the
   cheaper and slower LocalTalk is AppleTalk over a proprietary Apple
diff -Nru a/net/Config.in b/net/Config.in
--- a/net/Config.in	Thu May  2 17:22:16 2002
+++ b/net/Config.in	Thu May  2 17:22:16 2002
@@ -52,7 +52,10 @@
 if [ "$CONFIG_IPX" != "n" ]; then
    source net/ipx/Config.in
 fi
+
 tristate 'Appletalk protocol support' CONFIG_ATALK
+source drivers/net/appletalk/Config.in
+
 tristate 'DECnet Support' CONFIG_DECNET
 if [ "$CONFIG_DECNET" != "n" ]; then
    source net/decnet/Config.in
@@ -68,10 +71,10 @@
 #   fi
    if [ "$CONFIG_INET" = "y" ]; then
       tristate 'Acorn Econet/AUN protocols (EXPERIMENTAL)' CONFIG_ECONET
-   fi
-   if [ "$CONFIG_ECONET" != "n" ]; then
-      bool '  AUN over UDP' CONFIG_ECONET_AUNUDP
-      bool '  Native Econet' CONFIG_ECONET_NATIVE
+      if [ "$CONFIG_ECONET" != "n" ]; then
+	 bool '  AUN over UDP' CONFIG_ECONET_AUNUDP
+	 bool '  Native Econet' CONFIG_ECONET_NATIVE
+      fi
    fi
    tristate 'WAN router' CONFIG_WAN_ROUTER
    bool 'Fast switching (read help!)' CONFIG_NET_FASTROUTE
diff -Nru a/net/bridge/br_forward.c b/net/bridge/br_forward.c
--- a/net/bridge/br_forward.c	Thu May  2 17:22:16 2002
+++ b/net/bridge/br_forward.c	Thu May  2 17:22:16 2002
@@ -48,12 +48,8 @@
 
 static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb)
 {
-	struct net_device *indev;
-
-	indev = skb->dev;
 	skb->dev = to->dev;
-
-	NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, indev, skb->dev,
+	NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
 			__br_forward_finish);
 }
 
diff -Nru a/net/bridge/br_input.c b/net/bridge/br_input.c
--- a/net/bridge/br_input.c	Thu May  2 17:22:16 2002
+++ b/net/bridge/br_input.c	Thu May  2 17:22:16 2002
@@ -161,8 +161,10 @@
 handle_special_frame:
 	if (!dest[5]) {
 		br_stp_handle_bpdu(skb);
+		read_unlock(&br->lock);
 		return;
 	}
 
 	kfree_skb(skb);
+	read_unlock(&br->lock);
 }
diff -Nru a/net/core/netfilter.c b/net/core/netfilter.c
--- a/net/core/netfilter.c	Thu May  2 17:22:17 2002
+++ b/net/core/netfilter.c	Thu May  2 17:22:17 2002
@@ -83,8 +83,7 @@
 /* Do exclusive ranges overlap? */
 static inline int overlap(int min1, int max1, int min2, int max2)
 {
-	return (min1 >= min2 && min1 < max2)
-		|| (max1 > min2 && max1 <= max2);
+	return max1 > min2 && min1 < max2;
 }
 
 /* Functions to register sockopt ranges (exclusive). */
diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
--- a/net/ipv4/af_inet.c	Thu May  2 17:22:16 2002
+++ b/net/ipv4/af_inet.c	Thu May  2 17:22:16 2002
@@ -1158,8 +1158,8 @@
 					   sizeof(struct raw_sock), 0,
 					   SLAB_HWCACHE_ALIGN, 0, 0);
         if (!tcp_sk_cachep || !udp_sk_cachep || !raw4_sk_cachep)
-		printk(KERN_CRIT __FUNCTION__
-			": Can't create protocol sock SLAB caches!\n");
+		printk(KERN_CRIT
+		       "inet_init: Can't create protocol sock SLAB caches!\n");
 	/*
 	 *	Tell SOCKET that we are alive... 
 	 */
diff -Nru a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
--- a/net/ipv4/fib_frontend.c	Thu May  2 17:22:17 2002
+++ b/net/ipv4/fib_frontend.c	Thu May  2 17:22:17 2002
@@ -604,6 +604,11 @@
 	struct net_device *dev = ptr;
 	struct in_device *in_dev = __in_dev_get(dev);
 
+	if (event == NETDEV_UNREGISTER) {
+		fib_disable_ip(dev, 2);
+		return NOTIFY_DONE;
+	}
+
 	if (!in_dev)
 		return NOTIFY_DONE;
 
@@ -619,9 +624,6 @@
 		break;
 	case NETDEV_DOWN:
 		fib_disable_ip(dev, 0);
-		break;
-	case NETDEV_UNREGISTER:
-		fib_disable_ip(dev, 1);
 		break;
 	case NETDEV_CHANGEMTU:
 	case NETDEV_CHANGE:
diff -Nru a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
--- a/net/ipv4/fib_semantics.c	Thu May  2 17:22:16 2002
+++ b/net/ipv4/fib_semantics.c	Thu May  2 17:22:16 2002
@@ -185,6 +185,7 @@
 			continue;
 		for_nexthops(fi) {
 			if (nh->nh_dev == dev && nh->nh_gw == gw &&
+			    nh->nh_scope == RT_SCOPE_LINK &&
 			    !(nh->nh_flags&RTNH_F_DEAD)) {
 				read_unlock(&fib_info_lock);
 				return 0;
@@ -379,15 +380,23 @@
 		/* It is not necessary, but requires a bit of thinking */
 		if (key.scope < RT_SCOPE_LINK)
 			key.scope = RT_SCOPE_LINK;
-
 		if ((err = fib_lookup(&key, &res)) != 0)
 			return err;
+		err = -EINVAL;
+		if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
+			goto out;
 		nh->nh_scope = res.scope;
 		nh->nh_oif = FIB_RES_OIF(res);
-		nh->nh_dev = FIB_RES_DEV(res);
-		if (nh->nh_dev)
-			atomic_inc(&nh->nh_dev->refcnt);
+		if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
+			goto out;
+		atomic_inc(&nh->nh_dev->refcnt);
+		err = -ENETDOWN;
+		if (!(nh->nh_dev->flags & IFF_UP))
+			goto out;
+		err = 0;
+out:
 		fib_res_put(&res);
+		return err;
 	} else {
 		struct in_device *in_dev;
 
@@ -875,13 +884,15 @@
 					fi->fib_power -= nh->nh_power;
 					nh->nh_power = 0;
 					spin_unlock_bh(&fib_multipath_lock);
-					if (force && nh->nh_dev) {
-						dev_put(nh->nh_dev);
-						nh->nh_dev = NULL;
-					}
 #endif
 					dead++;
 				}
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+				if (force > 1 && nh->nh_dev == dev) {
+					dead = fi->fib_nhs;
+					break;
+				}
+#endif
 			} endfor_nexthops(fi)
 			if (dead == fi->fib_nhs) {
 				fi->fib_flags |= RTNH_F_DEAD;
@@ -913,10 +924,6 @@
 			if (!(nh->nh_flags&RTNH_F_DEAD)) {
 				alive++;
 				continue;
-			}
-			if (nh->nh_dev == NULL && nh->nh_oif == dev->ifindex) {
-				dev_hold(dev);
-				nh->nh_dev = dev;
 			}
 			if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
 				continue;
diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c
--- a/net/ipv4/tcp.c	Thu May  2 17:22:16 2002
+++ b/net/ipv4/tcp.c	Thu May  2 17:22:16 2002
@@ -251,6 +251,7 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/fs.h>
 
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -1375,6 +1376,84 @@
 
 	/* Clear memory counter. */
 	tp->ucopy.memory = 0;
+}
+
+static inline
+struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
+{
+	struct sk_buff *skb;
+	u32 offset;
+
+	skb_queue_walk(&sk->receive_queue, skb) {
+		offset = seq - TCP_SKB_CB(skb)->seq;
+		if (skb->h.th->syn)
+			offset--;
+		if (offset < skb->len || skb->h.th->fin) {
+			*off = offset;
+			return skb;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * This routine provides an alternative to tcp_recvmsg() for routines
+ * that would like to handle copying from skbuffs directly in 'sendfile'
+ * fashion.
+ * Note:
+ *	- It is assumed that the socket was locked by the caller.
+ *	- The routine does not block.
+ *	- At present, there is no support for reading OOB data
+ *	  or for 'peeking' the socket using this routine
+ *	  (although both would be easy to implement).
+ */
+int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
+		  sk_read_actor_t recv_actor)
+{
+	struct sk_buff *skb;
+	struct tcp_opt *tp = tcp_sk(sk);
+	u32 seq = tp->copied_seq;
+	u32 offset;
+	int copied = 0;
+
+	if (sk->state == TCP_LISTEN)
+		return -ENOTCONN;
+	while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) {
+		if (offset < skb->len) {
+			size_t used, len;
+
+			len = skb->len - offset;
+			/* Stop reading if we hit a patch of urgent data */
+			if (tp->urg_data) {
+				u32 urg_offset = tp->urg_seq - seq;
+				if (urg_offset < len)
+					len = urg_offset;
+				if (!len)
+					break;
+			}
+			used = recv_actor(desc, skb, offset, len);
+			if (used <= len) {
+				seq += used;
+				copied += used;
+				offset += used;
+			}
+			if (offset != skb->len)
+				break;
+		}
+		if (skb->h.th->fin) {
+			tcp_eat_skb(sk, skb);
+			++seq;
+			break;
+		}
+		tcp_eat_skb(sk, skb);
+		if (!desc->count)
+			break;
+	}
+	tp->copied_seq = seq;
+	/* Clean up data we have read: This will do ACK frames. */
+	if (copied)
+		cleanup_rbuf(sk, copied);
+	return copied;
 }
 
 /*
diff -Nru a/net/ipv4/utils.c b/net/ipv4/utils.c
--- a/net/ipv4/utils.c	Thu May  2 17:22:17 2002
+++ b/net/ipv4/utils.c	Thu May  2 17:22:17 2002
@@ -43,21 +43,6 @@
 
 
 /*
- *	Display an IP address in readable format. 
- */
- 
-char *in_ntoa(__u32 in)
-{
-	static char buff[18];
-	char *p;
-
-	p = (char *) &in;
-	sprintf(buff, "%d.%d.%d.%d",
-		(p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
-	return(buff);
-}
-
-/*
  *	Convert an ASCII string to binary IP. 
  */
  
diff -Nru a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
--- a/net/ipv6/addrconf.c	Thu May  2 17:22:17 2002
+++ b/net/ipv6/addrconf.c	Thu May  2 17:22:17 2002
@@ -1833,7 +1833,7 @@
 		break;
 	case RTM_DELADDR:
 		addrconf_leave_solict(ifp->idev->dev, &ifp->addr);
-		if (!ipv6_chk_addr(&ifp->addr, ifp->idev->dev))
+		if (!ipv6_chk_addr(&ifp->addr, NULL))
 			ip6_rt_addr_del(&ifp->addr, ifp->idev->dev);
 		break;
 	}
diff -Nru a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
--- a/net/ipv6/netfilter/ip6_tables.c	Thu May  2 17:22:17 2002
+++ b/net/ipv6/netfilter/ip6_tables.c	Thu May  2 17:22:17 2002
@@ -110,7 +110,7 @@
 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
 
 #ifdef CONFIG_SMP
-#define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*cpu_number_map(p))
+#define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
 #else
 #define TABLE_OFFSET(t,p) 0
 #endif
@@ -336,7 +336,8 @@
 	read_lock_bh(&table->lock);
 	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
 	table_base = (void *)table->private->entries
-		+ TABLE_OFFSET(table->private, smp_processor_id());
+		+ TABLE_OFFSET(table->private, 
+				cpu_number_map(smp_processor_id()));
 	e = get_entry(table_base, table->private->hook_entry[hook]);
 
 #ifdef CONFIG_NETFILTER_DEBUG
@@ -426,7 +427,7 @@
 #endif
 				/* Target might have changed stuff. */
 				ipv6 = (*pskb)->nh.ipv6h;
-				protohdr = (u_int32_t *)ipv6 + IPV6_HDR_LEN;
+				protohdr = (u_int32_t *)((void *)ipv6 + IPV6_HDR_LEN);
 				datalen = (*pskb)->len - IPV6_HDR_LEN;
 
 				if (verdict == IP6T_CONTINUE)
@@ -913,7 +914,7 @@
 
 	/* And one copy for every other CPU */
 	for (i = 1; i < smp_num_cpus; i++) {
-		memcpy(newinfo->entries + SMP_ALIGN(newinfo->size*i),
+		memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i,
 		       newinfo->entries,
 		       SMP_ALIGN(newinfo->size));
 	}
@@ -1795,9 +1796,15 @@
 	}
 
 #ifdef CONFIG_PROC_FS
-	if (!proc_net_create("ip6_tables_names", 0, ip6t_get_tables)) {
-		nf_unregister_sockopt(&ip6t_sockopts);
-		return -ENOMEM;
+	{
+		struct proc_dir_entry *proc;
+		proc = proc_net_create("ip6_tables_names", 0,
+					ip6t_get_tables);
+		if (!proc) {
+			nf_unregister_sockopt(&ip6t_sockopts);
+			return -ENOMEM;
+		}
+		proc->owner = THIS_MODULE;
 	}
 #endif
 
diff -Nru a/net/ipv6/netfilter/ip6t_mac.c b/net/ipv6/netfilter/ip6t_mac.c
--- a/net/ipv6/netfilter/ip6t_mac.c	Thu May  2 17:22:17 2002
+++ b/net/ipv6/netfilter/ip6t_mac.c	Thu May  2 17:22:17 2002
@@ -34,8 +34,10 @@
 		   unsigned int hook_mask)
 {
 	if (hook_mask
-	    & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN))) {
-		printk("ip6t_mac: only valid for PRE_ROUTING or LOCAL_IN.\n");
+	    & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN)
+		| (1 << NF_IP6_FORWARD))) {
+		printk("ip6t_mac: only valid for PRE_ROUTING, LOCAL_IN or"
+		       " FORWARD\n");
 		return 0;
 	}
 
@@ -60,3 +62,5 @@
 
 module_init(init);
 module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MAC address matching module for IPv6");
diff -Nru a/net/ipv6/raw.c b/net/ipv6/raw.c
--- a/net/ipv6/raw.c	Thu May  2 17:22:16 2002
+++ b/net/ipv6/raw.c	Thu May  2 17:22:16 2002
@@ -281,6 +281,16 @@
 
 static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
 {
+#if defined(CONFIG_FILTER)
+	if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
+		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
+			IP6_INC_STATS_BH(Ip6InDiscards);
+			kfree_skb(skb);
+			return 0;
+		}
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	}
+#endif
 	/* Charge it to the socket. */
 	if (sock_queue_rcv_skb(sk,skb)<0) {
 		IP6_INC_STATS_BH(Ip6InDiscards);
@@ -302,10 +312,35 @@
 int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
 {
 	struct inet_opt *inet = inet_sk(sk);
+	struct raw6_opt *raw_opt = raw6_sk(sk);
+
+	if (!raw_opt->checksum)
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
+		if (skb->ip_summed == CHECKSUM_HW) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+			if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
+					    &skb->nh.ipv6h->daddr,
+					    skb->len, inet->num, skb->csum)) {
+				NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "raw v6 hw csum failure.\n"));
+				skb->ip_summed = CHECKSUM_NONE;
+			}
+		}
+		if (skb->ip_summed == CHECKSUM_NONE)
+			skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr,
+						     &skb->nh.ipv6h->daddr,
+						     skb->len, inet->num, 0);
+	}
 
 	if (inet->hdrincl) {
-		__skb_push(skb, skb->nh.raw - skb->data);
-		skb->h.raw = skb->nh.raw;
+		if (skb->ip_summed != CHECKSUM_UNNECESSARY &&
+		    (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
+			IP6_INC_STATS_BH(Ip6InDiscards);
+			kfree_skb(skb);
+			return 0;
+		}
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
 
 	rawv6_rcv_skb(sk, skb);
@@ -345,7 +380,17 @@
   		msg->msg_flags |= MSG_TRUNC;
   	}
 
-	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+	if (skb->ip_summed==CHECKSUM_UNNECESSARY) {
+		err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+	} else if (msg->msg_flags&MSG_TRUNC) {
+		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)))
+			goto csum_copy_err;
+		err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+	} else {
+		err = skb_copy_and_csum_datagram_iovec(skb, 0, msg->msg_iov);
+		if (err == -EINVAL)
+			goto csum_copy_err;
+	}
 	if (err)
 		goto out_free;
 
@@ -372,6 +417,27 @@
 	skb_free_datagram(sk, skb);
 out:
 	return err;
+
+csum_copy_err:
+	/* Clear queue. */
+	if (flags&MSG_PEEK) {
+		int clear = 0;
+		spin_lock_irq(&sk->receive_queue.lock);
+		if (skb == skb_peek(&sk->receive_queue)) {
+			__skb_unlink(skb, &sk->receive_queue);
+			clear = 1;
+		}
+		spin_unlock_irq(&sk->receive_queue.lock);
+		if (clear)
+			kfree_skb(skb);
+	}
+
+	/* Error for blocking case is chosen to masquerade
+	   as some normal condition.
+	 */
+	err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
+	IP6_INC_STATS_USER(Ip6InDiscards);
+	goto out_free;
 }
 
 /*
diff -Nru a/net/ipv6/sit.c b/net/ipv6/sit.c
--- a/net/ipv6/sit.c	Thu May  2 17:22:17 2002
+++ b/net/ipv6/sit.c	Thu May  2 17:22:17 2002
@@ -64,7 +64,8 @@
 static int ipip6_tunnel_init(struct net_device *dev);
 
 static struct net_device ipip6_fb_tunnel_dev = {
-	"sit0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipip6_fb_tunnel_init,
+	name: "sit0",
+	init: ipip6_fb_tunnel_init
 };
 
 static struct ip_tunnel ipip6_fb_tunnel = {
diff -Nru a/net/ipv6/udp.c b/net/ipv6/udp.c
--- a/net/ipv6/udp.c	Thu May  2 17:22:16 2002
+++ b/net/ipv6/udp.c	Thu May  2 17:22:16 2002
@@ -508,7 +508,7 @@
 {
 #if defined(CONFIG_FILTER)
 	if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
-		if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) {
+		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
 			UDP6_INC_STATS_BH(UdpInErrors);
 			IP6_INC_STATS_BH(Ip6InDiscards);
 			kfree_skb(skb);
diff -Nru a/net/irda/af_irda.c b/net/irda/af_irda.c
--- a/net/irda/af_irda.c	Thu May  2 17:22:16 2002
+++ b/net/irda/af_irda.c	Thu May  2 17:22:16 2002
@@ -568,15 +568,17 @@
 	if(self->iriap == NULL)
 		return -ENOMEM;
 
-	/* Treat unexpected signals as disconnect */
+	/* Treat unexpected wakeup as disconnect */
 	self->errno = -EHOSTUNREACH;
 
 	/* Query remote LM-IAS */
 	iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr,
 				      name, "IrDA:TinyTP:LsapSel");
-	/* Wait for answer (if not already failed) */
-	if(self->iriap != NULL)
-		interruptible_sleep_on(&self->query_wait);
+
+	/* Wait for answer, if not yet finished (or failed) */
+	if (wait_event_interruptible(self->query_wait, (self->iriap==NULL)))
+		/* Treat signals as disconnect */
+		return -EHOSTUNREACH;
 
 	/* Check what happened */
 	if (self->errno)
@@ -877,16 +879,47 @@
 	 *	The read queue this time is holding sockets ready to use
 	 *	hooked into the SABM we saved
 	 */
-	do {
-		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
-			if (flags & O_NONBLOCK)
-				return -EWOULDBLOCK;
 
-			interruptible_sleep_on(sk->sleep);
-			if (signal_pending(current)) 
-				return -ERESTARTSYS;
+	/*
+	 * We can perform the accept only if there is incomming data
+	 * on the listening socket.
+	 * So, we will block the caller until we receive any data.
+	 * If the caller was waiting on select() or poll() before
+	 * calling us, the data is waiting for us ;-)
+	 * Jean II
+	 */
+	skb = skb_dequeue(&sk->receive_queue);
+	if (skb == NULL) {
+		int ret = 0;
+		DECLARE_WAITQUEUE(waitq, current);
+
+		/* Non blocking operation */
+		if (flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+
+		/* The following code is a cut'n'paste of the
+		 * wait_event_interruptible() macro.
+		 * We don't us the macro because the condition has
+		 * side effects : we want to make sure that only one
+		 * skb get dequeued - Jean II */
+		add_wait_queue(sk->sleep, &waitq);
+		for (;;) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			skb = skb_dequeue(&sk->receive_queue);
+			if (skb != NULL)
+				break;
+			if (!signal_pending(current)) {
+				schedule();
+				continue;
+			}
+			ret = -ERESTARTSYS;
+			break;
 		}
-	} while (skb == NULL);
+		current->state = TASK_RUNNING;
+		remove_wait_queue(sk->sleep, &waitq);
+		if(ret)
+			return -ERESTARTSYS;
+	}
 
  	newsk = newsock->sk;
 	newsk->state = TCP_ESTABLISHED;
@@ -1024,19 +1057,9 @@
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
 		return -EINPROGRESS;
 
-	/* Here, there is a race condition : the state may change between
-	 * our test and the sleep, via irda_connect_confirm().
-	 * The way to workaround that is to sleep with a timeout, so that
-	 * we don't sleep forever and check the state when waking up.
-	 * 50ms is plenty good enough, because the LAP is already connected.
-	 * Jean II */
-	while (sk->state == TCP_SYN_SENT) {
-		interruptible_sleep_on_timeout(sk->sleep, HZ/20);
-		if (signal_pending(current)) {
-			return -ERESTARTSYS;
-		}
-	}
-	
+	if (wait_event_interruptible(*(sk->sleep), (sk->state!=TCP_SYN_SENT)))
+		return -ERESTARTSYS;
+
 	if (sk->state != TCP_ESTABLISHED) {
 		sock->state = SS_UNCONNECTED;
 		return sock_error(sk);	/* Always set at this point */
@@ -1280,17 +1303,14 @@
 	ASSERT(self != NULL, return -1;);
 
 	/* Check if IrTTP is wants us to slow down */
-	while (self->tx_flow == FLOW_STOP) {
-		IRDA_DEBUG(2, __FUNCTION__ "(), IrTTP is busy, going to sleep!\n");
-		interruptible_sleep_on(sk->sleep);
-		
-		/* Check if we are still connected */
-		if (sk->state != TCP_ESTABLISHED)
-			return -ENOTCONN;
-		/* Handle signals */
-		if (signal_pending(current)) 
-			return -ERESTARTSYS;
-	}
+
+	if (wait_event_interruptible(*(sk->sleep),
+	    (self->tx_flow != FLOW_STOP  ||  sk->state != TCP_ESTABLISHED)))
+		return -ERESTARTSYS;
+
+	/* Check if we are still connected */
+	if (sk->state != TCP_ESTABLISHED)
+		return -ENOTCONN;
 
 	/* Check that we don't send out to big frames */
 	if (len > self->max_data_size) {
@@ -1382,14 +1402,23 @@
  *
  *    Sleep until data has arrive. But check for races..
  *
+ *    The caller is expected to deal with the situation when we return
+ *    due to pending signals. And even if not, the peeked skb might have
+ *    been already dequeued due to concurrent operation.
+ *    Currently irda_recvmsg_stream() is the only caller and is ok.
+ * Return 0 if condition packet has arrived, -ERESTARTSYS if signal_pending()
+ * Only used once in irda_recvmsg_stream() -> inline
  */
-static void irda_data_wait(struct sock *sk)
+static inline int irda_data_wait(struct sock *sk)
 {
+	int ret = 0;
 	if (!skb_peek(&sk->receive_queue)) {
 		set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
-		interruptible_sleep_on(sk->sleep);
+		__wait_event_interruptible(*(sk->sleep),
+			(skb_peek(&sk->receive_queue)!=NULL), ret);
 		clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
 	}
+	return(ret);
 }
 
 /*
@@ -1444,8 +1473,8 @@
 
 			if (noblock)
 				return -EAGAIN;
-			irda_data_wait(sk);
-			if (signal_pending(current))
+			/* Wait process until data arrives */
+			if (irda_data_wait(sk))
 				return -ERESTARTSYS;
 			continue;
 		}
@@ -2281,7 +2310,12 @@
 		self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
 					 irda_getvalue_confirm);
 
-		/* Treat unexpected signals as disconnect */
+		if (self->iriap == NULL) {
+			kfree(ias_opt);
+			return -ENOMEM;
+		}
+
+		/* Treat unexpected wakeup as disconnect */
 		self->errno = -EHOSTUNREACH;
 
 		/* Query remote LM-IAS */
@@ -2289,9 +2323,17 @@
 					      self->saddr, daddr,
 					      ias_opt->irda_class_name,
 					      ias_opt->irda_attrib_name);
-		/* Wait for answer (if not already failed) */
-		if(self->iriap != NULL)
-			interruptible_sleep_on(&self->query_wait);
+
+		/* Wait for answer, if not yet finished (or failed) */
+		if (wait_event_interruptible(self->query_wait,
+					     (self->iriap == NULL))) {
+			/* pending request uses copy of ias_opt-content
+			 * we can free it regardless! */
+			kfree(ias_opt);
+			/* Treat signals as disconnect */
+			return -EHOSTUNREACH;
+		}
+
 		/* Check what happened */
 		if (self->errno)
 		{
@@ -2348,12 +2390,14 @@
 		irlmp_update_client(self->ckey, self->mask,
 				    irda_selective_discovery_indication,
 				    NULL, (void *) self);
-		
+
 		/* Do some discovery (and also return cached results) */
 		irlmp_discovery_request(self->nslots);
-		
+
 		/* Wait until a node is discovered */
 		if (!self->cachediscovery) {
+			int ret = 0;
+
 			IRDA_DEBUG(1, __FUNCTION__ 
 				   "(), nothing discovered yet, going to sleep...\n");
 
@@ -2362,9 +2406,12 @@
 			self->watchdog.data = (unsigned long) self;
 			self->watchdog.expires = jiffies + (val * HZ/1000);
 			add_timer(&(self->watchdog));
+			self->errno = 0;
 
 			/* Wait for IR-LMP to call us back */
-			interruptible_sleep_on(&self->query_wait);
+			__wait_event_interruptible(self->query_wait,
+			   (self->cachediscovery!=NULL || self->errno==-ETIME),
+						   ret);
 
 			/* If watchdog is still activated, kill it! */
 			if(timer_pending(&(self->watchdog)))
@@ -2372,6 +2419,9 @@
 
 			IRDA_DEBUG(1, __FUNCTION__ 
 				   "(), ...waking up !\n");
+
+			if (ret != 0)
+				return ret;
 		}
 		else
 			IRDA_DEBUG(1, __FUNCTION__ 
diff -Nru a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
--- a/net/irda/ircomm/ircomm_tty.c	Thu May  2 17:22:16 2002
+++ b/net/irda/ircomm/ircomm_tty.c	Thu May  2 17:22:16 2002
@@ -453,8 +453,21 @@
 	 */
 	if (tty_hung_up_p(filp) ||
 	    (self->flags & ASYNC_CLOSING)) {
-		if (self->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&self->close_wait);
+
+		/* Hm, why are we blocking on ASYNC_CLOSING if we
+		 * do return -EAGAIN/-ERESTARTSYS below anyway?
+		 * IMHO it's either not needed in the first place
+		 * or for some reason we need to make sure the async
+		 * closing has been finished - if so, wouldn't we
+		 * probably better sleep uninterruptible?
+		 */
+
+		if (wait_event_interruptible(self->close_wait, !(self->flags&ASYNC_CLOSING))) {
+			WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
+				__FUNCTION__);
+			return -ERESTARTSYS;
+		}
+
 		/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
 #ifdef SERIAL_DO_RESTART
 		return ((self->flags & ASYNC_HUP_NOTIFY) ?
diff -Nru a/net/irda/irda_device.c b/net/irda/irda_device.c
--- a/net/irda/irda_device.c	Thu May  2 17:22:17 2002
+++ b/net/irda/irda_device.c	Thu May  2 17:22:17 2002
@@ -368,6 +368,12 @@
  *    time to complete. We do it this hairy way since we may have been
  *    called from interrupt context, so it's not possible to use
  *    schedule_timeout() 
+ * Two important notes :
+ *	o Make sure you irda_task_delete(task); in case you delete the
+ *	  calling instance.
+ *	o No real need to lock when calling this function, but you may
+ *	  want to lock within the task handler.
+ * Jean II
  */
 struct irda_task *irda_task_execute(void *instance, 
 				    IRDA_TASK_CALLBACK function, 
@@ -466,6 +472,9 @@
  * Function irda_device_init_dongle (self, type, qos)
  *
  *    Initialize attached dongle.
+ *
+ * Important : request_module require us to call this function with
+ * a process context and irq enabled. - Jean II
  */
 dongle_t *irda_device_dongle_init(struct net_device *dev, int type)
 {
@@ -477,6 +486,7 @@
 #ifdef CONFIG_KMOD
 	{
 	char modname[32];
+	ASSERT(!in_interrupt(), return NULL;);
 	/* Try to load the module needed */
 	sprintf(modname, "irda-dongle-%d", type);
 	request_module(modname);
diff -Nru a/net/irda/irlap_event.c b/net/irda/irlap_event.c
--- a/net/irda/irlap_event.c	Thu May  2 17:22:17 2002
+++ b/net/irda/irlap_event.c	Thu May  2 17:22:17 2002
@@ -253,19 +253,45 @@
 	case LAP_XMIT_P: /* FALLTHROUGH */
 	case LAP_XMIT_S:
 		/* 
+		 * We just received the pf bit and are at the beginning
+		 * of a new LAP transmit window.
 		 * Check if there are any queued data frames, and do not
 		 * try to disconnect link if we send any data frames, since
 		 * that will change the state away form XMIT
 		 */
+		IRDA_DEBUG(2, __FUNCTION__ "() : queue len = %d\n",
+			   skb_queue_len(&self->txq));
+
 		if (skb_queue_len(&self->txq)) {
 			/* Prevent race conditions with irlap_data_request() */
 			self->local_busy = TRUE;
 
+			/* Theory of operation.
+			 * We send frames up to when we fill the window or
+			 * reach line capacity. Those frames will queue up
+			 * in the device queue, and the driver will slowly
+			 * send them.
+			 * After each frame that we send, we poll the higher
+			 * layer for more data. It's the right time to do
+			 * that because the link layer need to perform the mtt
+			 * and then send the first frame, so we can afford
+			 * to send a bit of time in kernel space.
+			 * The explicit flow indication allow to minimise
+			 * buffers (== lower latency), to avoid higher layer
+			 * polling via timers (== less context switches) and
+			 * to implement a crude scheduler - Jean II */
+
 			/* Try to send away all queued data frames */
 			while ((skb = skb_dequeue(&self->txq)) != NULL) {
+				/* Send one frame */
 				ret = (*state[self->state])(self, SEND_I_CMD,
 							    skb, NULL);
 				kfree_skb(skb);
+
+				/* Poll the higher layers for one more frame */
+				irlmp_flow_indication(self->notify.instance,
+						      FLOW_START);
+
 				if (ret == -EPROTO)
 					break; /* Try again later! */
 			}
diff -Nru a/net/irda/irlmp.c b/net/irda/irlmp.c
--- a/net/irda/irlmp.c	Thu May  2 17:22:17 2002
+++ b/net/irda/irlmp.c	Thu May  2 17:22:17 2002
@@ -236,6 +236,16 @@
 	lap = self->lap;
 	if (lap) {
 		ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
+		/* We might close a LSAP before it has completed the
+		 * connection setup. In those case, higher layers won't
+		 * send a proper disconnect request. Harmless, except
+		 * that we will forget to close LAP... - Jean II */
+		if(self->lsap_state != LSAP_DISCONNECTED) {
+			self->lsap_state = LSAP_DISCONNECTED;
+			irlmp_do_lap_event(self->lap,
+					   LM_LAP_DISCONNECT_REQUEST, NULL);
+		}
+		/* Now, remove from the link */
 		lsap = hashbin_remove(lap->lsaps, (int) self, NULL);
 	}
 	self->lap = NULL;
@@ -1209,6 +1219,72 @@
 						       link, lock);
 		else
 			IRDA_DEBUG(2, __FUNCTION__ "(), no handler\n");
+	}
+}
+
+/*
+ * Receive flow control indication from LAP.
+ * LAP want us to send it one more frame. We implement a simple round
+ * robin scheduler between the active sockets so that we get a bit of
+ * fairness. Note that the round robin is far from perfect, but it's
+ * better than nothing.
+ * We then poll the selected socket so that we can do synchronous
+ * refilling of IrLAP (which allow to minimise the number of buffers).
+ * Jean II
+ */
+void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow)
+{
+	struct lsap_cb *next;
+	struct lsap_cb *curr;
+	int	lsap_todo;
+
+	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	ASSERT(flow == FLOW_START, return;);
+
+	/* Get the number of lsap. That's the only safe way to know
+	 * that we have looped around... - Jean II */
+	lsap_todo = HASHBIN_GET_SIZE(self->lsaps);
+	IRDA_DEBUG(4, __FUNCTION__ "() : %d lsaps to scan\n", lsap_todo);
+
+	/* Poll lsap in order until the queue is full or until we
+	 * tried them all.
+	 * Most often, the current LSAP will have something to send,
+	 * so we will go through this loop only once. - Jean II */
+	while((lsap_todo--) &&
+	      (IRLAP_GET_TX_QUEUE_LEN(self->irlap) < LAP_HIGH_THRESHOLD)) {
+		/* Try to find the next lsap we should poll. */
+		next = self->flow_next;
+		if(next != NULL) {
+			/* Note that if there is only one LSAP on the LAP
+			 * (most common case), self->flow_next is always NULL,
+			 * so we always avoid this loop. - Jean II */
+			IRDA_DEBUG(4, __FUNCTION__ "() : searching my LSAP\n");
+
+			/* We look again in hashbins, because the lsap
+			 * might have gone away... - Jean II */
+			curr = (struct lsap_cb *) hashbin_get_first(self->lsaps);
+			while((curr != NULL ) && (curr != next))
+				curr = (struct lsap_cb *) hashbin_get_next(self->lsaps);
+		} else
+			curr = NULL;
+
+		/* If we have no lsap, restart from first one */
+		if(curr == NULL)
+			curr = (struct lsap_cb *) hashbin_get_first(self->lsaps);
+		/* Uh-oh... Paranoia */
+		if(curr == NULL)
+			break;
+
+		/* Next time, we will get the next one (or the first one) */
+		self->flow_next = (struct lsap_cb *) hashbin_get_next(self->lsaps);
+		IRDA_DEBUG(4, __FUNCTION__ "() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap));
+
+		/* Inform lsap user that it can send one more packet. */
+		if (curr->notify.flow_indication != NULL)
+			curr->notify.flow_indication(curr->notify.instance, 
+						     curr, flow);
+		else
+			IRDA_DEBUG(1, __FUNCTION__ "(), no handler\n");
 	}
 }
 
diff -Nru a/net/irda/irnet/irnet.h b/net/irda/irnet/irnet.h
--- a/net/irda/irnet/irnet.h	Thu May  2 17:22:17 2002
+++ b/net/irda/irnet/irnet.h	Thu May  2 17:22:17 2002
@@ -217,6 +217,11 @@
  *	  Better fix in irnet_disconnect_indication() :
  *	  - if connected, kill pppd via hangup.
  *	  - if not connected, reenable ppp Tx, which trigger IrNET retry.
+ *
+ * v12 - 10.4.02 - Jean II
+ *	o Fix race condition in irnet_connect_indication().
+ *	  If the socket was already trying to connect, drop old connection
+ *	  and use new one only if acting as primary. See comments.
  */
 
 /***************************** INCLUDES *****************************/
diff -Nru a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c
--- a/net/irda/irnet/irnet_irda.c	Thu May  2 17:22:15 2002
+++ b/net/irda/irnet/irnet_irda.c	Thu May  2 17:22:15 2002
@@ -1340,46 +1340,80 @@
       return;
     }
 
-  /* Socket connecting ?
-   * Clear up flag : prevent irnet_disconnect_indication() to mess up tsap */
-  if(test_and_clear_bit(0, &new->ttp_connect))
-    {
-      /* The socket is trying to connect to the other end and may have sent
-       * a IrTTP connection request and is waiting for a connection response
-       * (that may never come).
-       * Now, the pain is that the socket may have opened a tsap and is
-       * waiting on it, while the other end is trying to connect to it on
-       * another tsap.
-       */
-      DERROR(IRDA_CB_ERROR, "Socket already connecting. Ouch !\n");
+  /* The following code is a bit tricky, so need comments ;-)
+   */
+  /* If ttp_connect is set, the socket is trying to connect to the other
+   * end and may have sent a IrTTP connection request and is waiting for
+   * a connection response (that may never come).
+   * Now, the pain is that the socket may have opened a tsap and is
+   * waiting on it, while the other end is trying to connect to it on
+   * another tsap.
+   * Because IrNET can be peer to peer, we need to workaround this.
+   * Furthermore, the way the irnetd script is implemented, the
+   * target will create a second IrNET connection back to the
+   * originator and expect the originator to bind this new connection
+   * to the original PPPD instance.
+   * And of course, if we don't use irnetd, we can have a race when
+   * both side try to connect simultaneously, which could leave both
+   * connections half closed (yuck).
+   * Conclusions :
+   *	1) The "originator" must accept the new connection and get rid
+   *	   of the old one so that irnetd works
+   *	2) One side must deny the new connection to avoid races,
+   *	   but both side must agree on which side it is...
+   * Most often, the originator is primary at the LAP layer.
+   * Jean II
+   */
+  /* Now, let's look at the way I wrote the test...
+   * We need to clear up the ttp_connect flag atomically to prevent
+   * irnet_disconnect_indication() to mess up the tsap we are going to close.
+   * We want to clear the ttp_connect flag only if we close the tsap,
+   * otherwise we will never close it, so we need to check for primary
+   * *before* doing the test on the flag.
+   * And of course, ALLOW_SIMULT_CONNECT can disable this entirely...
+   * Jean II
+   */
+
+  /* Socket already connecting ? On primary ? */
+  if(0
 #ifdef ALLOW_SIMULT_CONNECT
-      /* Cleanup the TSAP if necessary - IrIAP will be cleaned up later */
+     || ((irttp_is_primary(server->tsap) == 1)	/* primary */
+	 && (test_and_clear_bit(0, &new->ttp_connect)))
+#endif /* ALLOW_SIMULT_CONNECT */
+     )
+    {
+      DERROR(IRDA_CB_ERROR, "Socket already connecting, but going to reuse it !\n");
+
+      /* Cleanup the old TSAP if necessary - IrIAP will be cleaned up later */
       if(new->tsap != NULL)
 	{
-	  /* Close the connection the new socket was attempting.
-	   * This seems to be safe... */
+	  /* Close the old connection the new socket was attempting,
+	   * so that we can hook it up to the new connection.
+	   * It's now safe to do it... */
 	  irttp_close_tsap(new->tsap);
 	  new->tsap = NULL;
 	}
-      /* Note : no return, fall through... */
-#else /* ALLOW_SIMULT_CONNECT */
-      irnet_disconnect_server(server, skb);
-      return;
-#endif /* ALLOW_SIMULT_CONNECT */
     }
   else
-    /* If socket is not connecting or connected, tsap should be NULL */
-    if(new->tsap != NULL)
-      {
-	/* If we are here, we are also in irnet_disconnect_indication(),
-	 * and it's a nice race condition... On the other hand, we can't be
-	 * in irda_irnet_destroy() otherwise we would not have found the
-	 * socket in the hashbin. */
-	/* Better get out of here, otherwise we will mess up tsaps ! */
-	DERROR(IRDA_CB_ERROR, "Race condition detected, abort connect...\n");
-	irnet_disconnect_server(server, skb);
-	return;
-      }
+    {
+      /* Three options :
+       * 1) socket was not connecting or connected : ttp_connect should be 0.
+       * 2) we don't want to connect the socket because we are secondary or
+       * ALLOW_SIMULT_CONNECT is undefined. ttp_connect should be 1.
+       * 3) we are half way in irnet_disconnect_indication(), and it's a
+       * nice race condition... Fortunately, we can detect that by checking
+       * if tsap is still alive. On the other hand, we can't be in
+       * irda_irnet_destroy() otherwise we would not have found this
+       * socket in the hashbin.
+       * Jean II */
+      if((test_bit(0, &new->ttp_connect)) || (new->tsap != NULL))
+	{
+	  /* Don't mess this socket, somebody else in in charge... */
+	  DERROR(IRDA_CB_ERROR, "Race condition detected, socket in use, abort connect...\n");
+	  irnet_disconnect_server(server, skb);
+	  return;
+	}
+    }
 
   /* So : at this point, we have a socket, and it is idle. Good ! */
   irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size);
diff -Nru a/net/irda/irttp.c b/net/irda/irttp.c
--- a/net/irda/irttp.c	Thu May  2 17:22:15 2002
+++ b/net/irda/irttp.c	Thu May  2 17:22:15 2002
@@ -59,8 +59,8 @@
 
 static void irttp_flush_queues(struct tsap_cb *self);
 static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb);
-static void irttp_start_todo_timer(struct tsap_cb *self, int timeout);
 static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
+static void irttp_todo_expired(unsigned long data);
 static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
 				    int get);
 
@@ -72,6 +72,8 @@
 static pi_major_info_t pi_major_call_table[] = {{ pi_minor_call_table, 2 }};
 static pi_param_info_t param_info = { pi_major_call_table, 1, 0x0f, 4 };
 
+/************************ GLOBAL PROCEDURES ************************/
+
 /*
  * Function irttp_init (void)
  *
@@ -126,6 +128,239 @@
 }
 #endif
 
+/*************************** SUBROUTINES ***************************/
+
+/*
+ * Function irttp_start_todo_timer (self, timeout)
+ *
+ *    Start todo timer. 
+ *
+ * Made it more effient and unsensitive to race conditions - Jean II
+ */
+static inline void irttp_start_todo_timer(struct tsap_cb *self, int timeout)
+{
+	/* Set new value for timer */
+	mod_timer(&self->todo_timer, jiffies + timeout);
+}
+
+/*
+ * Function irttp_todo_expired (data)
+ *
+ *    Todo timer has expired!
+ *
+ * One of the restriction of the timer is that it is run only on the timer
+ * interrupt which run every 10ms. This mean that even if you set the timer
+ * with a delay of 0, it may take up to 10ms before it's run.
+ * So, to minimise latency and keep cache fresh, we try to avoid using
+ * it as much as possible.
+ * Note : we can't use tasklets, because they can't be asynchronously
+ * killed (need user context), and we can't guarantee that here...
+ * Jean II
+ */
+static void irttp_todo_expired(unsigned long data)
+{
+	struct tsap_cb *self = (struct tsap_cb *) data;
+
+	/* Check that we still exist */
+	if (!self || self->magic != TTP_TSAP_MAGIC)
+		return;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "(instance=%p)\n", self);
+
+	/* Try to make some progress, especially on Tx side - Jean II */
+	irttp_run_rx_queue(self);
+	irttp_run_tx_queue(self);
+
+	/* Check if time for disconnect */
+	if (test_bit(0, &self->disconnect_pend)) {
+		/* Check if it's possible to disconnect yet */
+		if (skb_queue_empty(&self->tx_queue)) {
+			/* Make sure disconnect is not pending anymore */
+			clear_bit(0, &self->disconnect_pend);	/* FALSE */
+
+			/* Note : self->disconnect_skb may be NULL */
+			irttp_disconnect_request(self, self->disconnect_skb,
+						 P_NORMAL);
+			self->disconnect_skb = NULL;
+		} else {
+			/* Try again later */
+			irttp_start_todo_timer(self, HZ/10);
+			
+			/* No reason to try and close now */
+			return;
+		}
+	}
+	
+	/* Check if it's closing time */
+	if (self->close_pend)
+		/* Finish cleanup */
+		irttp_close_tsap(self);
+}
+
+/*
+ * Function irttp_flush_queues (self)
+ *
+ *     Flushes (removes all frames) in transitt-buffer (tx_list)
+ */
+void irttp_flush_queues(struct tsap_cb *self)
+{
+	struct sk_buff* skb;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	
+	/* Deallocate frames waiting to be sent */
+	while ((skb = skb_dequeue(&self->tx_queue)) != NULL)
+		dev_kfree_skb(skb);
+	
+	/* Deallocate received frames */
+	while ((skb = skb_dequeue(&self->rx_queue)) != NULL)
+		dev_kfree_skb(skb);
+	
+	/* Deallocate received fragments */
+	while ((skb = skb_dequeue(&self->rx_fragments)) != NULL)
+		dev_kfree_skb(skb);
+}
+
+/*
+ * Function irttp_reassemble (self)
+ *
+ *    Makes a new (continuous) skb of all the fragments in the fragment
+ *    queue
+ *
+ */
+static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
+{
+	struct sk_buff *skb, *frag;
+	int n = 0;  /* Fragment index */
+	
+      	ASSERT(self != NULL, return NULL;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), self->rx_sdu_size=%d\n", 
+		   self->rx_sdu_size);
+
+	skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
+	if (!skb)
+		return NULL;
+
+	/* 
+	 * Need to reserve space for TTP header in case this skb needs to 
+	 * be requeued in case delivery failes
+	 */
+	skb_reserve(skb, TTP_HEADER);
+	skb_put(skb, self->rx_sdu_size);
+
+	/*
+	 *  Copy all fragments to a new buffer
+	 */
+	while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) {
+		memcpy(skb->data+n, frag->data, frag->len);
+		n += frag->len;
+		
+		dev_kfree_skb(frag);
+	}
+	IRDA_DEBUG(2, __FUNCTION__ "(), frame len=%d\n", n);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
+	ASSERT(n <= self->rx_sdu_size, return NULL;);
+
+	/* Set the new length */
+	skb_trim(skb, n);
+
+	self->rx_sdu_size = 0;
+
+	return skb;
+}
+
+/*
+ * Function irttp_fragment_skb (skb)
+ *
+ *    Fragments a frame and queues all the fragments for transmission
+ *
+ */
+static inline void irttp_fragment_skb(struct tsap_cb *self,
+				      struct sk_buff *skb)
+{
+	struct sk_buff *frag;
+	__u8 *frame;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
+
+	/*
+	 *  Split frame into a number of segments
+	 */
+	while (skb->len > self->max_seg_size) {
+		IRDA_DEBUG(2, __FUNCTION__  "(), fragmenting ...\n");
+
+		/* Make new segment */
+		frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
+		if (!frag)
+			return;
+
+		skb_reserve(frag, self->max_header_size);
+
+		/* Copy data from the original skb into this fragment. */
+		memcpy(skb_put(frag, self->max_seg_size), skb->data, 
+		       self->max_seg_size);
+
+		/* Insert TTP header, with the more bit set */
+		frame = skb_push(frag, TTP_HEADER);
+		frame[0] = TTP_MORE;
+		
+		/* Hide the copied data from the original skb */
+		skb_pull(skb, self->max_seg_size);
+
+		/* Queue fragment */
+		skb_queue_tail(&self->tx_queue, frag);
+	}
+	/* Queue what is left of the original skb */
+	IRDA_DEBUG(2, __FUNCTION__  "(), queuing last segment\n");
+	
+	frame = skb_push(skb, TTP_HEADER);
+	frame[0] = 0x00; /* Clear more bit */
+
+	/* Queue fragment */
+	skb_queue_tail(&self->tx_queue, skb);
+}
+
+/*
+ * Function irttp_param_max_sdu_size (self, param)
+ *
+ *    Handle the MaxSduSize parameter in the connect frames, this function
+ *    will be called both when this parameter needs to be inserted into, and
+ *    extracted from the connect frames
+ */
+static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
+				    int get)
+{
+	struct tsap_cb *self;
+
+	self = (struct tsap_cb *) instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+
+	if (get)
+		param->pv.i = self->tx_max_sdu_size;
+	else
+		self->tx_max_sdu_size = param->pv.i;
+
+	IRDA_DEBUG(1, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
+	
+	return 0;
+}
+
+/*************************** CLIENT CALLS ***************************/
+/************************** LMP CALLBACKS **************************/
+/* Everything is happily mixed up. Waiting for next clean up - Jean II */
+
 /*
  * Function irttp_open_tsap (stsap, notify)
  *
@@ -157,7 +392,10 @@
 	memset(self, 0, sizeof(struct tsap_cb));
 	spin_lock_init(&self->lock);
 
+	/* Initialise todo timer */
 	init_timer(&self->todo_timer);
+	self->todo_timer.data     = (unsigned long) self;
+	self->todo_timer.function = &irttp_todo_expired;
 
 	/* Initialize callbacks for IrLMP to use */
 	irda_notify_init(&ttp_notify);
@@ -166,6 +404,7 @@
 	ttp_notify.disconnect_indication = irttp_disconnect_indication;
 	ttp_notify.data_indication = irttp_data_indication;
 	ttp_notify.udata_indication = irttp_udata_indication;
+	ttp_notify.flow_indication = irttp_flow_indication;
 	if(notify->status_indication != NULL)
 		ttp_notify.status_indication = irttp_status_indication;
 	ttp_notify.instance = self;
@@ -199,8 +438,8 @@
 
 	hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (int) self, NULL);
 
-	if (credit > TTP_MAX_QUEUE)
-		self->initial_credit = TTP_MAX_QUEUE;
+	if (credit > TTP_RX_MAX_CREDIT)
+		self->initial_credit = TTP_RX_MAX_CREDIT;
 	else
 		self->initial_credit = credit;
 
@@ -224,7 +463,7 @@
 
 	del_timer(&self->todo_timer);
 
-	/* This one won't be cleaned up if we are diconnect_pend + close_pend
+	/* This one won't be cleaned up if we are disconnect_pend + close_pend
 	 * and we receive a disconnect_indication */
 	if (self->disconnect_skb)
 		dev_kfree_skb(self->disconnect_skb);
@@ -262,7 +501,7 @@
 			irttp_disconnect_request(self, NULL, P_NORMAL);
 		}
 		self->close_pend = TRUE;
-		irttp_start_todo_timer(self, 1*HZ);
+		irttp_start_todo_timer(self, HZ/10);
 
 		return 0; /* Will be back! */
 	}
@@ -327,6 +566,9 @@
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 	ASSERT(skb != NULL, return -1;);
 
+	IRDA_DEBUG(2, __FUNCTION__ " : queue len = %d\n",
+		   skb_queue_len(&self->tx_queue));
+
 	/* Check that nothing bad happens */
 	if ((skb->len == 0) || (!self->connected)) {
 		WARNING(__FUNCTION__ "(), No data, or not connected\n");
@@ -358,12 +600,14 @@
 	/* 
 	 *  Check if transmit queue is full
 	 */
-	if (skb_queue_len(&self->tx_queue) >= TTP_MAX_QUEUE) {
+	if (skb_queue_len(&self->tx_queue) >= TTP_TX_MAX_QUEUE) {
 		/*
 		 *  Give it a chance to empty itself
 		 */
 		irttp_run_tx_queue(self);
-		
+
+		/* Drop packet. This error code should trigger the caller
+		 * to requeue the packet in the client code - Jean II */
 		return -ENOBUFS;
 	}
        
@@ -387,20 +631,25 @@
 
 	/* Check if we can accept more data from client */
 	if ((!self->tx_sdu_busy) && 
-	    (skb_queue_len(&self->tx_queue) > TTP_HIGH_THRESHOLD)) {
-		
-		/* Tx queue filling up, so stop client */
-		self->tx_sdu_busy = TRUE;
-		
-	 	if (self->notify.flow_indication) {
+	    (skb_queue_len(&self->tx_queue) > TTP_TX_HIGH_THRESHOLD)) {
+		/* Tx queue filling up, so stop client. */
+		if (self->notify.flow_indication) {
  			self->notify.flow_indication(self->notify.instance, 
 						     self, FLOW_STOP);
 		}
- 	}
+		/* self->tx_sdu_busy is the state of the client.
+		 * Update state after notifying client to avoid
+		 * race condition with irttp_flow_indication().
+		 * If the queue empty itself after our test but before
+		 * we set the flag, we will fix ourselves below in
+		 * irttp_run_tx_queue().
+		 * Jean II */
+		self->tx_sdu_busy = TRUE;
+	}
 	
 	/* Try to make some progress */
 	irttp_run_tx_queue(self);
-	
+
 	return 0;
 }
 
@@ -416,28 +665,20 @@
 	unsigned long flags;
 	int n;
 
+	IRDA_DEBUG(2, __FUNCTION__ "() : send_credit = %d, queue_len = %d\n",
+		   self->send_credit, skb_queue_len(&self->tx_queue));
+
 	/* Get exclusive access to the tx queue, otherwise don't touch it */
 	if (irda_lock(&self->tx_queue_lock) == FALSE)
 		return;
 
-	/* Try to send out frames as long as we have credits */
+	/* Try to send out frames as long as we have credits
+	 * and as long as LAP is not full. If LAP is full, it will
+	 * poll us through irttp_flow_indication() - Jean II */
 	while ((self->send_credit > 0) &&
+	       (!irlmp_lap_tx_queue_full(self->lsap)) &&
 	       (skb = skb_dequeue(&self->tx_queue)))
 	{
-		/* 
-		 * Make sure we don't flood IrLAP with frames just because
-		 * the remote device has given us a lot of credits
-		 */
-		if (irlmp_get_lap_tx_queue_len(self->lsap) > LAP_MAX_QUEUE) {
-			/* Re-queue packet */
-			skb_queue_head(&self->tx_queue, skb);
-
-			/* Try later. Would be better if IrLAP could notify us */
-			irttp_start_todo_timer(self, MSECS_TO_JIFFIES(10));
-			
-			break;
-		}
-
 		/*
 		 *  Since we can transmit and receive frames concurrently, 
 		 *  the code below is a critical region and we must assure that
@@ -484,32 +725,35 @@
 		 * Jean II */
 		if (skb->sk != NULL) {
 			/* IrSOCK application, IrOBEX, ... */
-			IRDA_DEBUG(4, __FUNCTION__ "() : Detaching SKB from socket.\n");
-
-			/* That's the right way to do it - Jean II */
 			skb_orphan(skb);
-		} else {
-			/* IrCOMM over IrTTP, IrLAN, ... */
-			IRDA_DEBUG(4, __FUNCTION__ "() : Got SKB not attached to a socket.\n");
 		}
+			/* IrCOMM over IrTTP, IrLAN, ... */
 
 		/* Pass the skb to IrLMP - done */
 		irlmp_data_request(self->lsap, skb);
 		self->stats.tx_packets++;
+	}
 
-		/* Check if we can accept more frames from client */
-		if ((self->tx_sdu_busy) && 
-		    (skb_queue_len(&self->tx_queue) < TTP_LOW_THRESHOLD)) 
-		{
-			self->tx_sdu_busy = FALSE;
-			
-			if (self->notify.flow_indication)
-				self->notify.flow_indication(
-					self->notify.instance, self,
-					FLOW_START);
-		}
+	/* Check if we can accept more frames from client.
+	 * We don't want to wait until the todo timer to do that, and we
+	 * can't use tasklets (grr...), so we are obliged to give control
+	 * to client. That's ok, this test will be true not too often
+	 * (max once per LAP window) and we are called from places
+	 * where we can spend a bit of time doing stuff. - Jean II */
+	if ((self->tx_sdu_busy) && 
+	    (skb_queue_len(&self->tx_queue) < TTP_TX_LOW_THRESHOLD) &&
+	    (!self->close_pend))
+	{
+		if (self->notify.flow_indication)
+			self->notify.flow_indication(self->notify.instance,
+						     self, FLOW_START);
+
+		/* self->tx_sdu_busy is the state of the client.
+		 * We don't really have a race here, but it's always safer
+		 * to update our state after the client - Jean II */
+		self->tx_sdu_busy = FALSE;
 	}
-	
+
 	/* Reset lock */
 	self->tx_queue_lock = 0;
 }
@@ -520,7 +764,7 @@
  *    Send a dataless flowdata TTP-PDU and give available credit to peer
  *    TSAP
  */
-void irttp_give_credit(struct tsap_cb *self) 
+static inline void irttp_give_credit(struct tsap_cb *self) 
 {
 	struct sk_buff *tx_skb = NULL;
 	unsigned long flags;
@@ -531,7 +775,7 @@
 
 	IRDA_DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
 		   self->send_credit, self->avail_credit, self->remote_credit);
-	
+
 	/* Give credit to peer */
 	tx_skb = dev_alloc_skb(64);
 	if (!tx_skb)
@@ -606,6 +850,7 @@
 				 struct sk_buff *skb)
 {
 	struct tsap_cb *self;
+	unsigned long flags;
 	int n;
 
 	self = (struct tsap_cb *) instance;
@@ -614,47 +859,66 @@
 
 	self->stats.rx_packets++;
 
+	/*  Deal with inbound credit
+	 *  Since we can transmit and receive frames concurrently, 
+	 *  the code below is a critical region and we must assure that
+	 *  nobody messes with the credits while we update them.
+	 */
+	spin_lock_irqsave(&self->lock, flags);
+	self->send_credit += n;
+	if (skb->len > 1)
+		self->remote_credit--;
+	spin_unlock_irqrestore(&self->lock, flags);
+
 	/* 
 	 *  Data or dataless packet? Dataless frames contains only the 
 	 *  TTP_HEADER. 
 	 */
 	if (skb->len > 1) {
-		/* Deal with inbound credit */
-		self->send_credit += n;
-		self->remote_credit--;
-		
 		/* 
 		 *  We don't remove the TTP header, since we must preserve the
 		 *  more bit, so the defragment routing knows what to do
 		 */
 		skb_queue_tail(&self->rx_queue, skb);
 	} else {
-		self->send_credit += n;	/* Dataless flowdata TTP-PDU */
+		/* Dataless flowdata TTP-PDU */
 		dev_kfree_skb(skb);
 	}
 
+
+	/* Push data to the higher layer.
+	 * We do it synchronously because running the todo timer for each
+	 * receive packet would be too much overhead and latency.
+	 * By passing control to the higher layer, we run the risk that
+	 * it may take time or grab a lock. Most often, the higher layer
+	 * will only put packet in a queue.
+	 * Anyway, packets are only dripping through the IrDA, so we can
+	 * have time before the next packet.
+	 * Further, we are run from NET_BH, so the worse that can happen is
+	 * us missing the optimal time to send back the PF bit in LAP.
+	 * Jean II */
 	irttp_run_rx_queue(self);
 
-	/* 
-	 *  Give avay some credits to peer? 
-	 */
-	if ((skb_queue_empty(&self->tx_queue)) && 
-	    (self->remote_credit < TTP_LOW_THRESHOLD) && 
-	    (self->avail_credit > 0)) 
-	{
-		/* Schedule to start immediately after this thread */
-		irttp_start_todo_timer(self, 0);
-		/*irttp_give_credit(self);*/
-	}
-	
+	/* We now give credits to peer in irttp_run_rx_queue().
+	 * We need to send credit *NOW*, otherwise we are going
+	 * to miss the next Tx window. The todo timer may take
+	 * a while before it's run... - Jean II */
+
 	/* 
 	 * If the peer device has given us some credits and we didn't have
-         * anyone from before, the we need to shedule the tx queue?  
+         * anyone from before, then we need to shedule the tx queue.
+	 * We need to do that because our Tx have stopped (so we may not
+	 * get any LAP flow indication) and the user may be stopped as
+	 * well. - Jean II
 	 */
 	if (self->send_credit == n) {
-		/*irttp_run_tx_queue(self);*/
-		irttp_start_todo_timer(self, 0);
+		/* Restart pushing stuff to LAP */
+		irttp_run_tx_queue(self);
+		/* Note : we don't want to schedule the todo timer
+		 * because it has horrible latency. No tasklets
+		 * because the tasklet API is broken. - Jean II */
 	}
+
 	return 0;
 }
 
@@ -687,6 +951,50 @@
 }
 
 /*
+ * Function irttp_flow_indication (self, reason)
+ *
+ *    Flow_indication : IrLAP tells us to send more data.
+ *
+ */
+void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
+{
+	struct tsap_cb *self;
+
+	self = (struct tsap_cb *) instance;
+	
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	
+	IRDA_DEBUG(4, __FUNCTION__ "(instance=%p)\n", self);
+
+	/* We are "polled" directly from LAP, and the LAP want to fill
+	 * its Tx window. We want to do our best to send it data, so that
+	 * we maximise the window. On the other hand, we want to limit the
+	 * amount of work here so that LAP doesn't hang forever waiting
+	 * for packets. - Jean II */
+
+	/* Try to send some packets. Currently, LAP calls us every time
+	 * there is one free slot, so we will send only one packet.
+	 * This allow the scheduler to do its round robin - Jean II */
+	irttp_run_tx_queue(self);
+
+	/* Note regarding the interraction with higher layer.
+	 * irttp_run_tx_queue() may call the client when its queue
+	 * start to empty, via notify.flow_indication(). Initially.
+	 * I wanted this to happen in a tasklet, to avoid client
+	 * grabbing the CPU, but we can't use tasklets safely. And timer
+	 * is definitely too slow.
+	 * This will happen only once per LAP window, and usually at
+	 * the third packet (unless window is smaller). LAP is still
+	 * doing mtt and sending first packet so it's sort of OK
+	 * to do that. Jean II */
+
+	/* If we need to send disconnect. try to do it now */
+	if(self->disconnect_pend)
+		irttp_start_todo_timer(self, 0);
+}
+
+/*
  * Function irttp_flow_request (self, command)
  *
  *    This funtion could be used by the upper layers to tell IrTTP to stop
@@ -709,7 +1017,10 @@
 		IRDA_DEBUG(1, __FUNCTION__ "(), flow start\n");
 		self->rx_sdu_busy = FALSE;
 		
+		/* Client say he can accept more data, try to free our
+		 * queues ASAP - Jean II */
 		irttp_run_rx_queue(self);
+
 		break;
 	default:
 		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown flow command!\n");
@@ -1147,10 +1458,15 @@
 
 			irttp_run_tx_queue(self);
 
-			irttp_start_todo_timer(self, MSECS_TO_JIFFIES(1000));
+			irttp_start_todo_timer(self, HZ/10);
 			return -1;
 		}
 	}
+	/* Note : we don't need to check if self->rx_queue is full and the
+	 * state of self->rx_sdu_busy because the disconnect response will
+	 * be sent at the LMP level (so even if the peer has its Tx queue
+	 * full of data). - Jean II */
+
 	IRDA_DEBUG(1, __FUNCTION__ "(), Disconnecting ...\n");
 	self->connected = FALSE;
 
@@ -1281,8 +1597,7 @@
 	 *  Reassemble all frames in receive queue and deliver them
 	 */
 	while (!self->rx_sdu_busy && (skb = skb_dequeue(&self->rx_queue))) {
-		self->avail_credit++;
-
+		/* This bit will tell us if it's the last fragment or not */
 		more = skb->data[0] & 0x80;
 
 		/* Remove TTP header */
@@ -1293,7 +1608,7 @@
 
 		/*  
 		 * If SAR is disabled, or user has requested no reassembly
-		 * of received fragements then we just deliver them
+		 * of received fragments then we just deliver them
 		 * immediately. This can be requested by clients that
 		 * implements byte streams without any message boundaries
 		 */
@@ -1353,236 +1668,46 @@
 		}
 		self->rx_sdu_size = 0;
 	}
-	/* Reset lock */
-	self->rx_queue_lock = 0;
-}
-
-/*
- * Function irttp_flush_queues (self)
- *
- *     Flushes (removes all frames) in transitt-buffer (tx_list)
- */
-void irttp_flush_queues(struct tsap_cb *self)
-{
-	struct sk_buff* skb;
-	
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-	
-	/* Deallocate frames waiting to be sent */
-	while ((skb = skb_dequeue(&self->tx_queue)) != NULL)
-		dev_kfree_skb(skb);
-	
-	/* Deallocate received frames */
-	while ((skb = skb_dequeue(&self->rx_queue)) != NULL)
-		dev_kfree_skb(skb);
-	
-	/* Deallocate received fragments */
-	while ((skb = skb_dequeue(&self->rx_fragments)) != NULL)
-		dev_kfree_skb(skb);
-}
-
-/*
- * Function irttp_reasseble (self)
- *
- *    Makes a new (continuous) skb of all the fragments in the fragment
- *    queue
- *
- */
-static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
-{
-	struct sk_buff *skb, *frag;
-	int n = 0;  /* Fragment index */
-	
-      	ASSERT(self != NULL, return NULL;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
-
-	IRDA_DEBUG(2, __FUNCTION__ "(), self->rx_sdu_size=%d\n", 
-		   self->rx_sdu_size);
-
-	skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
-	if (!skb)
-		return NULL;
-
-	/* 
-	 * Need to reserve space for TTP header in case this skb needs to 
-	 * be requeued in case delivery failes
-	 */
-	skb_reserve(skb, TTP_HEADER);
-	skb_put(skb, self->rx_sdu_size);
 
 	/*
-	 *  Copy all fragments to a new buffer
+	 * It's not trivial to keep track of how many credits are available
+	 * by incrementing at each packet, because delivery may fail 
+	 * (irttp_do_data_indication() may requeue the frame) and because
+	 * we need to take care of fragmentation.
+	 * We want the other side to send up to initial_credit packets.
+	 * We have some frames in our queues, and we have already allowed it
+	 * to send remote_credit.
+	 * No need to spinlock, write is atomic and self correcting...
+	 * Jean II
 	 */
-	while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) {
-		memcpy(skb->data+n, frag->data, frag->len);
-		n += frag->len;
-		
-		dev_kfree_skb(frag);
-	}
-	IRDA_DEBUG(2, __FUNCTION__ "(), frame len=%d\n", n);
-
-	IRDA_DEBUG(2, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
-	ASSERT(n <= self->rx_sdu_size, return NULL;);
-
-	/* Set the new length */
-	skb_trim(skb, n);
-
-	self->rx_sdu_size = 0;
-
-	return skb;
-}
-
-/*
- * Function irttp_fragment_skb (skb)
- *
- *    Fragments a frame and queues all the fragments for transmission
- *
- */
-static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb)
-{
-	struct sk_buff *frag;
-	__u8 *frame;
-
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
-
-	/*
-	 *  Split frame into a number of segments
-	 */
-	while (skb->len > self->max_seg_size) {
-		IRDA_DEBUG(2, __FUNCTION__  "(), fragmenting ...\n");
-
-		/* Make new segment */
-		frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
-		if (!frag)
-			return;
-
-		skb_reserve(frag, self->max_header_size);
-
-		/* Copy data from the original skb into this fragment. */
-		memcpy(skb_put(frag, self->max_seg_size), skb->data, 
-		       self->max_seg_size);
-
-		/* Insert TTP header, with the more bit set */
-		frame = skb_push(frag, TTP_HEADER);
-		frame[0] = TTP_MORE;
-		
-		/* Hide the copied data from the original skb */
-		skb_pull(skb, self->max_seg_size);
-
-		/* Queue fragment */
-		skb_queue_tail(&self->tx_queue, frag);
-	}
-	/* Queue what is left of the original skb */
-	IRDA_DEBUG(2, __FUNCTION__  "(), queuing last segment\n");
-	
-	frame = skb_push(skb, TTP_HEADER);
-	frame[0] = 0x00; /* Clear more bit */
-
-	/* Queue fragment */
-	skb_queue_tail(&self->tx_queue, skb);
-}
-
-/*
- * Function irttp_param_max_sdu_size (self, param)
- *
- *    Handle the MaxSduSize parameter in the connect frames, this function
- *    will be called both when this parameter needs to be inserted into, and
- *    extracted from the connect frames
- */
-static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
-				    int get)
-{
-	struct tsap_cb *self;
-
-	self = (struct tsap_cb *) instance;
-
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-
-	if (get)
-		param->pv.i = self->tx_max_sdu_size;
-	else
-		self->tx_max_sdu_size = param->pv.i;
-
-	IRDA_DEBUG(1, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
-	
-	return 0;
-}
-
-/*
- * Function irttp_todo_expired (data)
- *
- *    Todo timer has expired!
- *
- */
-static void irttp_todo_expired(unsigned long data)
-{
-	struct tsap_cb *self = (struct tsap_cb *) data;
-
-	/* Check that we still exist */
-	if (!self || self->magic != TTP_TSAP_MAGIC)
-		return;
-	
-	irttp_run_rx_queue(self);
-	irttp_run_tx_queue(self);
-		
-	/*  Give avay some credits to peer?  */
-	if ((self->remote_credit < TTP_LOW_THRESHOLD) && 
-	    (self->avail_credit > 0) && (skb_queue_empty(&self->tx_queue)))
-	{
+	self->avail_credit = (self->initial_credit -
+			      (self->remote_credit +
+			       skb_queue_len(&self->rx_queue) +
+			       skb_queue_len(&self->rx_fragments)));
+
+	/* Do we have too much credits to send to peer ? */
+	if ((self->remote_credit <= TTP_RX_MIN_CREDIT) &&
+	    (self->avail_credit > 0)) {
+		/* Send explicit credit frame */
 		irttp_give_credit(self);
+		/* Note : do *NOT* check if tx_queue is non-empty, that
+		 * will produce deadlocks. I repeat : send a credit frame
+		 * even if we have something to send in our Tx queue.
+		 * If we have credits, it means that our Tx queue is blocked.
+		 *
+		 * Let's suppose the peer can't keep up with our Tx. He will
+		 * flow control us by not sending us any credits, and we
+		 * will stop Tx and start accumulating credits here.
+		 * Up to the point where the peer will stop its Tx queue,
+		 * for lack of credits.
+		 * Let's assume the peer application is single threaded.
+		 * It will block on Tx and never consume any Rx buffer.
+		 * Deadlock. Guaranteed. - Jean II
+		 */
 	}
 
-	/* Check if time for disconnect */
-	if (test_bit(0, &self->disconnect_pend)) {
-		/* Check if it's possible to disconnect yet */
-		if (skb_queue_empty(&self->tx_queue)) {
-			/* Make sure disconnect is not pending anymore */
-			clear_bit(0, &self->disconnect_pend);	/* FALSE */
-
-			/* Note : self->disconnect_skb may be NULL */
-			irttp_disconnect_request(self, self->disconnect_skb,
-						 P_NORMAL);
-			self->disconnect_skb = NULL;
-		} else {
-			/* Try again later */
-			irttp_start_todo_timer(self, 1*HZ);
-			
-			/* No reason to try and close now */
-			return;
-		}
-	}
-	
-	/* Check if it's closing time */
-	if (self->close_pend)
-		irttp_close_tsap(self);
-}
-
-/*
- * Function irttp_start_todo_timer (self, timeout)
- *
- *    Start todo timer. 
- *
- */
-static void irttp_start_todo_timer(struct tsap_cb *self, int timeout)
-{
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
-	del_timer(&self->todo_timer);
-	
-	self->todo_timer.data     = (unsigned long) self;
-	self->todo_timer.function = &irttp_todo_expired;
-	self->todo_timer.expires  = jiffies + timeout;
-
-	add_timer(&self->todo_timer);
+	/* Reset lock */
+	self->rx_queue_lock = 0;
 }
 
 #ifdef CONFIG_PROC_FS
diff -Nru a/net/irda/parameters.c b/net/irda/parameters.c
--- a/net/irda/parameters.c	Thu May  2 17:22:16 2002
+++ b/net/irda/parameters.c	Thu May  2 17:22:16 2002
@@ -28,6 +28,7 @@
  *     
  ********************************************************************/
 
+#include <linux/types.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
diff -Nru a/net/netsyms.c b/net/netsyms.c
--- a/net/netsyms.c	Thu May  2 17:22:16 2002
+++ b/net/netsyms.c	Thu May  2 17:22:16 2002
@@ -408,6 +408,8 @@
 
 #endif
 
+EXPORT_SYMBOL(tcp_read_sock);
+
 EXPORT_SYMBOL(netlink_set_err);
 EXPORT_SYMBOL(netlink_broadcast);
 EXPORT_SYMBOL(netlink_unicast);
@@ -446,7 +448,6 @@
 EXPORT_SYMBOL(dev_open);
 
 /* Used by other modules */
-EXPORT_SYMBOL(in_ntoa);
 EXPORT_SYMBOL(xrlim_allow);
 
 EXPORT_SYMBOL(ip_rcv);
diff -Nru a/net/sched/sch_generic.c b/net/sched/sch_generic.c
--- a/net/sched/sch_generic.c	Thu May  2 17:22:15 2002
+++ b/net/sched/sch_generic.c	Thu May  2 17:22:15 2002
@@ -280,7 +280,7 @@
 	list = ((struct sk_buff_head*)qdisc->data) +
 		prio2band[skb->priority&TC_PRIO_MAX];
 
-	if (list->qlen <= skb->dev->tx_queue_len) {
+	if (list->qlen <= qdisc->dev->tx_queue_len) {
 		__skb_queue_tail(list, skb);
 		qdisc->q.qlen++;
 		return 0;
diff -Nru a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
--- a/net/sched/sch_ingress.c	Thu May  2 17:22:17 2002
+++ b/net/sched/sch_ingress.c	Thu May  2 17:22:17 2002
@@ -43,6 +43,9 @@
 #define PRIV(sch) ((struct ingress_qdisc_data *) (sch)->data)
 
 
+/* Thanks to Doron Oz for this hack
+*/
+static int nf_registered = 0; 
 
 struct ingress_qdisc_data {
 	struct Qdisc		*q;
@@ -147,15 +150,21 @@
 #ifdef CONFIG_NET_CLS_POLICE
 		case TC_POLICE_SHOT:
 			result = NF_DROP;
+			sch->stats.drops++;
 			break;
 		case TC_POLICE_RECLASSIFY: /* DSCP remarking here ? */
 		case TC_POLICE_OK:
 		case TC_POLICE_UNSPEC:
 		default:
+			sch->stats.packets++;
+			sch->stats.bytes += skb->len;
 			result = NF_ACCEPT;
 			break;
+	}
+#else
+	sch->stats.packets++;
+	sch->stats.bytes += skb->len;
 #endif
-	};
 
 	skb->tc_index = TC_H_MIN(res.classid);
 	return result;
@@ -236,22 +245,21 @@
 {
 	struct ingress_qdisc_data *p = PRIV(sch);
 
+	if (!nf_registered) {
+		if (nf_register_hook(&ing_ops) < 0) {
+			printk("ingress qdisc registration error \n");
+			goto error;
+			}
+		nf_registered++;
+	}
+
 	DPRINTK("ingress_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt);
 	memset(p, 0, sizeof(*p));
 	p->filter_list = NULL;
 	p->q = &noop_qdisc;
-#ifndef MODULE
-	if (nf_register_hook(&ing_ops) < 0) {
-		printk("Unable to register ingress \n");
-		goto error;
-	}
-#endif
-	DPRINTK("ingress_init: qdisc %p\n", sch);
 	MOD_INC_USE_COUNT;
 	return 0;
-#ifndef MODULE
 error:
-#endif
 	return -EINVAL;
 }
 
@@ -295,12 +303,9 @@
 /* for future use */
 	qdisc_destroy(p->q);
 #endif
-
-#ifndef MODULE
-	nf_unregister_hook(&ing_ops);
-#endif
-
+ 
 	MOD_DEC_USE_COUNT;
+
 }
 
 
@@ -356,6 +361,7 @@
 	ingress_dump,			/* dump */
 };
 
+
 #ifdef MODULE
 int init_module(void)
 {
@@ -366,20 +372,15 @@
 		return ret;
 	}
 
-        if (nf_register_hook(&ing_ops) < 0) {
-		printk("Unable to register ingress on hook \n");
-		unregister_qdisc(&ingress_qdisc_ops);
-		return 0;
-	}
-
 	return ret;
 }
 
 
 void cleanup_module(void) 
 {
-	nf_unregister_hook(&ing_ops);
 	unregister_qdisc(&ingress_qdisc_ops);
+	if (nf_registered)
+		nf_unregister_hook(&ing_ops);
 }
 #endif
 MODULE_LICENSE("GPL");
diff -Nru a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
--- a/net/sunrpc/pmap_clnt.c	Thu May  2 17:22:17 2002
+++ b/net/sunrpc/pmap_clnt.c	Thu May  2 17:22:17 2002
@@ -87,8 +87,6 @@
 }
 
 #ifdef CONFIG_ROOT_NFS
-char *in_ntoa(__u32 in);
-
 int
 rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
 {
@@ -100,7 +98,7 @@
 	dprintk("RPC:      rpc_getport_external(%u.%u.%u.%u, %d, %d, %d)\n",
 			NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
 
-	strcpy(hostname, in_ntoa(sin->sin_addr.s_addr));
+	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
 	if (!(pmap_clnt = pmap_create(hostname, sin, prot)))
 		return -EACCES;
 
diff -Nru a/net/unix/af_unix.c b/net/unix/af_unix.c
--- a/net/unix/af_unix.c	Thu May  2 17:22:17 2002
+++ b/net/unix/af_unix.c	Thu May  2 17:22:17 2002
@@ -1886,8 +1886,8 @@
 					   sizeof(struct unix_sock), 0,
 					   SLAB_HWCACHE_ALIGN, 0, 0);
         if (!unix_sk_cachep)
-                printk(KERN_CRIT __FUNCTION__
-                        ": Cannot create unix_sock SLAB cache!\n");
+                printk(KERN_CRIT
+                        "af_unix_init: Cannot create unix_sock SLAB cache!\n");
 
 	sock_register(&unix_family_ops);
 #ifdef CONFIG_PROC_FS
diff -Nru a/sound/core/Makefile b/sound/core/Makefile
--- a/sound/core/Makefile	Thu May  2 17:22:16 2002
+++ b/sound/core/Makefile	Thu May  2 17:22:16 2002
@@ -36,7 +36,7 @@
   obj-y += oss/_oss.o
 endif
 
-obj-$(CONFIG_SND_PCM_OSS) += snd-pcm.o
+obj-$(CONFIG_SND_PCM_OSS) += snd-pcm.o snd-timer.o
 
 subdir-$(CONFIG_SND_SEQUENCER) += seq
 ifeq ($(CONFIG_SND_SEQUENCER),y)
diff -Nru a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
--- a/sound/oss/ac97_codec.c	Thu May  2 17:22:16 2002
+++ b/sound/oss/ac97_codec.c	Thu May  2 17:22:16 2002
@@ -65,6 +65,7 @@
 static int sigmatel_9708_init(struct ac97_codec *codec);
 static int sigmatel_9721_init(struct ac97_codec *codec);
 static int sigmatel_9744_init(struct ac97_codec *codec);
+static int ad1886_init(struct ac97_codec *codec);
 static int eapd_control(struct ac97_codec *codec, int);
 static int crystal_digital_control(struct ac97_codec *codec, int mode);
 
@@ -94,6 +95,7 @@
 static struct ac97_ops sigmatel_9721_ops = { sigmatel_9721_init, NULL, NULL };
 static struct ac97_ops sigmatel_9744_ops = { sigmatel_9744_init, NULL, NULL };
 static struct ac97_ops crystal_digital_ops = { NULL, eapd_control, crystal_digital_control };
+static struct ac97_ops ad1886_ops = { ad1886_init, eapd_control, NULL };
 
 /* sorted by vendor/device id */
 static const struct {
@@ -107,7 +109,7 @@
 	{0x41445360, "Analog Devices AD1885",	&default_ops},
 	{0x41445361, "Analog Devices AD1886",	&default_ops},
 	{0x41445460, "Analog Devices AD1885",	&default_ops},
-	{0x41445461, "Analog Devices AD1886",	&default_ops},
+	{0x41445461, "Analog Devices AD1886",	&ad1886_ops},
 	{0x414B4D00, "Asahi Kasei AK4540",	&null_ops},
 	{0x414B4D01, "Asahi Kasei AK4542",	&null_ops},
 	{0x414B4D02, "Asahi Kasei AK4543",	&null_ops},
@@ -871,6 +873,26 @@
 	codec->codec_write(codec, 0x2C, 0XFFFF);
 	return 0;
 }
+
+
+
+/* 
+ *	Presario700 workaround 
+ * 	for Jack Sense/SPDIF Register misetting causing
+ *	no audible output
+ *	by Santiago Nullo 04/05/2002
+ */
+
+#define AC97_AD1886_JACK_SENSE 0x72
+
+static int ad1886_init(struct ac97_codec * codec)
+{
+	/* from AD1886 Specs */
+	codec->codec_write(codec, AC97_AD1886_JACK_SENSE, 0x0010);
+	return 0;
+}
+
+
 
 
 /*
